diff --git a/.meta/folderstamp/.folderstamp.1 b/.meta/folderstamp/.folderstamp.1 new file mode 100644 index 0000000..9df30a1 --- /dev/null +++ b/.meta/folderstamp/.folderstamp.1 @@ -0,0 +1,86 @@ +This folder: /workspace/folderstamp +Platform: Linux +Storage Device: vda 64G disk 0x1af4 +folderstamp version: r6 +Method: Non-recursive +Dependency check: +Dependency OK: stat (/usr/bin/stat) +Dependency OK: git (/usr/bin/git) +Gitoxide/gix not found; Gitoxide is the default optional VCS accelerator. +You can install classic Git with your package manager, or install Gitoxide from GitHub Releases: + https://github.com/GitoxideLabs/gitoxide/releases/latest +Gitoxide usually provides the `gix` command; choose the asset for your OS/CPU architecture. +Optional dependency missing: pijul +Suggested install: sudo apt-get update && sudo apt-get install -y pijul +Dependency missing: ipfs +Dependency notice: ipfs is not installed. +Kubo is the reference IPFS implementation; you can download it from GitHub Releases: + https://github.com/ipfs/kubo/releases/latest +Choose the release asset that matches your OS and CPU architecture, then run the install script shipped in the archive. +Linux example after downloading the correct tarball: + tar -xzf kubo_*.tar.gz + cd kubo && sudo ./install.sh +Termux users should install into $PREFIX/bin instead of relying on sudo. +Current Git Branch: work +First Git Remote: none + + File: ./CHANGELOG.md + Size: 3716 Blocks: 8 IO Block: 4096 regular file +Device: 254,0 Inode: 2752568 Links: 1 +Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root) +Access: 2026-08-15 21:34:00.897075331 +0000 +Modify: 2026-08-15 21:41:58.517830670 +0000 +Change: 2026-08-15 21:41:58.517830670 +0000 + Birth: 2026-08-15 21:23:22.977075331 +0000 +CID hash: unavailable (ipfs command not found) +------------------------------ + File: ./GPTConversation.txt + Size: 0 Blocks: 0 IO Block: 4096 regular empty file +Device: 254,0 Inode: 2752564 Links: 1 +Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root) +Access: 2026-08-15 21:18:15.113075331 +0000 +Modify: 2026-08-15 21:18:15.113075331 +0000 +Change: 2026-08-15 21:18:15.113075331 +0000 + Birth: 2026-08-15 21:18:15.113075331 +0000 +CID hash: unavailable (ipfs command not found) +------------------------------ + File: ./SKILL.md + Size: 3410 Blocks: 8 IO Block: 4096 regular file +Device: 254,0 Inode: 2752596 Links: 1 +Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root) +Access: 2026-08-15 21:41:46.329075331 +0000 +Modify: 2026-08-15 21:41:46.337075331 +0000 +Change: 2026-08-15 21:41:46.337075331 +0000 + Birth: 2026-08-15 21:41:46.329075331 +0000 +CID hash: unavailable (ipfs command not found) +------------------------------ + File: ./folderstamp + Size: 13384 Blocks: 32 IO Block: 4096 regular file +Device: 254,0 Inode: 304776 Links: 1 +Access: (0755/-rwxr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root) +Access: 2026-08-15 21:42:13.537075331 +0000 +Modify: 2026-08-15 21:42:13.526483206 +0000 +Change: 2026-08-15 21:42:13.526483206 +0000 + Birth: 2026-08-15 21:19:38.081075331 +0000 +CID hash: unavailable (ipfs command not found) +------------------------------ + File: ./install.sh + Size: 1770 Blocks: 8 IO Block: 4096 regular file +Device: 254,0 Inode: 304777 Links: 1 +Access: (0755/-rwxr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root) +Access: 2026-08-15 21:41:29.169075331 +0000 +Modify: 2026-08-15 21:41:29.160516908 +0000 +Change: 2026-08-15 21:41:29.160516908 +0000 + Birth: 2026-08-15 21:19:38.101075331 +0000 +CID hash: unavailable (ipfs command not found) +------------------------------ + File: ./to-do.md + Size: 3189 Blocks: 8 IO Block: 4096 regular file +Device: 254,0 Inode: 2752565 Links: 1 +Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root) +Access: 2026-08-15 21:34:00.897075331 +0000 +Modify: 2026-08-15 21:41:58.517988779 +0000 +Change: 2026-08-15 21:41:58.517988779 +0000 + Birth: 2026-08-15 21:18:15.113075331 +0000 +CID hash: unavailable (ipfs command not found) +------------------------------ \ No newline at end of file diff --git a/.meta/folderstamp/.folderstamp.2 b/.meta/folderstamp/.folderstamp.2 new file mode 100644 index 0000000..842502b --- /dev/null +++ b/.meta/folderstamp/.folderstamp.2 @@ -0,0 +1,86 @@ +This folder: /workspace/folderstamp +Platform: Linux +Storage Device: vda 64G disk 0x1af4 +folderstamp version: r6 +Method: Non-recursive +Dependency check: +Dependency OK: stat (/usr/bin/stat) +Dependency OK: git (/usr/bin/git) +Gitoxide/gix not found; Gitoxide is the default optional VCS accelerator. +You can install classic Git with your package manager, or install Gitoxide from GitHub Releases: + https://github.com/GitoxideLabs/gitoxide/releases/latest +Gitoxide usually provides the `gix` command; choose the asset for your OS/CPU architecture. +Optional dependency missing: pijul +Suggested install: sudo apt-get update && sudo apt-get install -y pijul +Dependency missing: ipfs +Dependency notice: ipfs is not installed. +Kubo is the reference IPFS implementation; you can download it from GitHub Releases: + https://github.com/ipfs/kubo/releases/latest +Choose the release asset that matches your OS and CPU architecture, then run the install script shipped in the archive. +Linux example after downloading the correct tarball: + tar -xzf kubo_*.tar.gz + cd kubo && sudo ./install.sh +Termux users should install into $PREFIX/bin instead of relying on sudo. +Current Git Branch: work +First Git Remote: none + + File: ./CHANGELOG.md + Size: 4072 Blocks: 8 IO Block: 4096 regular file +Device: 254,0 Inode: 2752568 Links: 1 +Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root) +Access: 2026-08-15 21:42:16.265075331 +0000 +Modify: 2026-08-15 21:48:43.143856235 +0000 +Change: 2026-08-15 21:48:43.143856235 +0000 + Birth: 2026-08-15 21:23:22.977075331 +0000 +CID hash: unavailable (ipfs command not found) +------------------------------ + File: ./GPTConversation.txt + Size: 0 Blocks: 0 IO Block: 4096 regular empty file +Device: 254,0 Inode: 2752564 Links: 1 +Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root) +Access: 2026-08-15 21:18:15.113075331 +0000 +Modify: 2026-08-15 21:18:15.113075331 +0000 +Change: 2026-08-15 21:18:15.113075331 +0000 + Birth: 2026-08-15 21:18:15.113075331 +0000 +CID hash: unavailable (ipfs command not found) +------------------------------ + File: ./SKILL.md + Size: 3661 Blocks: 8 IO Block: 4096 regular file +Device: 254,0 Inode: 2752596 Links: 1 +Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root) +Access: 2026-08-15 21:42:22.281075331 +0000 +Modify: 2026-08-15 21:48:43.144023860 +0000 +Change: 2026-08-15 21:48:43.144023860 +0000 + Birth: 2026-08-15 21:41:46.329075331 +0000 +CID hash: unavailable (ipfs command not found) +------------------------------ + File: ./folderstamp + Size: 14760 Blocks: 32 IO Block: 4096 regular file +Device: 254,0 Inode: 304776 Links: 1 +Access: (0755/-rwxr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root) +Access: 2026-08-15 21:48:27.765075331 +0000 +Modify: 2026-08-15 21:48:27.754685338 +0000 +Change: 2026-08-15 21:48:27.754685338 +0000 + Birth: 2026-08-15 21:19:38.081075331 +0000 +CID hash: unavailable (ipfs command not found) +------------------------------ + File: ./install.sh + Size: 1770 Blocks: 8 IO Block: 4096 regular file +Device: 254,0 Inode: 304777 Links: 1 +Access: (0755/-rwxr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root) +Access: 2026-08-15 21:41:29.169075331 +0000 +Modify: 2026-08-15 21:41:29.160516908 +0000 +Change: 2026-08-15 21:41:29.160516908 +0000 + Birth: 2026-08-15 21:19:38.101075331 +0000 +CID hash: unavailable (ipfs command not found) +------------------------------ + File: ./to-do.md + Size: 3307 Blocks: 8 IO Block: 4096 regular file +Device: 254,0 Inode: 2752565 Links: 1 +Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root) +Access: 2026-08-15 21:42:16.265075331 +0000 +Modify: 2026-08-15 21:48:43.143501723 +0000 +Change: 2026-08-15 21:48:43.143501723 +0000 + Birth: 2026-08-15 21:18:15.113075331 +0000 +CID hash: unavailable (ipfs command not found) +------------------------------ \ No newline at end of file diff --git a/.meta/folderstamp/.folderstamp.3 b/.meta/folderstamp/.folderstamp.3 new file mode 100644 index 0000000..fd0f671 --- /dev/null +++ b/.meta/folderstamp/.folderstamp.3 @@ -0,0 +1,86 @@ +This folder: /workspace/folderstamp +Platform: Linux +Storage Device: vda 64G disk 0x1af4 +folderstamp version: r6 +Method: Non-recursive +Dependency check: +Dependency OK: stat (/usr/bin/stat) +Dependency OK: git (/usr/bin/git) +Gitoxide/gix not found; Gitoxide is the default optional VCS accelerator. +You can install classic Git with your package manager, or install Gitoxide from GitHub Releases: + https://github.com/GitoxideLabs/gitoxide/releases/latest +Gitoxide usually provides the `gix` command; choose the asset for your OS/CPU architecture. +Optional dependency missing: pijul +Suggested install: sudo apt-get update && sudo apt-get install -y pijul +Dependency missing: ipfs +Dependency notice: ipfs is not installed. +Kubo is the reference IPFS implementation; you can download it from GitHub Releases: + https://github.com/ipfs/kubo/releases/latest +Choose the release asset that matches your OS and CPU architecture, then run the install script shipped in the archive. +Linux example after downloading the correct tarball: + tar -xzf kubo_*.tar.gz + cd kubo && sudo ./install.sh +Termux users should install into $PREFIX/bin instead of relying on sudo. +Current Git Branch: work +First Git Remote: none + + File: ./CHANGELOG.md + Size: 4343 Blocks: 16 IO Block: 4096 regular file +Device: 254,0 Inode: 2752568 Links: 1 +Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root) +Access: 2026-08-15 21:48:54.393075331 +0000 +Modify: 2026-08-15 22:05:03.102721184 +0000 +Change: 2026-08-15 22:05:03.102721184 +0000 + Birth: 2026-08-15 21:23:22.977075331 +0000 +CID hash (CIDv0 basic): Qmd4hqT99WhMYmTpPLws5SRLBCMD2egZsbBDieFD1i73r3 +------------------------------ + File: ./GPTConversation.txt + Size: 0 Blocks: 0 IO Block: 4096 regular empty file +Device: 254,0 Inode: 2752564 Links: 1 +Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root) +Access: 2026-08-15 21:18:15.113075331 +0000 +Modify: 2026-08-15 21:18:15.113075331 +0000 +Change: 2026-08-15 21:18:15.113075331 +0000 + Birth: 2026-08-15 21:18:15.113075331 +0000 +CID hash (CIDv0 basic): QmaRwA91m9Rdfaq9u3FH1fdMVxw1wFPjKL38czkWMxh3KB +------------------------------ + File: ./SKILL.md + Size: 3885 Blocks: 8 IO Block: 4096 regular file +Device: 254,0 Inode: 2752596 Links: 1 +Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root) +Access: 2026-08-15 21:48:54.393075331 +0000 +Modify: 2026-08-15 22:05:03.103067684 +0000 +Change: 2026-08-15 22:05:03.103067684 +0000 + Birth: 2026-08-15 21:41:46.329075331 +0000 +CID hash (CIDv0 basic): QmTnorbPrC2d3gyWESggEMcRyPNAK57qEJnvs7w7YGzGZ6 +------------------------------ + File: ./folderstamp + Size: 16316 Blocks: 32 IO Block: 4096 regular file +Device: 254,0 Inode: 304776 Links: 1 +Access: (0755/-rwxr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root) +Access: 2026-08-15 22:04:42.101075331 +0000 +Modify: 2026-08-15 22:04:42.086841849 +0000 +Change: 2026-08-15 22:04:42.086841849 +0000 + Birth: 2026-08-15 21:19:38.081075331 +0000 +CID hash (CIDv0 basic): QmdGuAqejCYyUPzCWnqhqNbhnbeo2CqrqoKy2przgJYgxy +------------------------------ + File: ./install.sh + Size: 1770 Blocks: 8 IO Block: 4096 regular file +Device: 254,0 Inode: 304777 Links: 1 +Access: (0755/-rwxr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root) +Access: 2026-08-15 21:41:29.169075331 +0000 +Modify: 2026-08-15 21:41:29.160516908 +0000 +Change: 2026-08-15 21:41:29.160516908 +0000 + Birth: 2026-08-15 21:19:38.101075331 +0000 +CID hash (CIDv0 basic): QmR67K2SMN9TDdz9yMtqRX3UjQRkGSn4Y9K9g5i8rpf7SJ +------------------------------ + File: ./to-do.md + Size: 3402 Blocks: 8 IO Block: 4096 regular file +Device: 254,0 Inode: 2752565 Links: 1 +Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root) +Access: 2026-08-15 21:48:54.393075331 +0000 +Modify: 2026-08-15 22:05:03.102904574 +0000 +Change: 2026-08-15 22:05:03.102904574 +0000 + Birth: 2026-08-15 21:18:15.113075331 +0000 +CID hash (CIDv0 basic): QmXVfjpdwc7pf3h2ETeqedRmmjdvykzVvtFzHV5t6qHSLf +------------------------------ \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..c6ce1a6 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,58 @@ +# Changelog + +Todas as mudanças relevantes deste projeto serão documentadas aqui. + +O formato segue a ideia do [Keep a Changelog](https://keepachangelog.com/), com versões em ordem cronológica reversa. + +## [r6] - 2026-08-15 + +### Added +- Adicionado relatório de dependências no `folderstamp`, detectando `stat`, `git`/Gitoxide, `pijul` e `ipfs`. +- Renomeado o rótulo de saída de `IPFS hash:` para `CID hash:` para cobrir IPFS, Iroh e outros ecossistemas que usam CID sem acoplar marca. +- Iniciada implementação básica de geração de CIDv0 sem Kubo/IPFS usando Python 3 para arquivos single-block UnixFS/DAG-PB. +- Alterado `save` para armazenar novos stamps em `.meta/folderstamp/` em vez de criar `.folderstamp` na raiz. +- Adicionada migração automática de `.folderstamp` legado para `.meta/folderstamp/.folderstamp.1`, criando o próximo número disponível para novos stamps. +- Adicionada tarefa para avaliar Iroh como alternativa Rust para gerar CIDv0 e CIDv1. +- Adicionado instalador interativo para Kubo/IPFS e Gitoxide via GitHub Releases quando o usuário confirma no prompt. +- Adicionado Gitoxide como opção padrão sugerida mesmo quando Git clássico já existe, sem exigir passos manuais em sessão interativa. +- Adicionado suporte de portabilidade para BSD, macOS e Zircon/Fuchsia. +- Criado `SKILL.md` com práticas de Bash portátil, diagnósticos, dependências e documentação usadas nesta sequência de patches. +- Adicionada opção orientada para instalar Git pelo package manager ou Gitoxide via GitHub Releases quando nenhum dos dois está instalado. +- Adicionado suporte a repositórios Pijul ao lado do Git, exibindo canal atual quando `.pijul` existe. +- Adicionada oferta de instalação do Kubo/IPFS via GitHub Releases quando `ipfs` não está instalado. +- Adicionadas sugestões de instalação por package manager para dependências ausentes em Termux, Cygwin, RedoxOS e Linux comum. +- Adicionado `.folderstamp` versionado com o stamp do ambiente atual. +- Criado `to-do.md` organizado a partir do antigo `Tasks.txt`, com novas ideias de portabilidade, documentação e UX. +- Adicionado suporte explícito à detecção de plataforma para Termux, Cygwin e RedoxOS, mantendo compatibilidade com Linux padrão. +- Adicionada saída `Platform:` ao comando `folderstamp display`, facilitando debug em ambientes diferentes. +- Adicionado fallback para detalhes de armazenamento: usa `lsblk` quando disponível e recorre a `df -hP` quando `lsblk` não existe. +- Adicionado fallback para IPFS ausente, exibindo uma mensagem clara quando o comando `ipfs` não está instalado. +- Adicionada seleção automática de diretório de instalação no `install.sh`: + - Termux: `${PREFIX}/bin` ou `/data/data/com.termux/files/usr/bin`. + - Cygwin: `/usr/local/bin`. + - RedoxOS: `${HOME}/bin`. + - Linux padrão: `/usr/bin`. + +### Changed +- Renomeado `Tasks.txt` para `to-do.md`, com checkboxes e seções temáticas. +- Mantida a versão interna do `folderstamp` em `r6`. +- Centralizada a lógica de carimbo de arquivos na função `stamp_path`, reduzindo duplicação entre os modos recursivo e não-recursivo. +- Centralizada a leitura de dados Git na função `print_git_details`, com tratamento para repositórios sem remote configurado. +- O instalador deixou de depender obrigatoriamente de `sudo`; agora usa `sudo` apenas quando o diretório de destino exige permissão elevada e o comando está disponível. +- `folderstamp` e `install.sh` passaram a ser instaláveis/executáveis diretamente, com permissão de execução versionada no Git. + +### Fixed +- Evitada falha em ambientes sem `lsblk`, comuns em Termux e outros sistemas minimalistas. +- Evitada falha em ambientes sem `ipfs`, substituindo o erro por uma mensagem informativa. +- Evitada falha ao exibir informações Git quando o repositório não possui remote configurado. +- Evitada dependência rígida de `/usr/bin`, que não é o destino correto em Termux, Cygwin ou RedoxOS. + +## [r5] - Antes de 2026-08-15 + +### Existing +- Exibição do diretório atual. +- Exibição de informações de armazenamento via `lsblk` em Linux. +- Exibição da branch Git atual e primeiro remote quando `.git` existe. +- Suporte aos comandos `display` e `save`. +- Suporte ao modo recursivo com `--recursive` ou `-r`. +- Geração de hash IPFS usando `ipfs add -q --only-hash`. diff --git a/SKILL.md b/SKILL.md new file mode 100644 index 0000000..f339f4f --- /dev/null +++ b/SKILL.md @@ -0,0 +1,67 @@ +# Bash Script Craft Skill + +Use this skill when creating or reviewing shell scripts for Perla's projects. The goal is to write Bash that survives real machines, not just a shiny Linux container with every dependency preinstalled like a fake Web3 roadmap. + +## Voice and project expectations + +- Prefer clear comments where behavior is not obvious. +- Prefer helpful diagnostics over silent failure. +- If a dependency is missing, say exactly what is missing and suggest an install command when the platform is known. +- Keep scripts friendly for debugging: print platform, relevant tool paths, fallback choices, and what the script is about to do. +- Avoid fragile assumptions like `/usr/bin`, `sudo`, GNU-only flags, or a single package manager. + +## Portability checklist + +Detect the platform before choosing paths or install commands. Consider at least: + +- Linux and common package managers: `apt-get`, `dnf`, `pacman`, `apk`, `zypper`. +- Termux/Android: `$TERMUX_VERSION`, `$PREFIX`, `uname -o Android`, install into `$PREFIX/bin`, avoid `sudo`. +- Cygwin: `uname -s` starting with `CYGWIN`, prefer `/usr/local/bin`, mention the Cygwin setup executable for packages. +- BSD: `FreeBSD`, `OpenBSD`, `NetBSD`, `DragonFly`; try `pkg` or `pkg_add` and avoid assuming GNU userland. +- macOS: `Darwin`; prefer Homebrew when available but do not require it. +- RedoxOS: `Redox`; prefer user-writable install paths such as `$HOME/bin` when unsure. +- Zircon/Fuchsia: `Fuchsia` or `Zircon`; report limitations clearly because package workflows vary by image/build. + +## Dependency handling + +- Wrap command detection in a helper such as `command_exists() { command -v "$1" >/dev/null 2>&1; }`. +- Check critical commands before use (`stat`, `find`, `sed`, `awk`, `df`, `tar`, `curl`, VCS tools). +- Prefer graceful fallbacks: + - `lsblk` for Linux storage details, then `df -hP` as fallback. + - Git metadata via `git`, with Gitoxide/`gix` as a supported alternative where possible. + - Pijul metadata when `.pijul` exists and `pijul` is installed. +- Optional tools should not break the main script unless the user explicitly requested that feature. + +## Interactive installers + +- If a missing tool can be installed from GitHub Releases, offer an interactive yes/no prompt when stdin is a TTY. +- If stdin is not a TTY, print the install/release URL and continue safely. +- Install into user-writable locations first (`$PREFIX/bin`, `$HOME/.local/bin`) before attempting privileged paths. +- Never require `sudo` on Termux. +- If auto-install needs helper tools (`curl`, `tar`, `python3`), check them first and explain what is missing. + +## Bash style + +- Use `#!/bin/bash -e` only when Bash features are actually used; otherwise use POSIX `sh`. +- Quote variables unless intentionally splitting. +- Keep repeated logic in functions. +- Use `while IFS= read -r -d ''` with `find -print0` for filenames that may contain spaces/newlines. +- Avoid `grep -R`; prefer `rg` in repo work and targeted `find` where needed. +- Do not put try/catch-style wrappers around imports in languages that have imports. + +## Documentation expectations + +- Keep `CHANGELOG.md` updated when behavior changes. +- Keep `to-do.md` organized with checkboxes and theme sections. +- Prefer a `README.md` for scripts with install, usage, examples, troubleshooting, and platform notes. +- When generating an environment stamp, commit `.folderstamp` only if explicitly requested. + +## Metadata output convention + +- Prefer storing generated metadata under `.meta//` instead of cluttering the project root. +- When migrating legacy root metadata files, preserve them by numbering old outputs before creating the next stamp. + +## CID naming + +- Prefer the neutral label `CID hash:` instead of brand-specific labels such as `IPFS hash:`. +- When implementing CID fallbacks, document whether the implementation is basic/single-block or feature-complete. diff --git a/Tasks.txt b/Tasks.txt deleted file mode 100644 index 288a630..0000000 --- a/Tasks.txt +++ /dev/null @@ -1,24 +0,0 @@ -"v2"(r5+) from ChatGPT: -- after "This folder: " line, add the storage device manufacturer/capacity/details (find some Linux programs that can do that) -- when stamping on Desktop: tell the current background location, items' positions and items' icons! gsettings get org.cinnamon.desktop.background picture-uri | tr -d "'" (have to detect DE, and fallback is not using this) -- in the recursive mode, also stamp the folder (but without hash) as non-recursive do -- IPFS CID option through the --hash flag -- if .folderstamp is found, rename it to ".folderstamp1" and the next will be ".folderstamp2" (use the untitled library) (mirror this feature, in verifact-hash) -- support a simple .ls (.ls1, .ls2 - use the untitled library) -- option to choose a custom number for .folderstamp (except if already existing) -- hardcoded exception items, such as the very .folderstamp file and .git folder -- .folderstampignore file (pig nore? or .folderstamp-ignore file but it won't follow git's naming convention) - -- at the end of .folderstamp file, tell the date it was done. option to add Ethereum's current latest block no. - ---help flag - ----- - -v3: -- when stamping on Desktop: beyond telling the current background: tell items' positions and items' icons! - ----- - -.file-timestamps files will be symlinks to a git folder with sharedbytes! -- .folderstamp.listed file; can be used to avoid listing files that were already snapshot previously diff --git a/folderstamp b/folderstamp old mode 100644 new mode 100755 index 8b460a3..6c6806d --- a/folderstamp +++ b/folderstamp @@ -1,16 +1,514 @@ #!/bin/bash -e +FOLDERSTAMP_VERSION="r6" + +command_exists() { + command -v "$1" >/dev/null 2>&1 +} + +platform_name() { + local uname_s uname_o + uname_s="$(uname -s 2>/dev/null || echo unknown)" + uname_o="$(uname -o 2>/dev/null || echo unknown)" + + if [[ -n "${TERMUX_VERSION:-}" ]] || [[ "${PREFIX:-}" == *com.termux* ]] || [[ "$uname_o" == "Android" ]]; then + echo "Termux" + elif [[ "$uname_s" == CYGWIN* ]]; then + echo "Cygwin" + elif [[ "$uname_s" == "Redox" ]]; then + echo "RedoxOS" + elif [[ "$uname_s" == "Darwin" ]]; then + echo "macOS" + elif [[ "$uname_s" == *BSD ]]; then + echo "BSD" + elif [[ "$uname_s" == "Fuchsia" ]] || [[ "$uname_s" == "Zircon" ]]; then + echo "Zircon/Fuchsia" + else + echo "$uname_s" + fi +} + + +install_command_for() { + local package="$1" + local platform + platform="$(platform_name)" + + case "$platform" in + Termux) + echo "pkg install $package" + ;; + Cygwin) + echo "Install the '$package' package with the Cygwin setup executable." + ;; + RedoxOS) + echo "pkg install $package" + ;; + macOS) + if command_exists brew; then + echo "brew install $package" + else + echo "Install '$package' with Homebrew, MacPorts, or the upstream project release." + fi + ;; + BSD) + if command_exists pkg; then + echo "pkg install $package" + elif command_exists pkg_add; then + echo "pkg_add $package" + else + echo "Install '$package' with your BSD package manager." + fi + ;; + Zircon/Fuchsia) + echo "Install '$package' with the Fuchsia package workflow for your image/build." + ;; + Linux) + if command_exists apt-get; then + echo "sudo apt-get update && sudo apt-get install -y $package" + elif command_exists dnf; then + echo "sudo dnf install -y $package" + elif command_exists pacman; then + echo "sudo pacman -S --needed $package" + elif command_exists apk; then + echo "sudo apk add $package" + elif command_exists zypper; then + echo "sudo zypper install -y $package" + else + echo "Install '$package' with your distribution package manager." + fi + ;; + *) + echo "Install '$package' with the package manager for $(platform_name)." + ;; + esac +} + + +normalized_arch() { + local arch + arch="$(uname -m 2>/dev/null || echo unknown)" + + case "$arch" in + x86_64|amd64) echo "amd64" ;; + aarch64|arm64) echo "arm64" ;; + armv7*|armv6*) echo "arm" ;; + *) echo "$arch" ;; + esac +} + +github_os_token() { + case "$(platform_name)" in + Linux|Termux) echo "linux" ;; + macOS) echo "darwin" ;; + BSD) echo "freebsd" ;; + Cygwin) echo "windows" ;; + *) echo "" ;; + esac +} + +install_bin_dir() { + if [[ -n "${PREFIX:-}" && -w "${PREFIX}/bin" ]]; then + echo "${PREFIX}/bin" + elif [[ -d "$HOME/.local/bin" || -w "$HOME" ]]; then + mkdir -p "$HOME/.local/bin" 2>/dev/null || true + echo "$HOME/.local/bin" + else + echo "/usr/local/bin" + fi +} + +install_release_asset() { + local repo="$1" + local label="$2" + local asset_regex="$3" + local bin_name="$4" + local os_token arch token url archive workdir dest + + if ! command_exists curl; then + echo "Cannot auto-install $label: curl is missing." + echo "Suggested install: $(install_command_for curl)" + return 1 + fi + + if ! command_exists tar; then + echo "Cannot auto-install $label: tar is missing." + echo "Suggested install: $(install_command_for tar)" + return 1 + fi + + if ! command_exists python3; then + echo "Cannot auto-install $label safely: python3 is missing for GitHub release asset selection." + echo "Open instead: https://github.com/$repo/releases/latest" + return 1 + fi + + os_token="$(github_os_token)" + arch="$(normalized_arch)" + token="${os_token}-${arch}" + + if [[ -z "$os_token" ]]; then + echo "Cannot auto-install $label on $(platform_name) yet. Open: https://github.com/$repo/releases/latest" + return 1 + fi + + url="$(curl -fsSL "https://api.github.com/repos/$repo/releases/latest" | python3 -c ' +import json, re, sys +os_token = sys.argv[1].lower() +arch = sys.argv[2].lower() +regex = re.compile(sys.argv[3], re.I) +arch_aliases = { + "amd64": ["amd64", "x86_64"], + "arm64": ["arm64", "aarch64"], + "arm": ["arm", "armv7", "armv6"], +} +arches = arch_aliases.get(arch, [arch]) +data = json.load(sys.stdin) +for asset in data.get("assets", []): + name = asset.get("name", "") + low = name.lower() + if os_token in low and any(a in low for a in arches) and regex.search(name): + print(asset.get("browser_download_url", "")) + break +' "$os_token" "$arch" "$asset_regex")" + + if [[ -z "$url" ]]; then + echo "No matching $label release asset found for $token." + echo "Open: https://github.com/$repo/releases/latest" + return 1 + fi + + workdir="$(mktemp -d 2>/dev/null || mktemp -d -t folderstamp)" + archive="$workdir/asset.tar.gz" + dest="$(install_bin_dir)/$bin_name" + + echo "Downloading $label from: $url" + curl -fL "$url" -o "$archive" + tar -xzf "$archive" -C "$workdir" + + found="$(find "$workdir" -type f -name "$bin_name" -perm -u+x 2>/dev/null | head -n1)" + if [[ -z "$found" ]]; then + found="$(find "$workdir" -type f -name "$bin_name" 2>/dev/null | head -n1)" + fi + + if [[ -z "$found" ]]; then + echo "Downloaded $label, but could not find $bin_name inside the archive." + echo "Workdir kept for inspection: $workdir" + return 1 + fi + + cp "$found" "$dest" + chmod +x "$dest" + echo "$label installed at $dest" +} + +ask_yes_no() { + local question="$1" + local answer + + if [[ ! -t 0 ]]; then + return 1 + fi + + printf "%s [Y/n] " "$question" + read -r answer + case "$answer" in + n|N|no|NO|No) return 1 ;; + *) return 0 ;; + esac +} + +offer_gitoxide_install() { + if ask_yes_no "Install Gitoxide/gix from GitHub Releases now?"; then + install_release_asset "GitoxideLabs/gitoxide" "Gitoxide" 'gitoxide.*(tar\.gz|tgz)$' "gix" + else + gitoxide_install_offer + fi +} + +offer_kubo_install() { + if ask_yes_no "Install Kubo/IPFS from GitHub Releases now?"; then + install_release_asset "ipfs/kubo" "Kubo/IPFS" 'kubo.*(tar\.gz|tgz)$' "ipfs" + else + kubo_install_offer + fi +} + +gitoxide_install_offer() { + cat <<'GITOXIDE_EOF' +You can install classic Git with your package manager, or install Gitoxide from GitHub Releases: + https://github.com/GitoxideLabs/gitoxide/releases/latest +Gitoxide usually provides the `gix` command; choose the asset for your OS/CPU architecture. +GITOXIDE_EOF +} + +check_git_tooling() { + if command_exists git; then + echo "Dependency OK: git ($(command -v git))" + if ! command_exists gix; then + echo "Gitoxide/gix not found; Gitoxide is the default optional VCS accelerator." + offer_gitoxide_install || true + fi + return 0 + fi + + if command_exists gix; then + echo "Dependency OK: gitoxide/gix ($(command -v gix))" + return 0 + fi + + echo "Dependency missing: git or gitoxide/gix" + echo "Suggested Git install: $(install_command_for git)" + offer_gitoxide_install || true + return 1 +} + +check_optional_dependency() { + local command_name="$1" + local package_name="${2:-$1}" + + if command_exists "$command_name"; then + echo "Optional dependency OK: $command_name ($(command -v "$command_name"))" + return 0 + fi + + echo "Optional dependency missing: $command_name" + echo "Suggested install: $(install_command_for "$package_name")" + return 1 +} + +kubo_install_offer() { + cat <<'KUBO_EOF' +Dependency notice: ipfs is not installed. +Kubo is the reference IPFS implementation; you can download it from GitHub Releases: + https://github.com/ipfs/kubo/releases/latest +Choose the release asset that matches your OS and CPU architecture, then run the install script shipped in the archive. +Linux example after downloading the correct tarball: + tar -xzf kubo_*.tar.gz + cd kubo && sudo ./install.sh +Termux users should install into $PREFIX/bin instead of relying on sudo. +KUBO_EOF +} + +check_dependency() { + local command_name="$1" + local package_name="${2:-$1}" + + if command_exists "$command_name"; then + echo "Dependency OK: $command_name ($(command -v "$command_name"))" + return 0 + fi + + echo "Dependency missing: $command_name" + + if [[ "$command_name" == "ipfs" ]]; then + offer_kubo_install || true + else + echo "Suggested install: $(install_command_for "$package_name")" + fi + + return 1 +} + +print_dependency_report() { + echo "Dependency check:" + check_dependency stat coreutils || true + check_git_tooling || true + check_optional_dependency pijul pijul || true + check_dependency ipfs kubo || true +} + +print_storage_details() { + local mount_source + mount_source="$(df -P . 2>/dev/null | awk 'NR==2 {print $1}')" + + if [[ -n "$mount_source" ]] && command_exists lsblk; then + lsblk -o NAME,SIZE,TYPE,VENDOR,MODEL 2>/dev/null \ + | awk -v device="$mount_source" 'index(device, "/" $1) || device == $1 {print "Storage Device: " $0}' + return 0 + fi + + if command_exists df; then + df -hP . 2>/dev/null | awk 'NR==2 {print "Storage Device: " $1 " mounted on " $6 " (" $2 " total, " $4 " available)"}' + return 0 + fi + + echo "Storage Device: unavailable on this platform" +} + +print_git_details() { + local current_branch first_remote_name first_remote_url + + if [[ -d ".git" ]] && command_exists git; then + current_branch="$(git rev-parse --abbrev-ref HEAD 2>/dev/null || true)" + first_remote_name="$(git remote 2>/dev/null | head -n1)" + echo "Current Git Branch: ${current_branch:-unknown}" + + if [[ -n "$first_remote_name" ]]; then + first_remote_url="$(git remote get-url "$first_remote_name" 2>/dev/null || true)" + echo "First Git Remote: $first_remote_name - URL: ${first_remote_url:-unknown}" + else + echo "First Git Remote: none" + fi + elif [[ -d ".git" ]] && command_exists gix; then + echo "Git repository detected; Gitoxide available: $(command -v gix)" + echo "Current Git Branch: unavailable without classic git" + fi +} + +print_pijul_details() { + local current_channel + + if [[ -d ".pijul" ]] && command_exists pijul; then + current_channel="$(pijul channel 2>/dev/null | awk '/\*/ {print $2; exit}')" + echo "Current Pijul Channel: ${current_channel:-unknown}" + elif [[ -d ".pijul" ]]; then + echo "Pijul repository detected, but pijul is not installed." + echo "Suggested install: $(install_command_for pijul)" + fi +} + +cid_v0_basic_python() { + local file="$1" + + python3 - "$file" <<'PY_CID' +import hashlib +import sys + +ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" + + +def varint(value: int) -> bytes: + out = bytearray() + while value >= 0x80: + out.append((value & 0x7F) | 0x80) + value >>= 7 + out.append(value) + return bytes(out) + + +def field_varint(number: int, value: int) -> bytes: + return varint((number << 3) | 0) + varint(value) + + +def field_bytes(number: int, value: bytes) -> bytes: + return varint((number << 3) | 2) + varint(len(value)) + value + + +def b58encode(data: bytes) -> str: + n = int.from_bytes(data, "big") + chars = [] + while n: + n, rem = divmod(n, 58) + chars.append(ALPHABET[rem]) + prefix = "1" * (len(data) - len(data.lstrip(b"\\0"))) + return prefix + "".join(reversed(chars or ["1"])) + +path = sys.argv[1] +with open(path, "rb") as handle: + payload = handle.read() + +# Basic CIDv0 study/implementation for a single-block UnixFS file: +# UnixFS Data: Type=File(2), Data=, filesize=. +unixfs_data = field_varint(1, 2) + field_bytes(2, payload) + field_varint(3, len(payload)) +# DAG-PB PBNode: Data=. No links/chunking in this basic fallback. +pb_node = field_bytes(1, unixfs_data) +digest = hashlib.sha256(pb_node).digest() +multihash = bytes([0x12, 0x20]) + digest +print(b58encode(multihash)) +PY_CID +} + +print_cid_hash() { + local file="$1" + + if command_exists ipfs; then + echo "CID hash: $(ipfs add -q --only-hash "$file")" + elif command_exists python3; then + echo "CID hash (CIDv0 basic): $(cid_v0_basic_python "$file")" + else + echo "CID hash: unavailable (install Kubo/IPFS, Iroh, or python3 for the basic CIDv0 fallback)" + fi +} + +stamp_path() { + local file="$1" + local all + + all=$(printf '\n'; if command_exists stat; then stat "$file" 2>/dev/null || echo "stat failed for: $file"; else echo "stat unavailable for: $file"; echo "Suggested install: $(install_command_for coreutils)"; fi; print_cid_hash "$file"; printf '%s\n' '------------------------------') + printf "%s" "$all" | sed 's/%/%%/g' +} + +folderstamp_store_dir() { + echo ".meta/folderstamp" +} + +legacy_folderstamp_path() { + echo ".folderstamp" +} + +next_folderstamp_path() { + local store_dir="$1" + local max=0 + local path name number + + if [[ -f "$store_dir/.folderstamp" ]]; then + max=1 + fi + + for path in "$store_dir"/.folderstamp.*; do + [[ -e "$path" ]] || continue + name="${path##*/}" + number="${name##*.}" + if [[ "$number" =~ ^[0-9]+$ ]] && (( number > max )); then + max="$number" + fi + done + + if (( max == 0 )); then + echo "$store_dir/.folderstamp" + else + echo "$store_dir/.folderstamp.$((max + 1))" + fi +} + +prepare_folderstamp_output_path() { + local store_dir legacy_path next_path + store_dir="$(folderstamp_store_dir)" + legacy_path="$(legacy_folderstamp_path)" + + mkdir -p "$store_dir" + + if [[ -f "$legacy_path" ]]; then + if [[ ! -e "$store_dir/.folderstamp.1" ]]; then + mv "$legacy_path" "$store_dir/.folderstamp.1" + else + mv "$legacy_path" "$(next_folderstamp_path "$store_dir")" + fi + fi + + next_path="$(next_folderstamp_path "$store_dir")" + echo "$next_path" +} + +save_folderstamp() { + local output_path + output_path="$(prepare_folderstamp_output_path)" + + echo "🤓📝 Working..." + echo "Saving folderstamp to: $output_path" + display "$1" "$2" > "$output_path" +} + function display { -#SCRIPTPATH="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" -#echo "This folder: $SCRIPTPATH" rocketlaunch_dir=`pwd` #from https://unix.stackexchange.com/a/52919/470623 echo "This folder: $rocketlaunch_dir" +echo "Platform: $(platform_name)" #- -# Add storage device details -storage_details=$(lsblk -o NAME,SIZE,TYPE,VENDOR,MODEL | grep "$(df -P . | awk 'NR==2 {print $1}')" | sed 's/^/Storage Device: /') -echo "$storage_details" +# Add storage device details with fallbacks for Linux, Termux, Cygwin and RedoxOS. +print_storage_details #- -echo "folderstamp version: r5" +echo "folderstamp version: $FOLDERSTAMP_VERSION" if [[ "$2" == "--recursive" ]] || [[ "$2" == "-r" ]]; then method="Recursive" else @@ -19,59 +517,22 @@ fi echo "Method: $method" # Add this line to show the method used # Display current git branch and first git remote name with URL if .git folder is present -# Check if .git folder exists -if [ -d ".git" ]; then - current_branch=$(git rev-parse --abbrev-ref HEAD) - first_remote_name=$(git remote | head -n1) - first_remote_url=$(git remote get-url $first_remote_name) - echo "Current Git Branch: $current_branch" - echo "First Git Remote: $first_remote_name - URL: $first_remote_url" -fi +print_dependency_report +print_git_details +print_pijul_details if [[ "$2" == "--recursive" ]] || [[ "$2" == "-r" ]] then find . -type f -name '*' -print0 | while IFS= read -r -d '' file do - #name=$(basename "$file") - #path=$(dirname "$file") - # full_path=$(readlink -f "$file") # This only works on Linux - #full_path=$(echo "$PWD/${file#./}") - #extension=${name##*.} - #size_human_readable=$(ls -lh "$file" | awk -F' ' '{print $5}') - #size_in_bytes=$(stat -f "%z" "$file") - #creation_date=$(stat -f "%SB" "$file") - #last_access=$(stat -f "%Sa" "$file") - #last_modification=$(stat -f "%Sm" "$file") - #last_change=$(stat -f "%Sc" "$file") - #-to fix: all=$(echo -e "" && stat "$file" && if [ "$2" = "hash" ];then echo "IPFS hash: $(ipfs add -q --only-hash "$file")"; fi && echo -e "------------------------------") - all=$(echo -e "" && stat "$file" && echo "IPFS hash: $(ipfs add -q --only-hash "$file")" && echo -e "------------------------------") -#-to fix: if [ "$2" = "--hash" ];then -#-to fix: all=$(echo -e "" && stat "$file" && echo "IPFS hash: $(ipfs add -q --only-hash "$file")" && echo -e "------------------------------") -#-to fix: else -#-to fix: all=$(echo -e "" && stat "$file" && echo -e "------------------------------") -#-to fix: fi - - #printf "[$file]:\n" - #printf "\tfile name:\t\t$name\n" - #printf "\tfile path:\t\t$path\n" - #printf "\tfull file path:\t\t$full_path\n" - #printf "\tfile extension:\t\t$extension\n" - #printf "\tfile size:\t\t$size_human_readable\n" - #printf "\tfile size in bytes:\t$size_in_bytes\n" - #printf "\tfile creation date:\t$creation_date\n" - #printf "\tlast file access:\t$last_access\n" - #printf "\tlast file modification:\t$last_modification\n" - #printf "\tlast file change:\t$last_change\n" - #printf "\n" - printf "$all" | sed 's/%/%%/g' + stamp_path "$file" done # from https://stackoverflow.com/a/25948226/5623661 else # NOTE : Quote it else use array to avoid problems # for file in ./* do - all=$(echo -e "" && stat "$file" && echo "IPFS hash: $(ipfs add -q --only-hash "$file")" && echo -e "------------------------------") - printf "$all" | sed 's/%/%%/g' + stamp_path "$file" # from https://stackoverflow.com/a/25948226/5623661 done # based from https://www.cyberciti.biz/faq/bash-loop-over-file/ @@ -79,8 +540,7 @@ fi } if [ "$1" = "save" ];then - echo "🤓📝 Working..." - display "$1" "$2" > .folderstamp + save_folderstamp "$1" "$2" fi if [ "$1" = "display" ];then display "$1" "$2" @@ -91,6 +551,3 @@ fi #-to fix: else #-to fix: if [ "$1" = "save" ];then echo "🤓📝 Working..."; display > .file-timestamps; else display; fi #-to fix: fi - - - diff --git a/install.sh b/install.sh old mode 100644 new mode 100755 index 08fc8e7..3bee724 --- a/install.sh +++ b/install.sh @@ -1,6 +1,67 @@ #!/bin/sh +set -e -echo "Installing folderstamp..." && echo "- Installing folderstamp command in /usr/bin..." -sudo cp -f folderstamp /usr/bin +command_exists() { + command -v "$1" >/dev/null 2>&1 +} + +install_dir() { + uname_s="$(uname -s 2>/dev/null || echo unknown)" + uname_o="$(uname -o 2>/dev/null || echo unknown)" + + if [ -n "${TERMUX_VERSION:-}" ] || [ "${PREFIX:-}" != "${PREFIX#*com.termux}" ] || [ "$uname_o" = "Android" ]; then + echo "${PREFIX:-/data/data/com.termux/files/usr}/bin" + elif [ "$uname_s" = "Redox" ]; then + echo "${HOME}/bin" + elif [ "$uname_s" = "Darwin" ]; then + echo "/usr/local/bin" + elif [ "${uname_s#CYGWIN}" != "$uname_s" ]; then + echo "/usr/local/bin" + elif [ "${uname_s%BSD}" != "$uname_s" ]; then + echo "/usr/local/bin" + elif [ "$uname_s" = "Fuchsia" ] || [ "$uname_s" = "Zircon" ]; then + echo "${HOME}/bin" + else + echo "/usr/bin" + fi +} + +copy_as_needed() { + src="$1" + dest="$2" + + if [ -w "$(dirname "$dest")" ]; then + cp -f "$src" "$dest" + elif command_exists sudo; then + sudo cp -f "$src" "$dest" + else + echo "Cannot write to $(dirname "$dest") and sudo is unavailable." >&2 + echo "Try: install -Dm755 folderstamp \"$dest\"" >&2 + exit 1 + fi +} + +chmod_as_needed() { + dest="$1" + + if [ -w "$dest" ]; then + chmod +x "$dest" + elif command_exists sudo; then + sudo chmod +x "$dest" + else + echo "Cannot chmod $dest and sudo is unavailable." >&2 + exit 1 + fi +} + +DEST_DIR="$(install_dir)" +DEST="$DEST_DIR/folderstamp" + +mkdir -p "$DEST_DIR" 2>/dev/null || true + +echo "Installing folderstamp..." +echo "- Installing folderstamp command in $DEST_DIR..." +copy_as_needed folderstamp "$DEST" echo "- Turning folderstamp into an executable..." -sudo chmod +x /usr/bin/folderstamp +chmod_as_needed "$DEST" +echo "folderstamp installed at $DEST" diff --git a/to-do.md b/to-do.md new file mode 100644 index 0000000..42b89b5 --- /dev/null +++ b/to-do.md @@ -0,0 +1,64 @@ +# To-do + +Uma lista organizada dos próximos feitiços técnicos do `folderstamp`. + +## Próximas prioridades + +- [ ] Adicionar flag `--help` com exemplos de uso para `display`, `save`, `--recursive` e futuras opções. +- [ ] Implementar flag `--hash` para controlar quando o CID/IPFS hash deve ser calculado. +- [ ] Criar rotação automática de `.folderstamp`, gerando `.folderstamp1`, `.folderstamp2` etc. quando o arquivo já existir. +- [ ] Adicionar suporte a `.folderstampignore`, seguindo uma lógica parecida com `.gitignore`. +- [ ] Ignorar itens internos por padrão, como `.git/` e o próprio `.folderstamp`, especialmente no modo recursivo. +- [ ] Registrar a data/hora exata no fim de cada `.folderstamp`. +- [ ] Adicionar opção para registrar o número do bloco Ethereum mais recente no momento do stamp. + +## Modos de listagem + +- [ ] Criar modo simples `.ls`, com rotação `.ls1`, `.ls2` etc. +- [ ] Criar `.folderstamp.listed` para evitar listar novamente arquivos já snapshotados anteriormente. +- [ ] Avaliar integração futura com uma biblioteca de nomes incrementais/untitled para evitar sobrescrever arquivos. + +## Desktop e ambiente gráfico + +- [ ] Quando o stamp for feito no Desktop, detectar o ambiente gráfico quando possível. +- [ ] Em Cinnamon, registrar o wallpaper atual com: + ```sh + gsettings get org.cinnamon.desktop.background picture-uri | tr -d "'" + ``` +- [ ] Pesquisar como registrar posições e ícones de itens no Desktop por ambiente gráfico. +- [ ] Fazer fallback silencioso quando não houver desktop environment detectado. + +## Recursividade e escopo + +- [ ] No modo recursivo, registrar também metadados das pastas, não apenas dos arquivos. +- [ ] Adicionar opção para limitar profundidade de recursão. +- [ ] Adicionar opção para escolher um número customizado para `.folderstamp`, recusando números já existentes. + +## Portabilidade e dependências + +- [ ] Evoluir o fallback `CIDv0 basic` para suportar chunking, diretórios e CIDv1/raw leaves. +- [ ] Estudar Iroh como alternativa Rust para gerar CIDv0 e CIDv1 dos arquivos sem depender diretamente do Kubo/IPFS. +- [ ] Expandir a detecção de package managers além de `apt`, `dnf`, `pacman`, `apk`, `zypper`, `pkg` e Cygwin setup. +- [ ] Criar instalador assistido para Kubo/IPFS com seleção automática de arquitetura. +- [ ] Adicionar checks para dependências opcionais como `df`, `awk`, `sed`, `find`, `tar` e `curl`. +- [ ] Documentar diferenças entre GNU/Linux, Termux, Cygwin e RedoxOS. + +## Documentação + +- [ ] Criar `README.md` com instalação, uso, exemplos e troubleshooting. +- [ ] Documentar as limitações do hash IPFS quando o daemon não está rodando. +- [ ] Adicionar exemplos de saída para modo recursivo e não-recursivo. +- [ ] Explicar como auditar um `.folderstamp` salvo. + +## Controle de versão alternativo + +- [ ] Melhorar suporte ao Gitoxide para extrair branch/remotes sem depender do Git clássico. +- [ ] Expandir suporte Pijul para registrar remotes, identidade do repositório e mudanças pendentes. +- [ ] Adicionar testes simulando ambientes com apenas `git`, apenas `gix`, apenas `pijul` e nenhum VCS instalado. + + +## Plataformas adicionais + +- [ ] Testar o instalador em macOS real com e sem Homebrew. +- [ ] Testar comandos BSD com `pkg` e `pkg_add` em shells não-GNU. +- [ ] Documentar o que é possível automatizar em Zircon/Fuchsia sem fingir universalidade fake.