diff options
| author | Benedikt Peetz <benedikt.peetz@b-peetz.de> | 2026-06-10 21:32:08 +0200 |
|---|---|---|
| committer | Benedikt Peetz <benedikt.peetz@b-peetz.de> | 2026-06-10 21:32:08 +0200 |
| commit | 796a8f59a61ed6e54d0d2b41a5d0155c5bb9696b (patch) | |
| tree | 538a0b1dac22b5aec2b65e67a0115369f44a1d88 | |
| parent | feat: Capture command output + expose to new `atuin_output` tool (#3510) (diff) | |
| download | atuin-796a8f59a61ed6e54d0d2b41a5d0155c5bb9696b.zip | |
chore: Remove unneeded files
65 files changed, 2 insertions, 5202 deletions
diff --git a/.atuin/skills/release/SKILL.md b/.atuin/skills/release/SKILL.md deleted file mode 100644 index bfe49f4d..00000000 --- a/.atuin/skills/release/SKILL.md +++ /dev/null @@ -1,213 +0,0 @@ ---- -name: release -description: > - Orchestrate a multi-step Atuin CLI release — version bumping, changelog - generation, PR creation, tagging, and crates.io publishing. Invoke with - /release or /release <version>. -disable-model-invocation: true -argument-hint: [version] ---- - -# Atuin CLI Release - -You are orchestrating a release of the Atuin CLI. Follow the steps below -**in order**, pausing at each checkpoint for user confirmation. Do not skip -steps or combine them. - -## Current State - -- Workspace version: !`sed -n '/^\[workspace\.package\]/,/^\[/s/^version = "\(.*\)"/\1/p' Cargo.toml` -- Latest tag: !`git describe --tags --abbrev=0 2>/dev/null || echo "none"` -- Suggested next version: !`git-cliff --bumped-version 2>/dev/null | sed 's/^v//' || echo "(unknown)"` - ---- - -## Step 1 — Check Dependencies - -Verify these tools are installed: `git`, `gsed`, `cargo`, `gh`, `git-cliff`. - -Use `command -v` for each. If any are missing, report which ones and stop. - -Remember to use `gsed`, or else macOS flags to regular `sed`, later in the workflow. - ---- - -## Step 2 — Determine Version - -The target version may be provided as `$ARGUMENTS`. If it's empty, use -AskUserQuestion to ask for the new version (show the current state above -for reference). - -After determining the version: -- If it contains a `-` (e.g. `18.15.0-beta.1`), it is a **prerelease**. - Note this — it affects changelog and publish behavior later. -- Show the user: `current → new` and whether it's a prerelease. -- **Checkpoint:** Ask the user to confirm before proceeding. - ---- - -## Step 3 — Set Up Working Directory - -Clone a fresh copy into a temp directory: - -```bash -WORKDIR=$(mktemp -d) -git clone git@github.com:atuinsh/atuin.git "$WORKDIR" -``` - -Print the working directory path so the user can find it if needed. - -NOTE: -ALL subsequent Bash commands run from `$WORKDIR`. - ---- - -## Step 4 — Create Branch & Update Versions - -1. Create a release branch named after the version (no `v` prefix): - `git checkout -b <VERSION>` - -2. Replace the old version with the new one in all `Cargo.toml` files. - **Escape dots** in the old version so sed treats them literally: - - ```bash - VERSION_PATTERN="${OLD_VERSION//./\\.}" - find . -type f -name 'Cargo.toml' -not -path './.git/*' \ - -exec gsed -i "s/$VERSION_PATTERN/$NEW_VERSION/g" {} \; - ``` - -3. Run `cargo check` to update `Cargo.lock`. - -4. Show `git diff --stat` and the version-related lines from the diff: - ```bash - git diff --unified=0 -- '*.toml' | grep '^\+.*version' | grep -vF '+++' - ``` - Remember to use macOS grep arguments on macOS systems. - -5. Verify the workspace version was actually updated by re-reading it - from `Cargo.toml`. - -6. **Checkpoint:** Show the diff summary and ask the user to confirm the - version changes look correct. - ---- - -## Step 5 — Update Changelog - -The changelog strategy differs for prereleases vs stable releases: - -- **Prerelease:** Maintain a running `## [unreleased]` section containing - all changes since the last stable release. Use: - `git-cliff --unreleased --strip all` - (cliff.toml's `ignore_tags` already ignores beta/alpha tags, so - `--unreleased` spans back to the last stable release automatically.) - -- **Stable release:** Generate a versioned entry that replaces the - `[unreleased]` section. Use: - `git-cliff --unreleased --tag "v<VERSION>" --strip all` - -Then update `CHANGELOG.md`: - -1. If an existing `## [unreleased]` or `## [Unreleased]` section exists, - **remove it entirely** (the heading and all content up to the next - `## ` heading). - -2. Insert the new entry before the first existing `## ` version heading. - -3. **Checkpoint:** Read and display the new changelog entry to the user. - Ask if they want any edits. If so, make the requested changes using - the Edit tool. Repeat until they're satisfied. - ---- - -## Step 6 — Commit & Push - -Stage all changes and commit: - -``` -chore(release): prepare for release <VERSION> -``` - -Push the branch with `--set-upstream origin`. - ---- - -## Step 7 — Create PR & Wait for Merge - -### Create the PR - -Extract the changelog entry body (everything between the new `## ` heading -and the next one) for the PR description. - -For prereleases, the heading to match is `## [unreleased]`. -For stable releases, it's `## <VERSION>` (escape dots in the awk pattern). - -Create the PR: -```bash -gh pr create \ - --title "chore(release): prepare for release <VERSION>" \ - --body "<body with changelog>" \ - --repo atuinsh/atuin - --draft -``` - -Show the PR URL to the user. Tell the user to go review and merge the PR. - -When the user reports the PR is merged, proceed to the next step. - ---- - -## Step 8 — Tag Release - -Back in the working directory: - -```bash -git checkout main -git pull -git tag "v<VERSION>" -git push --tags -``` - -Tell the user the tag was pushed and the release CI workflow has been -triggered. - ---- - -## Step 9 — Publish to crates.io - -**If this is a prerelease**, skip this step entirely and tell the user. - -**If this is a stable release**, ask the user whether to publish. - -If yes, publish each crate **in dependency order** using `--no-verify` -(the code already passed CI, and verification fails when crates.io -hasn't indexed a freshly-published dependency yet): - -``` -atuin-common, atuin-client, atuin-ai, atuin-dotfiles, atuin-history, -atuin-nucleo/matcher, atuin-nucleo, atuin-daemon, atuin-kv, -atuin-scripts, atuin-server-database, atuin-server-postgres, -atuin-server-sqlite, atuin-server, atuin-pty-proxy, atuin -``` - -For each crate, run from `crates/<name>`: -```bash -cargo publish --no-verify 2>&1 -``` - -If it fails with "already uploaded", report it as a skip (not an error) — -some crates like `atuin-nucleo` are versioned independently and may -already be published at their current version. - -If it fails for any other reason, stop and report the error. - ---- - -## Completion - -Summarize what was done: -- Version released -- PR URL -- Tag name -- Which crates were published (if any) -- Working directory path and how to clean it up (`rm -rf`) diff --git a/.claude/skills/hunk/SKILL.md b/.claude/skills/hunk/SKILL.md deleted file mode 100644 index 2306293f..00000000 --- a/.claude/skills/hunk/SKILL.md +++ /dev/null @@ -1,154 +0,0 @@ ---- -name: hunk-review -description: Interacts with live Hunk diff review sessions via CLI. Inspects review focus, navigates files and hunks, reloads session contents, and adds inline review comments. Use when the user has a Hunk session running or wants to review diffs interactively. ---- - -# Hunk Review - -Hunk is an interactive terminal diff viewer. The TUI is for the user -- do NOT run `hunk diff`, `hunk show`, or other interactive commands directly. Use `hunk session *` CLI commands to inspect and control live sessions through the local daemon. - -If no session exists, ask the user to launch Hunk in their terminal first. - -## Workflow - -```text -1. hunk session list # find live sessions -2. hunk session get --repo . # inspect path / repo / source -3. hunk session review --repo . --json # inspect file/hunk structure first -4. hunk session review --repo . --include-patch --json # opt into raw diff text only when needed -5. hunk session context --repo . # check current focus when needed -6. hunk session navigate ... # move to the right place -7. hunk session reload -- <command> # swap contents if needed -8. hunk session comment add ... # leave one review note -9. hunk session comment apply ... # apply many agent notes in one stdin batch -``` - -## Session selection - -Most session commands accept: - -- `--repo <path>` -- match the live session by its current loaded repo root (most common) -- `<session-id>` -- match by exact ID (use when multiple sessions share a repo) -- If only one session exists, it auto-resolves - -`reload` also supports: - -- `--session-path <path>` -- match the live Hunk window by its current working directory -- `--source <path>` -- load the replacement `diff` / `show` command from a different directory - -Use `--source` only for advanced reloads where the live session you want to control is not already associated with the checkout you want to load next. For a normal worktree session, prefer selecting it directly with `--repo /path/to/worktree`. - -## Commands - -### Inspect - -```bash -hunk session list [--json] -hunk session get (--repo . | <id>) [--json] -hunk session context (--repo . | <id>) [--json] -hunk session review (--repo . | <id>) [--json] [--include-patch] -``` - -- `get` shows the session `Path`, `Repo`, and `Source`, which helps when choosing between `--repo` and `--session-path` -- `Repo` is what `--repo` matches; `Path` is what `--session-path` matches -- `review --json` returns file and hunk structure by default; add `--include-patch` only when a caller truly needs raw unified diff text - -### Navigate - -Absolute navigation requires `--file` and exactly one of `--hunk`, `--new-line`, or `--old-line`: - -```bash -hunk session navigate --repo . --file src/App.tsx --hunk 2 -hunk session navigate --repo . --file src/App.tsx --new-line 372 -hunk session navigate --repo . --file src/App.tsx --old-line 355 -``` - -Relative comment navigation jumps between annotated hunks and does not require `--file`: - -```bash -hunk session navigate --repo . --next-comment -hunk session navigate --repo . --prev-comment -``` - -- `--hunk <n>` is 1-based -- `--new-line` / `--old-line` are 1-based line numbers on that diff side -- Use either `--next-comment` or `--prev-comment`, not both - -### Reload - -Swaps the live session's contents. Pass a Hunk review command after `--`: - -```bash -hunk session reload --repo . -- diff -hunk session reload --repo . -- diff main...feature -- src/ui -hunk session reload --repo . -- show HEAD~1 -hunk session reload --repo . -- show HEAD~1 -- README.md -hunk session reload --repo /path/to/worktree -- diff -hunk session reload --session-path /path/to/live-window --source /path/to/other-checkout -- diff -``` - -- Always include `--` before the nested Hunk command -- `--repo` or `<session-id>` usually selects the session you want -- `--source` is advanced: it does not select the session; it only changes where the replacement review command runs -- If the live session is already showing the target worktree, prefer `hunk session reload --repo /path/to/worktree -- diff` -- `--session-path` targets the live window when you need to keep session selection separate from reload source - -### Comments - -```bash -hunk session comment add --repo . --file README.md --new-line 103 --summary "Tighten this wording" [--rationale "..."] [--author "agent"] [--focus] -printf '%s\n' '{"comments":[{"filePath":"README.md","newLine":103,"summary":"Tighten this wording"}]}' | hunk session comment apply --repo . --stdin [--focus] -hunk session comment list --repo . [--file README.md] -hunk session comment rm --repo . <comment-id> -hunk session comment clear --repo . --yes [--file README.md] -``` - -- `comment add` is best for one note; `comment apply` is best when an agent already has several notes ready -- `comment add` requires `--file`, `--summary`, and exactly one of `--old-line` or `--new-line` -- `comment apply` payload items require `filePath`, `summary`, and exactly one target such as `hunk`, `hunkNumber`, `oldLine`, or `newLine` -- `comment apply` reads a JSON batch from stdin and validates the full batch before mutating the live session -- Pass `--focus` when you want to jump to the new note or the first note in a batch -- `comment list` and `comment clear` accept optional `--file` -- Quote `--summary` and `--rationale` defensively in the shell - -## New files in working-tree reviews - -`hunk diff` includes untracked files by default. If the user wants tracked changes only, reload with `--exclude-untracked`: - -```bash -hunk session reload --repo . -- diff --exclude-untracked -``` - -## Guiding a review - -The user may ask you to walk them through a changeset or review code using Hunk. Start with `hunk session review --json` to understand the file/hunk structure without inflating agent context, then use `--include-patch` only for the files you truly need to read in raw diff form. Use `context` and `navigate` to line up the user's current view before adding comments. - -Your role is to narrate: steer the user's view to what matters and leave comments that explain what they're looking at. - -Typical flow: - -1. Load the right content (`reload` if needed) -2. Navigate to the first interesting file / hunk -3. Add a comment explaining what's happening and why -4. If you already have several notes ready, prefer one `comment apply` batch over many separate shell invocations -5. Summarize when done - -Guidelines: - -- Work in the order that tells the clearest story, not necessarily file order -- Navigate before commenting so the user sees the code you're discussing -- Use `comment apply` for agent-generated batches and `comment add` for one-off notes -- Use `--focus` sparingly when the note itself should actively steer the review -- Keep comments focused: intent, structure, risks, or follow-ups -- Don't comment on every hunk -- highlight what the user wouldn't spot themselves - -## Common errors - -- **"No visible diff file matches ..."** -- the file is not in the loaded review. Check `context`, then `reload` if needed. -- **"No active Hunk sessions"** -- ask the user to open Hunk in their terminal. -- **"Multiple active sessions match"** -- pass `<session-id>` explicitly. -- **"No active Hunk session matches session path ..."** -- for advanced split-path reloads, verify the live window `Path` via `hunk session get` or `list`, then use `--session-path`. -- **"Pass the replacement Hunk command after `--`"** -- include `--` before the nested `diff` / `show` command. -- **"Pass --stdin to read batch comments from stdin JSON."** -- `comment apply` only reads its batch payload from stdin. -- **"Specify exactly one navigation target"** -- pick one of `--hunk`, `--old-line`, or `--new-line`. -- **"Specify either --next-comment or --prev-comment, not both."** -- choose one comment-navigation direction. diff --git a/.claude/skills/release/SKILL.md b/.claude/skills/release/SKILL.md deleted file mode 100644 index a90efc69..00000000 --- a/.claude/skills/release/SKILL.md +++ /dev/null @@ -1,269 +0,0 @@ ---- -name: release -description: > - Orchestrate a multi-step Atuin CLI release — version bumping, changelog - generation, PR creation, tagging, and crates.io publishing. Invoke with - /release or /release <version>. -disable-model-invocation: true -argument-hint: [version] ---- - -# Atuin CLI Release - -You are orchestrating a release of the Atuin CLI. Follow the steps below -**in order**, pausing at each checkpoint for user confirmation. Do not skip -steps or combine them. - -## Current State - -- Workspace version: !`sed -n '/^\[workspace\.package\]/,/^\[/s/^version = "\(.*\)"/\1/p' Cargo.toml` -- Latest tag: !`git describe --tags --abbrev=0 2>/dev/null || echo "none"` -- Suggested next version: !`git-cliff --bumped-version 2>/dev/null | sed 's/^v//' || echo "(unknown)"` - ---- - -## Step 1 — Check Dependencies - -Verify these tools are installed: `git`, `gsed`, `cargo`, `gh`, `git-cliff`. - -Use `command -v` for each. If any are missing, report which ones and stop. - ---- - -## Step 2 — Determine Version - -The target version may be provided as `$ARGUMENTS`. If it's empty, use -AskUserQuestion to ask for the new version (show the current state above -for reference). - -After determining the version: -- If it contains a `-` (e.g. `18.15.0-beta.1`), it is a **prerelease**. - Note this — it affects changelog and publish behavior later. -- Show the user: `current → new` and whether it's a prerelease. -- **Checkpoint:** Ask the user to confirm before proceeding. - ---- - -## Step 3 — Set Up Working Directory - -Clone a fresh copy into a temp directory: - -```bash -WORKDIR=$(mktemp -d) -git clone git@github.com:atuinsh/atuin.git "$WORKDIR" -``` - -Print the working directory path so the user can find it if needed. -All subsequent Bash commands run from `$WORKDIR`. - ---- - -## Step 4 — Create Branch & Update Versions - -1. Create a release branch named after the version (no `v` prefix): - `git checkout -b <VERSION>` - -2. Replace the old version with the new one in all `Cargo.toml` files. - **Escape dots** in the old version so sed treats them literally: - - ```bash - VERSION_PATTERN="${OLD_VERSION//./\\.}" - find . -type f -name 'Cargo.toml' -not -path './.git/*' \ - -exec gsed -i "s/$VERSION_PATTERN/$NEW_VERSION/g" {} \; - ``` - -3. Run `cargo check` to update `Cargo.lock`. - -4. Show `git diff --stat` and the version-related lines from the diff: - ```bash - git diff --unified=0 -- '*.toml' | grep -E '^\+.*version' | grep -v '^\+\+\+' - ``` - -5. Verify the workspace version was actually updated by re-reading it - from `Cargo.toml`. - -6. **Checkpoint:** Show the diff summary and ask the user to confirm the - version changes look correct. - ---- - -## Step 5 — Update Changelog - -The changelog strategy differs for prereleases vs stable releases: - -- **Prerelease:** Maintain a running `## [unreleased]` section containing - all changes since the last stable release. Use: - `git-cliff --unreleased --strip all` - (cliff.toml's `ignore_tags` already ignores beta/alpha tags, so - `--unreleased` spans back to the last stable release automatically.) - -- **Stable release:** Generate a versioned entry that replaces the - `[unreleased]` section. Use: - `git-cliff --unreleased --tag "v<VERSION>" --strip all` - -Then update `CHANGELOG.md`: - -1. If an existing `## [unreleased]` or `## [Unreleased]` section exists, - **remove it entirely** (the heading and all content up to the next - `## ` heading). - -2. Insert the new entry before the first existing `## ` version heading. - -3. **Checkpoint:** Read and display the new changelog entry to the user. - Ask if they want any edits. If so, make the requested changes using - the Edit tool. Repeat until they're satisfied. - ---- - -## Step 6 — Commit & Push - -Stage all changes and commit: - -``` -chore(release): prepare for release <VERSION> -``` - -Push the branch with `--set-upstream origin`. - ---- - -## Step 7 — Create PR & Wait for Merge - -### Create the PR - -Extract the changelog entry body (everything between the new `## ` heading -and the next one) for the PR description. - -For prereleases, the heading to match is `## [unreleased]`. -For stable releases, it's `## <VERSION>` (escape dots in the awk pattern). - -Create the PR: -```bash -gh pr create \ - --title "chore(release): prepare for release <VERSION>" \ - --body "<body with changelog>" \ - --repo atuinsh/atuin -``` - -Show the PR URL to the user. - -### Wait for merge - -Start a **persistent Monitor** that polls the PR status every 30 seconds. -The monitor script must: -- **Only emit output** on meaningful state changes: all checks green, PR - merged, or PR closed. Silent polls keep the monitor quiet and avoid - flooding notifications. -- Handle transient API errors gracefully (don't crash on a single failure) -- Exit 0 on `MERGED`, exit 1 on `CLOSED` - -The rollup mixes two entry shapes: `CheckRun` entries use `status` + -`conclusion`, while `StatusContext` entries use `state`. A check counts -as "passing" when it's in a terminal state with a non-failing outcome. -Treat `SUCCESS`, `SKIPPED`, and `NEUTRAL` as passing — some release -workflows (e.g. `announce`, `build-global-artifacts`) are conditional -and report `SKIPPED` on non-tag events, which is expected, not a -failure. - -Example monitor script (substitute the actual PR number): -```bash -checks_passed=false -while true; do - json=$(gh pr view PR_NUM --repo atuinsh/atuin --json state,statusCheckRollup 2>/dev/null) || { sleep 30; continue; } - state=$(echo "$json" | jq -r '.state') - case "$state" in - MERGED) echo "PR #PR_NUM has been merged!"; exit 0 ;; - CLOSED) echo "PR #PR_NUM was closed without merging."; exit 1 ;; - esac - # Only notify once when all checks reach a terminal passing state. - # CheckRun entries carry `status`/`conclusion`; StatusContext entries - # carry `state`. SKIPPED and NEUTRAL count as passing. - if [ "$checks_passed" = false ]; then - counts=$(echo "$json" | jq -r ' - [.statusCheckRollup[]?] as $all - | ($all | map(select( - (.status == "COMPLETED" and (.conclusion | IN("SUCCESS","SKIPPED","NEUTRAL"))) - or .state == "SUCCESS" - )) | length) as $passing - | ($all | map(select( - (.status == "COMPLETED" and (.conclusion | IN("FAILURE","TIMED_OUT","CANCELLED","ACTION_REQUIRED","STALE"))) - or (.state | IN("FAILURE","ERROR")) - )) | length) as $failing - | "\($all | length) \($passing) \($failing)" - ' 2>/dev/null) - read -r total passing failing <<<"$counts" - if [ "${failing:-0}" -gt 0 ] 2>/dev/null; then - echo "PR #PR_NUM has $failing failing check(s) — investigate before merging." - checks_passed=true # don't re-notify - elif [ "${total:-0}" -gt 0 ] 2>/dev/null && [ "$total" = "$passing" ]; then - echo "All $total checks passed on PR #PR_NUM — ready to merge!" - checks_passed=true - fi - fi - sleep 30 -done -``` - -Tell the user to go review and merge the PR. While the monitor runs, you -can respond to other questions — the monitor notifications will arrive -asynchronously. - -When the monitor reports `MERGED`, proceed to the next step. -If it reports `CLOSED`, inform the user and stop the release. - ---- - -## Step 8 — Tag Release - -Back in the working directory: - -```bash -git checkout main -git pull -git tag "v<VERSION>" -git push --tags -``` - -Tell the user the tag was pushed and the release CI workflow has been -triggered. - ---- - -## Step 9 — Publish to crates.io - -**If this is a prerelease**, skip this step entirely and tell the user. - -**If this is a stable release**, ask the user whether to publish. - -If yes, publish each crate **in dependency order** using `--no-verify` -(the code already passed CI, and verification fails when crates.io -hasn't indexed a freshly-published dependency yet): - -``` -atuin-common, atuin-client, atuin-ai, atuin-dotfiles, atuin-history, -atuin-nucleo/matcher, atuin-nucleo, atuin-daemon, atuin-kv, -atuin-scripts, atuin-server-database, atuin-server-postgres, -atuin-server-sqlite, atuin-server, atuin-pty-proxy, atuin -``` - -For each crate, run from `crates/<name>`: -```bash -cargo publish --no-verify 2>&1 -``` - -If it fails with "already uploaded", report it as a skip (not an error) — -some crates like `atuin-nucleo` are versioned independently and may -already be published at their current version. - -If it fails for any other reason, stop and report the error. - ---- - -## Completion - -Summarize what was done: -- Version released -- PR URL -- Tag name -- Which crates were published (if any) -- Working directory path and how to clean it up (`rm -rf`) diff --git a/.depot/workflows/codespell.yml b/.depot/workflows/codespell.yml deleted file mode 100644 index 2647cb49..00000000 --- a/.depot/workflows/codespell.yml +++ /dev/null @@ -1,28 +0,0 @@ -# Depot CI Migration -# Source: .github/workflows/codespell.yml -# -# No changes were necessary. - -# Codespell configuration is within .codespellrc -name: Codespell -on: - push: - branches: [main] - pull_request: - branches: [main] -permissions: - contents: read -jobs: - codespell: - name: Check for spelling errors - runs-on: depot-ubuntu-24.04 - steps: - - name: Checkout - uses: actions/checkout@v6 - - name: Codespell - uses: codespell-project/actions-codespell@v2 - with: - # This is regenerated from commit history - # we cannot rewrite commit history, and I'd rather not correct it - # every time - exclude_file: CHANGELOG.md diff --git a/.depot/workflows/installer.yml b/.depot/workflows/installer.yml deleted file mode 100644 index 57a6a466..00000000 --- a/.depot/workflows/installer.yml +++ /dev/null @@ -1,36 +0,0 @@ -# Depot CI Migration -# Source: .github/workflows/installer.yml -# -# No changes were necessary. - -name: Install -on: - push: - branches: [main] - pull_request: - paths: .github/workflows/installer.yml -env: - CARGO_TERM_COLOR: always -jobs: - install: - strategy: - matrix: - os: [depot-ubuntu-24.04, macos-14] - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v6 - - name: Install zsh for ubuntu - if: matrix.os == 'depot-ubuntu-24.04' - run: | - sudo apt install zsh - - name: Test install script on bash - run: | - /bin/bash -c "$(curl --proto '=https' --tlsv1.2 -sSf https://setup.atuin.sh)" - [ -d "$HOME/.atuin" ] && source $HOME/.atuin/bin/env - atuin --help - - name: Test install script on zsh - shell: zsh {0} - run: | - /bin/bash -c "$(curl --proto '=https' --tlsv1.2 -sSf https://setup.atuin.sh)" - [ -d "$HOME/.atuin" ] && source $HOME/.atuin/bin/env - atuin --help diff --git a/.depot/workflows/nix.yml b/.depot/workflows/nix.yml deleted file mode 100644 index 3b5a360a..00000000 --- a/.depot/workflows/nix.yml +++ /dev/null @@ -1,33 +0,0 @@ -# Depot CI Migration -# Source: .github/workflows/nix.yml -# -# No changes were necessary. - -# Verify the Nix build is working -# Failures will usually occur due to an out of date Rust version -# That can be updated to the latest version in nixpkgs-unstable with `nix flake update` -name: Nix -on: - push: - branches: [main] - paths-ignore: - - 'ui/**' - pull_request: - branches: [main] - paths-ignore: - - 'ui/**' -jobs: - check: - runs-on: depot-ubuntu-24.04 - steps: - - uses: actions/checkout@v6 - - uses: cachix/install-nix-action@v31 - - name: Run nix flake check - run: nix flake check --print-build-logs - build-test: - runs-on: depot-ubuntu-24.04 - steps: - - uses: actions/checkout@v6 - - uses: cachix/install-nix-action@v31 - - name: Run nix build - run: nix build --print-build-logs diff --git a/.depot/workflows/rust.yml b/.depot/workflows/rust.yml deleted file mode 100644 index 550995d7..00000000 --- a/.depot/workflows/rust.yml +++ /dev/null @@ -1,187 +0,0 @@ -# Depot CI Migration -# Source: .github/workflows/rust.yml -# -# No changes were necessary. - -name: Rust -on: - push: - branches: [main] - paths-ignore: - - "ui/**" - pull_request: - branches: [main] - paths-ignore: - - "ui/**" -env: - CARGO_TERM_COLOR: always -jobs: - build: - strategy: - matrix: - os: [depot-ubuntu-24.04, macos-14, windows-latest] - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v6 - - name: Install rust - uses: dtolnay/rust-toolchain@master - with: - toolchain: 1.94.0 - - uses: actions/cache@v5 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-cargo-release-${{ hashFiles('**/Cargo.lock') }} - - name: Run cargo build common - run: cargo build -p atuin-common --locked --release - - name: Run cargo build client - run: cargo build -p atuin-client --locked --release - - name: Run cargo build server - run: cargo build -p atuin-server --locked --release - - name: Run cargo build main - run: cargo build --all --locked --release - cross-compile: - strategy: - matrix: - # There was an attempt to make cross-compiles also work on FreeBSD, but that failed with: - # - # warning: libelf.so.2, needed by <...>/libkvm.so, not found (try using -rpath or -rpath-link) - target: [x86_64-unknown-illumos] - runs-on: depot-ubuntu-24.04 - steps: - - uses: actions/checkout@v6 - - name: Install cross - uses: taiki-e/install-action@v2 - with: - tool: cross - - uses: actions/cache@v5 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ matrix.target }}-cross-compile-${{ hashFiles('**/Cargo.lock') }} - - name: Run cross build common - run: cross build -p atuin-common --locked --target ${{ matrix.target }} - - name: Run cross build client - run: cross build -p atuin-client --locked --target ${{ matrix.target }} - - name: Run cross build server - run: cross build -p atuin-server --locked --target ${{ matrix.target }} - - name: Run cross build main - run: | - cross build --all --locked --target ${{ matrix.target }} - unit-test: - strategy: - matrix: - os: [depot-ubuntu-24.04, macos-14, windows-latest] - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v6 - - name: Install rust - uses: dtolnay/rust-toolchain@master - with: - toolchain: 1.94.0 - - uses: taiki-e/install-action@v2 - name: Install nextest - with: - tool: cargo-nextest - - uses: actions/cache@v5 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-cargo-debug-${{ hashFiles('**/Cargo.lock') }} - - name: Run cargo test - run: cargo nextest run --lib --bins - check: - strategy: - matrix: - os: [depot-ubuntu-24.04, macos-14, windows-latest] - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v6 - - name: Install rust - uses: dtolnay/rust-toolchain@master - with: - toolchain: 1.94.0 - - uses: actions/cache@v5 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-cargo-debug-${{ hashFiles('**/Cargo.lock') }} - - name: Run cargo check (all features) - run: cargo check --all-features --workspace - - name: Run cargo check (no features) - run: cargo check --no-default-features --workspace - - name: Run cargo check (sync) - run: cargo check --no-default-features --features sync --workspace - - name: Run cargo check (server) - run: cargo check -p atuin-server - - name: Run cargo check (client only) - run: cargo check --no-default-features --features client --workspace - integration-test: - runs-on: depot-ubuntu-24.04 - services: - postgres: - image: postgres - env: - POSTGRES_USER: atuin - POSTGRES_PASSWORD: pass - POSTGRES_DB: atuin - ports: - - 5432:5432 - steps: - - uses: actions/checkout@v6 - - name: Install rust - uses: dtolnay/rust-toolchain@master - with: - toolchain: 1.94.0 - - uses: taiki-e/install-action@v2 - name: Install nextest - with: - tool: cargo-nextest - - uses: actions/cache@v5 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-cargo-debug-${{ hashFiles('**/Cargo.lock') }} - - name: Run cargo test - run: cargo nextest run --test '*' - env: - ATUIN_DB_URI: postgres://atuin:pass@localhost:5432/atuin - clippy: - runs-on: depot-ubuntu-24.04 - steps: - - uses: actions/checkout@v6 - - name: Install latest rust - uses: dtolnay/rust-toolchain@master - with: - toolchain: 1.94.0 - components: clippy - - uses: actions/cache@v5 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-cargo-debug-${{ hashFiles('**/Cargo.lock') }} - - name: Run clippy - run: cargo clippy -- -D warnings -D clippy::redundant_clone - format: - runs-on: depot-ubuntu-24.04 - steps: - - uses: actions/checkout@v6 - - name: Install latest rust - uses: dtolnay/rust-toolchain@master - with: - toolchain: 1.94.0 - components: rustfmt - - name: Format - run: cargo fmt -- --check diff --git a/.depot/workflows/shellcheck.yml b/.depot/workflows/shellcheck.yml deleted file mode 100644 index 99a2c434..00000000 --- a/.depot/workflows/shellcheck.yml +++ /dev/null @@ -1,20 +0,0 @@ -# Depot CI Migration -# Source: .github/workflows/shellcheck.yml -# -# No changes were necessary. - -name: Shellcheck -on: - push: - branches: [main] - pull_request: - branches: [main] -jobs: - shellcheck: - runs-on: depot-ubuntu-24.04 - steps: - - uses: actions/checkout@v6 - - name: Run shellcheck - uses: ludeeus/action-shellcheck@master - env: - SHELLCHECK_OPTS: "-e SC2148" diff --git a/.depot/workflows/update-nix-deps.yml b/.depot/workflows/update-nix-deps.yml deleted file mode 100644 index 6c83816a..00000000 --- a/.depot/workflows/update-nix-deps.yml +++ /dev/null @@ -1,25 +0,0 @@ -# Depot CI Migration -# Source: .github/workflows/update-nix-deps.yml -# -# No changes were necessary. - -name: Update Nix Deps -on: - workflow_dispatch: # allows manual triggering - schedule: - - cron: '0 0 1 * *' # runs monthly on the first day of the month at 00:00 -jobs: - lockfile: - runs-on: depot-ubuntu-24.04 - if: github.repository == 'atuinsh/atuin' - steps: - - name: Checkout repository - uses: actions/checkout@v6 - - name: Install Nix - uses: DeterminateSystems/nix-installer-action@main - - name: Update flake.lock - uses: DeterminateSystems/update-flake-lock@main - with: - pr-title: "chore(deps): update flake.lock" - pr-labels: | - dependencies diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index 1f5346b7..00000000 --- a/.dockerignore +++ /dev/null @@ -1,2 +0,0 @@ -./target -Dockerfile diff --git a/.fossier.db b/.fossier.db Binary files differdeleted file mode 100644 index 216c685e..00000000 --- a/.fossier.db +++ /dev/null diff --git a/.github/DISCUSSION_TEMPLATE/support.yml b/.github/DISCUSSION_TEMPLATE/support.yml deleted file mode 100644 index b6a6ae40..00000000 --- a/.github/DISCUSSION_TEMPLATE/support.yml +++ /dev/null @@ -1,84 +0,0 @@ -body: - - type: input - attributes: - label: Operating System - description: What operating system are you using? - placeholder: "Example: macOS Big Sur" - validations: - required: true - - - type: input - attributes: - label: Shell - description: What shell are you using? - placeholder: "Example: zsh 5.8.1" - validations: - required: true - - - type: dropdown - attributes: - label: Version - description: What version of atuin are you running? - multiple: false - options: # how often will I forget to update this? a lot. - - v17.0.0 (Default) - - v16.0.0 - - v15.0.0 - - v14.0.1 - - v14.0.0 - - v13.0.1 - - v13.0.0 - - v12.0.0 - - v11.0.0 - - v0.10.0 - - v0.9.1 - - v0.9.0 - - v0.8.1 - - v0.8.0 - - v0.7.2 - - v0.7.1 - - v0.7.0 - - v0.6.4 - - v0.6.3 - default: 0 - validations: - required: true - - - type: checkboxes - attributes: - label: Self hosted - description: Are you self hosting atuin server? - options: - - label: I am self hosting atuin server - - - type: checkboxes - attributes: - label: Search the issues - description: Did you search the issues and discussions for your problem? - options: - - label: I checked that someone hasn't already asked about the same issue - required: true - - - type: textarea - attributes: - label: Behaviour - description: "Please describe the issue - what you expected to happen, what actually happened" - - - type: textarea - attributes: - label: Logs - description: "If possible, please include logs from atuin, especially if you self host the server - ATUIN_LOG=debug" - - - type: textarea - attributes: - label: Extra information - description: "Anything else you'd like to add?" - - - type: checkboxes - attributes: - label: Code of Conduct - description: The Code of Conduct helps create a safe space for everyone. We require - that everyone agrees to it. - options: - - label: I agree to follow this project's [Code of Conduct](https://github.com/atuinsh/atuin/blob/main/CODE_OF_CONDUCT.md) - required: true diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index 8b9c8039..00000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1,13 +0,0 @@ -# These are supported funding model platforms - -github: [atuinsh] -patreon: # Replace with a single Patreon username -open_collective: # Replace with a single Open Collective username -ko_fi: # Replace with a single Ko-fi username -tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel -community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry -liberapay: # Replace with a single Liberapay username -issuehunt: # Replace with a single IssueHunt username -otechie: # Replace with a single Otechie username -lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry -custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff --git a/.github/ISSUE_TEMPLATE/bug.yaml b/.github/ISSUE_TEMPLATE/bug.yaml deleted file mode 100644 index 54cc46d7..00000000 --- a/.github/ISSUE_TEMPLATE/bug.yaml +++ /dev/null @@ -1,39 +0,0 @@ -name: Bug Report -description: File a bug report -title: "[Bug]: " -labels: ["bug", "triage"] -body: - - type: markdown - attributes: - value: | - Thanks for taking the time to fill out this bug report! - - type: textarea - id: what-expected - attributes: - label: What did you expect to happen? - placeholder: Tell us what you expected to see! - validations: - required: true - - type: textarea - id: what-happened - attributes: - label: What happened? - placeholder: Tell us what you see! - validations: - required: true - - type: textarea - id: doctor - validations: - required: true - attributes: - label: Atuin doctor output - description: Please run 'atuin doctor' and share the output. If it fails to run, share any errors. This requires Atuin >=v18.1.0 - render: yaml - - type: checkboxes - id: terms - attributes: - label: Code of Conduct - description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/atuinsh/atuin/blob/main/CODE_OF_CONDUCT.md) - options: - - label: I agree to follow this project's Code of Conduct - required: true diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 9380a5ce..00000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,19 +0,0 @@ -# To get started with Dependabot version updates, you'll need to specify which -# package ecosystems to update and where the package manifests are located. -# Please see the documentation for all configuration options: -# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates - -version: 2 -updates: - - package-ecosystem: "cargo" # See documentation for possible values - directory: "/" # Location of package manifests - schedule: - interval: "weekly" - - package-ecosystem: "docker" # See documentation for possible values - directory: "/" # Location of package manifests - schedule: - interval: "weekly" - - package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: "weekly" diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md deleted file mode 100644 index 4621b63c..00000000 --- a/.github/pull_request_template.md +++ /dev/null @@ -1,5 +0,0 @@ -<!-- Thank you for making a PR! Bug fixes are always welcome, but if you're adding a new feature or changing an existing one, we'd really appreciate if you open an issue, post on the forum, or drop in on Discord --> - -## Checks -- [ ] I am happy for maintainers to push small adjustments to this PR, to speed up the review cycle -- [ ] I have checked that there are no existing pull requests for the same thing diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml deleted file mode 100644 index 7d941112..00000000 --- a/.github/workflows/codespell.yml +++ /dev/null @@ -1,28 +0,0 @@ -# Codespell configuration is within .codespellrc ---- -name: Codespell - -on: - push: - branches: [main] - pull_request: - branches: [main] - -permissions: - contents: read - -jobs: - codespell: - name: Check for spelling errors - runs-on: depot-ubuntu-24.04 - - steps: - - name: Checkout - uses: actions/checkout@v6 - - name: Codespell - uses: codespell-project/actions-codespell@v2 - with: - # This is regenerated from commit history - # we cannot rewrite commit history, and I'd rather not correct it - # every time - exclude_file: CHANGELOG.md diff --git a/.github/workflows/docker.yaml b/.github/workflows/docker.yaml deleted file mode 100644 index 8761aaf6..00000000 --- a/.github/workflows/docker.yaml +++ /dev/null @@ -1,61 +0,0 @@ -name: build-docker - -on: - push: - branches: [main] - tags: - - 'v*' - -jobs: - publish: - concurrency: - group: ${{ github.ref }}-docker - cancel-in-progress: true - permissions: - packages: write - contents: read - id-token: write - - runs-on: depot-ubuntu-24.04 - steps: - - uses: actions/checkout@v6 - - - name: Get Repo Owner - id: get_repo_owner - run: echo "REPO_OWNER=$(echo ${{ github.repository_owner }} | tr '[:upper:]' '[:lower:]')" > $GITHUB_ENV - - - uses: depot/setup-action@v1 - - - name: Login to container Registry - uses: docker/login-action@v3 - with: - username: ${{ github.repository_owner }} - password: ${{ secrets.GITHUB_TOKEN }} - registry: ghcr.io - - - name: Docker meta - id: meta - uses: docker/metadata-action@v5 - with: - images: ghcr.io/${{ env.REPO_OWNER }}/atuin - flavor: | - latest=false - tags: | - type=ref,event=branch - type=sha,prefix= - type=semver,pattern={{version}} - type=semver,pattern={{major}}.{{minor}} - - - name: Build and push - uses: depot/build-push-action@v1 - with: - push: true - platforms: linux/amd64,linux/arm64 - file: ./Dockerfile - context: . - provenance: false - build-args: | - Version=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.version'] || 'dev' }} - GitCommit=${{ github.sha }} - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} diff --git a/.github/workflows/fossier-scan.yml b/.github/workflows/fossier-scan.yml deleted file mode 100644 index 5c89be67..00000000 --- a/.github/workflows/fossier-scan.yml +++ /dev/null @@ -1,51 +0,0 @@ -name: Fossier Scan All PRs - -on: - workflow_dispatch: - inputs: - dry-run: - description: "Dry run - evaluate but don't take actions" - type: boolean - default: false - -permissions: - contents: read - pull-requests: write - issues: write - -jobs: - scan: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Set up uv - uses: astral-sh/setup-uv@v4 - - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: "3.13" - - - name: Install fossier - run: uv tool install git+https://github.com/pthorpe92/fossier.git - - - name: Restore DB cache - uses: actions/cache@v4 - with: - path: .fossier.db - key: fossier-db-${{ github.repository }} - restore-keys: | - fossier-db-${{ github.repository }} - - - name: Scan open PRs - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - FLAGS="--format table" - if [ "${{ inputs.dry-run }}" = "true" ]; then - FLAGS="$FLAGS --dry-run" - else - FLAGS="$FLAGS --execute" - fi - fossier scan $FLAGS diff --git a/.github/workflows/fossier.yml b/.github/workflows/fossier.yml deleted file mode 100644 index e582e2d3..00000000 --- a/.github/workflows/fossier.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: Fossier PR Check -on: - pull_request_target: - types: [opened, synchronize] - issue_comment: - types: [created] - -permissions: - contents: write - pull-requests: write - issues: write - -jobs: - check: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - uses: PThorpe92/fossier@6e7f2a6c1c727949e2a6c94d7dc6904d7bb40928 - id: fossier - with: - contact-url: "https://discord.gg/Fq8bJSKPHh" - github-token: ${{ secrets.GITHUB_TOKEN }} - # Optional: connect to the global spam registry - # registry-api-key: ${{ secrets.FOSSIER_REGISTRY_API_KEY }} - - - name: Handle result - if: steps.fossier.outputs.outcome == 'deny' - run: echo "PR denied with score ${{ steps.fossier.outputs.score }}" diff --git a/.github/workflows/installer.yml b/.github/workflows/installer.yml deleted file mode 100644 index 2cc4f89f..00000000 --- a/.github/workflows/installer.yml +++ /dev/null @@ -1,38 +0,0 @@ -name: Install - -on: - push: - branches: [main] - pull_request: - paths: .github/workflows/installer.yml - -env: - CARGO_TERM_COLOR: always - -jobs: - install: - strategy: - matrix: - os: [depot-ubuntu-24.04, macos-14] - runs-on: ${{ matrix.os }} - - steps: - - uses: actions/checkout@v6 - - - name: Install zsh for ubuntu - if: matrix.os == 'depot-ubuntu-24.04' - run: | - sudo apt install zsh - - - name: Test install script on bash - run: | - /bin/bash -c "$(curl --proto '=https' --tlsv1.2 -sSf https://setup.atuin.sh)" - [ -d "$HOME/.atuin" ] && source $HOME/.atuin/bin/env - atuin --help - - - name: Test install script on zsh - shell: zsh {0} - run: | - /bin/bash -c "$(curl --proto '=https' --tlsv1.2 -sSf https://setup.atuin.sh)" - [ -d "$HOME/.atuin" ] && source $HOME/.atuin/bin/env - atuin --help diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml deleted file mode 100644 index 515a05eb..00000000 --- a/.github/workflows/nix.yml +++ /dev/null @@ -1,34 +0,0 @@ -# Verify the Nix build is working -# Failures will usually occur due to an out of date Rust version -# That can be updated to the latest version in nixpkgs-unstable with `nix flake update` -name: Nix -on: - push: - branches: [ main ] - paths-ignore: - - 'ui/**' - pull_request: - branches: [ main ] - paths-ignore: - - 'ui/**' - -jobs: - check: - runs-on: depot-ubuntu-24.04 - - steps: - - uses: actions/checkout@v6 - - uses: cachix/install-nix-action@v31 - - - name: Run nix flake check - run: nix flake check --print-build-logs - - build-test: - runs-on: depot-ubuntu-24.04 - - steps: - - uses: actions/checkout@v6 - - uses: cachix/install-nix-action@v31 - - - name: Run nix build - run: nix build --print-build-logs diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 5da97452..00000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,304 +0,0 @@ -# This file was autogenerated by dist: https://axodotdev.github.io/cargo-dist -# -# Copyright 2022-2024, axodotdev -# SPDX-License-Identifier: MIT or Apache-2.0 -# -# CI that: -# -# * checks for a Git Tag that looks like a release -# * builds artifacts with dist (archives, installers, hashes) -# * uploads those artifacts to temporary workflow zip -# * on success, uploads the artifacts to a GitHub Release -# -# Note that the GitHub Release will be created with a generated -# title/body based on your changelogs. - -name: Release -permissions: - "contents": "write" - -# This task will run whenever you push a git tag that looks like a version -# like "1.0.0", "v0.1.0-prerelease.1", "my-app/0.1.0", "releases/v1.0.0", etc. -# Various formats will be parsed into a VERSION and an optional PACKAGE_NAME, where -# PACKAGE_NAME must be the name of a Cargo package in your workspace, and VERSION -# must be a Cargo-style SemVer Version (must have at least major.minor.patch). -# -# If PACKAGE_NAME is specified, then the announcement will be for that -# package (erroring out if it doesn't have the given version or isn't dist-able). -# -# If PACKAGE_NAME isn't specified, then the announcement will be for all -# (dist-able) packages in the workspace with that version (this mode is -# intended for workspaces with only one dist-able package, or with all dist-able -# packages versioned/released in lockstep). -# -# If you push multiple tags at once, separate instances of this workflow will -# spin up, creating an independent announcement for each one. However, GitHub -# will hard limit this to 3 tags per commit, as it will assume more tags is a -# mistake. -# -# If there's a prerelease-style suffix to the version, then the release(s) -# will be marked as a prerelease. -on: - pull_request: - push: - tags: - - '**[0-9]+.[0-9]+.[0-9]+*' - -jobs: - # Run 'dist plan' (or host) to determine what tasks we need to do - plan: - runs-on: "ubuntu-22.04" - outputs: - val: ${{ steps.plan.outputs.manifest }} - tag: ${{ !github.event.pull_request && github.ref_name || '' }} - tag-flag: ${{ !github.event.pull_request && format('--tag={0}', github.ref_name) || '' }} - publishing: ${{ !github.event.pull_request }} - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - steps: - - uses: actions/checkout@v6 - with: - persist-credentials: false - submodules: recursive - - name: Install dist - # we specify bash to get pipefail; it guards against the `curl` command - # failing. otherwise `sh` won't catch that `curl` returned non-0 - shell: bash - run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v0.31.0/cargo-dist-installer.sh | sh" - - name: Cache dist - uses: actions/upload-artifact@v6 - with: - name: cargo-dist-cache - path: ~/.cargo/bin/dist - # sure would be cool if github gave us proper conditionals... - # so here's a doubly-nested ternary-via-truthiness to try to provide the best possible - # functionality based on whether this is a pull_request, and whether it's from a fork. - # (PRs run on the *source* but secrets are usually on the *target* -- that's *good* - # but also really annoying to build CI around when it needs secrets to work right.) - - id: plan - run: | - dist ${{ (!github.event.pull_request && format('host --steps=create --tag={0}', github.ref_name)) || 'plan' }} --output-format=json > plan-dist-manifest.json - echo "dist ran successfully" - cat plan-dist-manifest.json - echo "manifest=$(jq -c "." plan-dist-manifest.json)" >> "$GITHUB_OUTPUT" - - name: "Upload dist-manifest.json" - uses: actions/upload-artifact@v6 - with: - name: artifacts-plan-dist-manifest - path: plan-dist-manifest.json - - # Build and packages all the platform-specific things - build-local-artifacts: - name: build-local-artifacts (${{ join(matrix.targets, ', ') }}) - # Let the initial task tell us to not run (currently very blunt) - needs: - - plan - if: ${{ fromJson(needs.plan.outputs.val).ci.github.artifacts_matrix.include != null && (needs.plan.outputs.publishing == 'true' || fromJson(needs.plan.outputs.val).ci.github.pr_run_mode == 'upload') }} - strategy: - fail-fast: false - # Target platforms/runners are computed by dist in create-release. - # Each member of the matrix has the following arguments: - # - # - runner: the github runner - # - dist-args: cli flags to pass to dist - # - install-dist: expression to run to install dist on the runner - # - # Typically there will be: - # - 1 "global" task that builds universal installers - # - N "local" tasks that build each platform's binaries and platform-specific installers - matrix: ${{ fromJson(needs.plan.outputs.val).ci.github.artifacts_matrix }} - runs-on: ${{ matrix.runner }} - container: ${{ matrix.container && matrix.container.image || null }} - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - BUILD_MANIFEST_NAME: target/distrib/${{ join(matrix.targets, '-') }}-dist-manifest.json - permissions: - "attestations": "write" - "contents": "read" - "id-token": "write" - steps: - - name: enable windows longpaths - run: | - git config --global core.longpaths true - - uses: actions/checkout@v6 - with: - persist-credentials: false - submodules: recursive - - name: Install Rust non-interactively if not already installed - if: ${{ matrix.container }} - run: | - if ! command -v cargo > /dev/null 2>&1; then - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y - echo "$HOME/.cargo/bin" >> $GITHUB_PATH - fi - - name: Install dist - run: ${{ matrix.install_dist.run }} - # Get the dist-manifest - - name: Fetch local artifacts - uses: actions/download-artifact@v7 - with: - pattern: artifacts-* - path: target/distrib/ - merge-multiple: true - - name: Install dependencies - run: | - ${{ matrix.packages_install }} - - name: Build artifacts - run: | - # Actually do builds and make zips and whatnot - dist build ${{ needs.plan.outputs.tag-flag }} --print=linkage --output-format=json ${{ matrix.dist_args }} > dist-manifest.json - echo "dist ran successfully" - - name: Attest - uses: actions/attest-build-provenance@v3 - with: - subject-path: "target/distrib/*${{ join(matrix.targets, ', ') }}*" - - id: cargo-dist - name: Post-build - # We force bash here just because github makes it really hard to get values up - # to "real" actions without writing to env-vars, and writing to env-vars has - # inconsistent syntax between shell and powershell. - shell: bash - run: | - # Parse out what we just built and upload it to scratch storage - echo "paths<<EOF" >> "$GITHUB_OUTPUT" - dist print-upload-files-from-manifest --manifest dist-manifest.json >> "$GITHUB_OUTPUT" - echo "EOF" >> "$GITHUB_OUTPUT" - - cp dist-manifest.json "$BUILD_MANIFEST_NAME" - - name: "Upload artifacts" - uses: actions/upload-artifact@v6 - with: - name: artifacts-build-local-${{ join(matrix.targets, '_') }} - path: | - ${{ steps.cargo-dist.outputs.paths }} - ${{ env.BUILD_MANIFEST_NAME }} - - # Build and package all the platform-agnostic(ish) things - build-global-artifacts: - needs: - - plan - - build-local-artifacts - runs-on: "ubuntu-22.04" - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - BUILD_MANIFEST_NAME: target/distrib/global-dist-manifest.json - steps: - - uses: actions/checkout@v6 - with: - persist-credentials: false - submodules: recursive - - name: Install cached dist - uses: actions/download-artifact@v7 - with: - name: cargo-dist-cache - path: ~/.cargo/bin/ - - run: chmod +x ~/.cargo/bin/dist - # Get all the local artifacts for the global tasks to use (for e.g. checksums) - - name: Fetch local artifacts - uses: actions/download-artifact@v7 - with: - pattern: artifacts-* - path: target/distrib/ - merge-multiple: true - - id: cargo-dist - shell: bash - run: | - dist build ${{ needs.plan.outputs.tag-flag }} --output-format=json "--artifacts=global" > dist-manifest.json - echo "dist ran successfully" - - # Parse out what we just built and upload it to scratch storage - echo "paths<<EOF" >> "$GITHUB_OUTPUT" - jq --raw-output ".upload_files[]" dist-manifest.json >> "$GITHUB_OUTPUT" - echo "EOF" >> "$GITHUB_OUTPUT" - - cp dist-manifest.json "$BUILD_MANIFEST_NAME" - - name: "Upload artifacts" - uses: actions/upload-artifact@v6 - with: - name: artifacts-build-global - path: | - ${{ steps.cargo-dist.outputs.paths }} - ${{ env.BUILD_MANIFEST_NAME }} - # Determines if we should publish/announce - host: - needs: - - plan - - build-local-artifacts - - build-global-artifacts - # Only run if we're "publishing", and only if plan, local and global didn't fail (skipped is fine) - if: ${{ always() && needs.plan.result == 'success' && needs.plan.outputs.publishing == 'true' && (needs.build-global-artifacts.result == 'skipped' || needs.build-global-artifacts.result == 'success') && (needs.build-local-artifacts.result == 'skipped' || needs.build-local-artifacts.result == 'success') }} - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - runs-on: "ubuntu-22.04" - outputs: - val: ${{ steps.host.outputs.manifest }} - steps: - - uses: actions/checkout@v6 - with: - persist-credentials: false - submodules: recursive - - name: Install cached dist - uses: actions/download-artifact@v7 - with: - name: cargo-dist-cache - path: ~/.cargo/bin/ - - run: chmod +x ~/.cargo/bin/dist - # Fetch artifacts from scratch-storage - - name: Fetch artifacts - uses: actions/download-artifact@v7 - with: - pattern: artifacts-* - path: target/distrib/ - merge-multiple: true - - id: host - shell: bash - run: | - dist host ${{ needs.plan.outputs.tag-flag }} --steps=upload --steps=release --output-format=json > dist-manifest.json - echo "artifacts uploaded and released successfully" - cat dist-manifest.json - echo "manifest=$(jq -c "." dist-manifest.json)" >> "$GITHUB_OUTPUT" - - name: "Upload dist-manifest.json" - uses: actions/upload-artifact@v6 - with: - # Overwrite the previous copy - name: artifacts-dist-manifest - path: dist-manifest.json - # Create a GitHub Release while uploading all files to it - - name: "Download GitHub Artifacts" - uses: actions/download-artifact@v7 - with: - pattern: artifacts-* - path: artifacts - merge-multiple: true - - name: Cleanup - run: | - # Remove the granular manifests - rm -f artifacts/*-dist-manifest.json - - name: Create GitHub Release - env: - PRERELEASE_FLAG: "${{ fromJson(steps.host.outputs.manifest).announcement_is_prerelease && '--prerelease' || '' }}" - ANNOUNCEMENT_TITLE: "${{ fromJson(steps.host.outputs.manifest).announcement_title }}" - ANNOUNCEMENT_BODY: "${{ fromJson(steps.host.outputs.manifest).announcement_github_body }}" - RELEASE_COMMIT: "${{ github.sha }}" - run: | - # Write and read notes from a file to avoid quoting breaking things - echo "$ANNOUNCEMENT_BODY" > $RUNNER_TEMP/notes.txt - - gh release create "${{ needs.plan.outputs.tag }}" --target "$RELEASE_COMMIT" $PRERELEASE_FLAG --title "$ANNOUNCEMENT_TITLE" --notes-file "$RUNNER_TEMP/notes.txt" artifacts/* - - announce: - needs: - - plan - - host - # use "always() && ..." to allow us to wait for all publish jobs while - # still allowing individual publish jobs to skip themselves (for prereleases). - # "host" however must run to completion, no skipping allowed! - if: ${{ always() && needs.host.result == 'success' }} - runs-on: "ubuntu-22.04" - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - steps: - - uses: actions/checkout@v6 - with: - persist-credentials: false - submodules: recursive diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml deleted file mode 100644 index 96c8ebc7..00000000 --- a/.github/workflows/rust.yml +++ /dev/null @@ -1,230 +0,0 @@ -name: Rust - -on: - push: - branches: [main] - paths-ignore: - - "ui/**" - pull_request: - branches: [main] - paths-ignore: - - "ui/**" - -env: - CARGO_TERM_COLOR: always - -jobs: - build: - strategy: - matrix: - os: [depot-ubuntu-24.04, macos-14, windows-latest] - runs-on: ${{ matrix.os }} - - steps: - - uses: actions/checkout@v6 - - - name: Install rust - uses: dtolnay/rust-toolchain@master - with: - toolchain: 1.96.0 - - - uses: actions/cache@v5 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-cargo-release-${{ hashFiles('**/Cargo.lock') }} - - - name: Run cargo build common - run: cargo build -p atuin-common --locked --release - - - name: Run cargo build client - run: cargo build -p atuin-client --locked --release - - - name: Run cargo build server - run: cargo build -p atuin-server --locked --release - - - name: Run cargo build main - run: cargo build --all --locked --release - - cross-compile: - strategy: - matrix: - # There was an attempt to make cross-compiles also work on FreeBSD, but that failed with: - # - # warning: libelf.so.2, needed by <...>/libkvm.so, not found (try using -rpath or -rpath-link) - target: [x86_64-unknown-illumos] - runs-on: depot-ubuntu-24.04 - steps: - - uses: actions/checkout@v6 - - - name: Install cross - uses: taiki-e/install-action@v2 - with: - tool: cross - - - uses: actions/cache@v5 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ matrix.target }}-cross-compile-${{ hashFiles('**/Cargo.lock') }} - - - name: Run cross build common - run: cross build -p atuin-common --locked --target ${{ matrix.target }} - - - name: Run cross build client - run: cross build -p atuin-client --locked --target ${{ matrix.target }} - - - name: Run cross build server - run: cross build -p atuin-server --locked --target ${{ matrix.target }} - - - name: Run cross build main - run: | - cross build --all --locked --target ${{ matrix.target }} - - unit-test: - strategy: - matrix: - os: [depot-ubuntu-24.04, macos-14, windows-latest] - runs-on: ${{ matrix.os }} - - steps: - - uses: actions/checkout@v6 - - - name: Install rust - uses: dtolnay/rust-toolchain@master - with: - toolchain: 1.96.0 - - - uses: taiki-e/install-action@v2 - name: Install nextest - with: - tool: cargo-nextest - - - uses: actions/cache@v5 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-cargo-debug-${{ hashFiles('**/Cargo.lock') }} - - - name: Run cargo test - run: cargo nextest run --lib --bins - - check: - strategy: - matrix: - os: [depot-ubuntu-24.04, macos-14, windows-latest] - runs-on: ${{ matrix.os }} - - steps: - - uses: actions/checkout@v6 - - - name: Install rust - uses: dtolnay/rust-toolchain@master - with: - toolchain: 1.96.0 - - - uses: actions/cache@v5 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-cargo-debug-${{ hashFiles('**/Cargo.lock') }} - - - name: Run cargo check (all features) - run: cargo check --all-features --workspace - - - name: Run cargo check (no features) - run: cargo check --no-default-features --workspace - - - name: Run cargo check (sync) - run: cargo check --no-default-features --features sync --workspace - - - name: Run cargo check (server) - run: cargo check -p atuin-server - - - name: Run cargo check (client only) - run: cargo check --no-default-features --features client --workspace - - integration-test: - runs-on: depot-ubuntu-24.04 - - services: - postgres: - image: postgres - env: - POSTGRES_USER: atuin - POSTGRES_PASSWORD: pass - POSTGRES_DB: atuin - ports: - - 5432:5432 - - steps: - - uses: actions/checkout@v6 - - - name: Install rust - uses: dtolnay/rust-toolchain@master - with: - toolchain: 1.96.0 - - - uses: taiki-e/install-action@v2 - name: Install nextest - with: - tool: cargo-nextest - - - uses: actions/cache@v5 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-cargo-debug-${{ hashFiles('**/Cargo.lock') }} - - - name: Run cargo test - run: cargo nextest run --test '*' - env: - ATUIN_DB_URI: postgres://atuin:pass@localhost:5432/atuin - - clippy: - runs-on: depot-ubuntu-24.04 - - steps: - - uses: actions/checkout@v6 - - - name: Install latest rust - uses: dtolnay/rust-toolchain@master - with: - toolchain: 1.96.0 - components: clippy - - - uses: actions/cache@v5 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-cargo-debug-${{ hashFiles('**/Cargo.lock') }} - - - name: Run clippy - run: cargo clippy -- -D warnings -D clippy::redundant_clone - - format: - runs-on: depot-ubuntu-24.04 - - steps: - - uses: actions/checkout@v6 - - - name: Install latest rust - uses: dtolnay/rust-toolchain@master - with: - toolchain: 1.96.0 - components: rustfmt - - - name: Format - run: cargo fmt -- --check diff --git a/.github/workflows/shellcheck.yml b/.github/workflows/shellcheck.yml deleted file mode 100644 index e85381fd..00000000 --- a/.github/workflows/shellcheck.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: Shellcheck - -on: - push: - branches: [ main ] - pull_request: - branches: [ main ] - -jobs: - shellcheck: - runs-on: depot-ubuntu-24.04 - - steps: - - uses: actions/checkout@v6 - - name: Run shellcheck - uses: ludeeus/action-shellcheck@master - env: - SHELLCHECK_OPTS: "-e SC2148" diff --git a/.github/workflows/update-nix-deps.yml b/.github/workflows/update-nix-deps.yml deleted file mode 100644 index 2ed5ff78..00000000 --- a/.github/workflows/update-nix-deps.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: Update Nix Deps -on: - workflow_dispatch: # allows manual triggering - schedule: - - cron: '0 0 1 * *' # runs monthly on the first day of the month at 00:00 - -jobs: - lockfile: - runs-on: depot-ubuntu-24.04 - if: github.repository == 'atuinsh/atuin' - steps: - - name: Checkout repository - uses: actions/checkout@v6 - - name: Install Nix - uses: DeterminateSystems/nix-installer-action@main - - name: Update flake.lock - uses: DeterminateSystems/update-flake-lock@main - with: - pr-title: "chore(deps): update flake.lock" - pr-labels: | - dependencies diff --git a/.rustfmt.toml b/.rustfmt.toml index ec1e17ff..76387ac0 100644 --- a/.rustfmt.toml +++ b/.rustfmt.toml @@ -1,4 +1,4 @@ reorder_imports = true # uncomment once stable -#imports_granularity = "crate" -#group_imports = "StdExternalCrate" +imports_granularity = "crate" +group_imports = "StdExternalCrate" diff --git a/AGENTS.md b/AGENTS.md deleted file mode 100644 index 4aba8ed2..00000000 --- a/AGENTS.md +++ /dev/null @@ -1,71 +0,0 @@ -# Atuin - -Shell history tool. Replaces your shell's built-in history with a SQLite database, adds context (cwd, exit code, duration, hostname), and optionally syncs across machines with end-to-end encryption. - -## Workspace crates - -``` -atuin CLI binary + TUI (clap, ratatui, crossterm) -atuin-client Client library: local DB, encryption, sync, settings -atuin-common Shared types, API models, utils -atuin-daemon Background gRPC daemon (tonic) for shell hooks -atuin-dotfiles Alias/var sync via record store -atuin-history Sorting algorithms, stats -atuin-kv Key-value store (synced) -atuin-scripts Script management (minijinja) -atuin-server HTTP sync server (axum) - lib + standalone binary -atuin-server-database Database trait for server -atuin-server-postgres Postgres implementation (sqlx) -atuin-server-sqlite SQLite implementation (sqlx) -``` - -## Two sync protocols - -- **V1 (legacy)**: Syncs history entries directly. Being phased out. Toggleable via `sync_v1_enabled`. -- **V2 (current)**: Record store abstraction. All data types (history, KV, aliases, vars, scripts) share the same sync infrastructure using tagged records. Envelope-encrypted with PASETO V4 and per-record CEKs. - -## Encryption - -- **V1**: XSalsa20Poly1305 (secretbox). Key at `~/.local/share/atuin/key`. -- **V2**: PASETO V4 Local (XChaCha20-Poly1305 + Blake2b). Envelope encryption: each record gets a random CEK wrapped with the master key. Record metadata (id, idx, version, tag, host) is authenticated as implicit assertions. - -## Databases - -- **Client**: SQLite everywhere. Separate DBs for history, record store, KV, scripts. All use sqlx + WAL mode. -- **Server**: Postgres (primary) or SQLite. Auto-detected from URI prefix. -- Migrations live alongside each crate. Never modify existing migrations, only add new ones. - -## Hot paths - -`history start`, `history end`, and `init` skip database initialization for latency. Don't add DB calls to these without good reason. - -## Conventions - -- Rust 2024 edition, toolchain 1.93.1. -- Errors: `eyre::Result` in binaries, `thiserror` for typed errors in libraries. -- Async: tokio. Client uses `current_thread`; server uses `multi_thread`. -- `#![deny(unsafe_code)]` on client/common, `#![forbid(unsafe_code)]` on server. -- Clippy: `pedantic` + `nursery` on main crate. CI enforces `-D warnings -D clippy::redundant_clone`. -- Format: `cargo fmt`. Only non-default: `reorder_imports = true`. -- IDs: UUIDv7 (time-ordered), newtype wrappers (`HistoryId`, `RecordId`, `HostId`). -- Serialization: MessagePack for encrypted payloads, JSON for API, TOML for config. -- Storage traits: `Database` (client), `Store` (record store), `Database` (server) -- all `async_trait`. -- History builders: `HistoryImported`, `HistoryCaptured`, `HistoryFromDb` with compile-time field validation. -- Feature flags: `client`, `sync`, `daemon`, `clipboard`, `check-update`. - -## Testing - -- Unit tests inline with `#[cfg(test)]`, async via `#[tokio::test]`. -- Integration tests in `crates/atuin/tests/` need Postgres (`ATUIN_DB_URI` env var). -- Use `":memory:"` SQLite for unit tests needing a database. -- Runner: `cargo nextest`. -- Benchmarks: `divan` in `atuin-history`. - -## Build and check - -```sh -cargo build -cargo test -cargo clippy -- -D warnings -cargo fmt --check -``` diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 37e40ffe..00000000 --- a/Dockerfile +++ /dev/null @@ -1,36 +0,0 @@ -FROM lukemathwalker/cargo-chef:latest-rust-1.96.0-slim-bookworm AS chef -WORKDIR app - -FROM chef AS planner -COPY . . -RUN cargo chef prepare --recipe-path recipe.json - -FROM chef AS builder - -# Ensure working C compile setup (not installed by default in arm64 images) -RUN apt update && apt install build-essential -y - -COPY --from=planner /app/recipe.json recipe.json -RUN cargo chef cook --release --recipe-path recipe.json - -COPY . . -RUN cargo build --release --bin atuin-server - -FROM debian:bookworm-20260518-slim AS runtime -LABEL org.opencontainers.image.source="https://github.com/atuinsh/atuin" \ - org.opencontainers.image.url="https://atuin.sh" \ - org.opencontainers.image.licenses="MIT" - -RUN useradd -c 'atuin user' atuin && mkdir /config && chown atuin:atuin /config -# Install ca-certificates for webhooks to work -RUN apt update && apt install ca-certificates -y && rm -rf /var/lib/apt/lists/* -WORKDIR app - -USER atuin - -ENV TZ=Etc/UTC -ENV RUST_LOG=atuin_server=info -ENV ATUIN_CONFIG_DIR=/config - -COPY --from=builder /app/target/release/atuin-server /usr/local/bin -ENTRYPOINT ["/usr/local/bin/atuin-server"] diff --git a/VOUCHED.td b/VOUCHED.td deleted file mode 100644 index 031e7ccf..00000000 --- a/VOUCHED.td +++ /dev/null @@ -1,278 +0,0 @@ -+ 0x4A6F -+ 13werwolf13 -+ abatkin -+ Absolucy -+ Adda0 -+ Aehmlo -+ ajjahn -+ akinomyoga -+ akirk -+ alerque -+ alexandregv -+ Aloxaf -+ amosbird -+ andrewaylett -+ ap-1 -+ arcuru -+ ardrigh -+ aschey -+ ataraxia937 -+ AtomicRobotMan0101 -+ avinassh -+ azzamsa -+ b3nj5m1n -+ bahdotsh -+ baprx -+ bdavj -+ benwr -+ BinaryMuse -+ bjschafer -+ bradrf -+ braelyn-ai -+ briankung -+ bvergnaud -+ c-14 -+ c-git -+ caio96 -+ candrewlee14 -+ Carthaca -+ chitao1234 -+ clouserw -+ conradludgate -+ cosgroveb -+ CosmicHorrorDev -+ cultpony -+ cyqsimon -+ dacog -+ DanielAtCosmicDNA -+ DaniPopes -+ david-crespo -+ davidolrik -+ davlgd -+ dcarosone -+ deicon -+ dennis-tra -+ dependabot[bot] -+ dhth -+ digital-cuttlefish -+ dongxuwang -+ dotfrag -+ dotsam -+ drbrain -+ drmorr0 -+ ds-cbo -+ eatradish -+ eclairevoyant -+ edeustua -+ edwardloveall -+ ekroon -+ ellie -+ elsbrock -+ ElvishJerricco -+ enchantednatures -+ eopb -+ EricCrosson -+ eripa -+ etbyrd -+ eth3lbert -+ evanpurkhiser -+ felixonmars -+ filviu -+ fragmede -+ frankh -+ frukto -+ fzakaria -+ github-actions[bot] -+ hack3ric -+ happenslol -+ haristhohir -+ helbing -+ herbygillot -+ hesampakdaman -+ hezhizhen -+ hhamud -+ hlxid -+ hunger -+ iamkroot -+ IanManske -+ ibayramli -+ ijanos -+ iloveitaly -+ InCogNiTo124 -+ Indy2222 -+ injust -+ IoSonoPiero -+ ismith -+ ivan-toriya -+ ivvvve -+ jamesbrooks -+ jamestrew -+ janlarres -+ jaxvanyang -+ jbaiter -+ jean-santos -+ jeremycline -+ jfmontanaro -+ jhult -+ jingmian -+ jinnatar -+ jinnko -+ jirutka -+ JoaquinTrinanes -+ jonaylor89 -+ Jongy -+ Josef-Friedrich -+ josegonzalez -+ JRGould -+ julienp -+ jyn514 -+ karlding -+ keithamus -+ kejadlen -+ keysmashes -+ kianmeng -+ kjetijor -+ KorvinSzanto -+ kosak -+ laurentlbm -+ lazzurs -+ lchausmann -+ LecrisUT -+ LeoniePhiline -+ liljaylj -+ lilydjwg -+ lmBored -+ lmburns -+ ltrzesniewski -+ lucacome -+ lugoues -+ lukebaker -+ lukekarrys -+ m42e -+ macno -+ majiayu000 -+ manelvf -+ marius -+ mateuscomh -+ mattgodbolt -+ matthewberryman -+ matthiasbeyer -+ Matthieu-LAURENT39 -+ maxim-uvarov -+ mb6ockatf -+ Mellbourn -+ mentalisttraceur -+ merc1031 -+ michaelmior -+ millette -+ morguldir -+ mozzieongit -+ mrcjkb -+ mrjones2014 -+ mrkbac -+ mundry -+ musicinmybrain -+ mwotton -+ mwpastore -+ nc7s -+ nebkor -+ nekowinston -+ Nelyah -+ Nemo157 -+ NeoPhi -+ networkException -+ nh2 -+ notjedi -+ notrudyyy -+ notsatyarth -+ noyez -+ offbyone -+ onedr0p -+ OnePieceJoker -+ onkelT2 -+ orhun -+ overhacked -+ oxo42 -+ pamburus -+ panekj -+ papertigers -+ paulbarton90 -+ pdecat -+ pevogam -+ philn -+ philtweir -+ phinze -+ piec -+ pmarschik -+ pmodin -+ poliorcetics -+ popsu -+ postmath -+ printfn -+ r-vdp -+ rektide -+ remmycat -+ Reverier-Xu -+ RichardDRJ -+ rightaditya -+ rigrig -+ Rohan5commit -+ rriski -+ rufo -+ s0 -+ s1ck -+ sashkab -+ SAY-5 -+ schrej -+ Sciencentistguy -+ sdr135284 -+ senekor -+ sftblw -+ shgew -+ shreve -+ shymega -+ simon-b -+ skx -+ slamp -+ snaggen -+ sophiajt -+ sowbug -+ Sped0n -+ sporeventexplosion -+ starsep -+ stevenxxiu -+ stuartcarnie -+ sunshowers -+ SuperSandro2000 -+ svenstaro -+ szinn -+ takac -+ tessus -+ thedrow -+ thePanz -+ tobiasge -+ tombh -+ tpoliaw -+ tranzystorekk -+ trygveaa -+ Tyarel8 -+ TymanWasTaken -+ UbiquitousPhoton -+ utterstep -+ VuiMuich -+ Vynce -+ waldyrious -+ WindSoilder -+ wpbrz -+ wzzrd -+ xav-ie -+ xfzv -+ xqm32 -+ xvello -+ yan -+ yannickulrich -+ yarikoptic -+ yolo2h -+ YummyOreo -+ yuvipanda -+ zygous diff --git a/atuin.plugin.zsh b/atuin.plugin.zsh deleted file mode 100644 index 9ad5284f..00000000 --- a/atuin.plugin.zsh +++ /dev/null @@ -1,6 +0,0 @@ -# shellcheck disable=2148,SC2168,SC1090,SC2125 -local FOUND_ATUIN=$+commands[atuin] - -if [[ $FOUND_ATUIN -eq 1 ]]; then - source <(atuin init zsh) -fi diff --git a/contrib/pi/atuin.ts b/contrib/pi/atuin.ts deleted file mode 120000 index d5e7a533..00000000 --- a/contrib/pi/atuin.ts +++ /dev/null @@ -1 +0,0 @@ -../../crates/atuin/contrib/pi/atuin.ts
\ No newline at end of file diff --git a/demo.gif b/demo.gif Binary files differdeleted file mode 100644 index 6eac1abf..00000000 --- a/demo.gif +++ /dev/null diff --git a/depot.json b/depot.json deleted file mode 100644 index e51895a6..00000000 --- a/depot.json +++ /dev/null @@ -1 +0,0 @@ -{"id":"v6vqpk6559"} diff --git a/dist-workspace.toml b/dist-workspace.toml deleted file mode 100644 index bd4a56cb..00000000 --- a/dist-workspace.toml +++ /dev/null @@ -1,29 +0,0 @@ -[workspace] -members = ["cargo:."] - -# Config for 'dist' -[dist] -# Path that installers should place binaries in -install-path = "~/.atuin/bin" -# The preferred dist version to use in CI (Cargo.toml SemVer syntax) -cargo-dist-version = "0.31.0" -# CI backends to support -ci = "github" -# The installers to generate for each app -installers = ["shell", "powershell"] -# Target platforms to build apps for (Rust target-triple syntax) -targets = ["aarch64-apple-darwin", "aarch64-unknown-linux-gnu", "aarch64-unknown-linux-musl", "x86_64-unknown-linux-gnu", "x86_64-unknown-linux-musl", "x86_64-pc-windows-msvc"] -# Which actions to run on pull requests -pr-run-mode = "plan" -# Whether to install an updater program -install-updater = true -# The archive format to use for non-windows builds (defaults .tar.xz) -unix-archive = ".tar.gz" -# Whether to enable GitHub Attestations -github-attestations = true - -[dist.github-custom-runners] -aarch64-unknown-linux-gnu = "depot-ubuntu-24.04-arm-8" -aarch64-unknown-linux-musl = "depot-ubuntu-24.04-arm-8" -x86_64-unknown-linux-gnu = "depot-ubuntu-24.04-8" -x86_64-unknown-linux-musl = "depot-ubuntu-24.04-8" diff --git a/docs-i18n/.gitignore b/docs-i18n/.gitignore deleted file mode 100644 index b2d6de30..00000000 --- a/docs-i18n/.gitignore +++ /dev/null @@ -1,20 +0,0 @@ -# Dependencies -/node_modules - -# Production -/build - -# Generated files -.docusaurus -.cache-loader - -# Misc -.DS_Store -.env.local -.env.development.local -.env.test.local -.env.production.local - -npm-debug.log* -yarn-debug.log* -yarn-error.log* diff --git a/docs-i18n/ru/config_ru.md b/docs-i18n/ru/config_ru.md deleted file mode 100644 index b1e64218..00000000 --- a/docs-i18n/ru/config_ru.md +++ /dev/null @@ -1,146 +0,0 @@ -# Конфигурация - -Autin использует два файла конфигурации. Они хранятся в `~/.config/atuin/`. Данные -хранятся в `~/.local/share/atuin` (если не определено другое в XDG\_\*). - -Путь до катклога конфигурации может быть изменён установкой -параметра `ATUIN_CONFIG_DIR`. Например - -``` -export ATUIN_CONFIG_DIR = /home/ellie/.atuin -``` - -## Пользовательская конфигурация - -``` -~/.config/atuin/config.toml -``` - -Этот файл используется когда клиент работает на локальной машине (не сервере). - -See [config.toml](../../atuin-client/config.toml) for an example - -### `dialect` - -Этот параметр контролирует как [stats](stats.md) команда обрабатывает данные. -Может принимать одно из двух допустимых значений: - -``` -dialect = "uk" -``` - -или - -``` -dialect = "us" -``` - -По умолчанию - "us". - -### `auto_sync` - -Синхронизироваться ли автоматически если выполнен вход. По умолчанию - да (true) -``` -auto_sync = true/false -``` - -### `sync_address` - -Адрес сервера для синхронизации. По умолчанию `https://api.atuin.sh`. - -``` -sync_address = "https://api.atuin.sh" -``` - -### `sync_frequency` - -Как часто клиент синхронизируется с сервером. Может быть указано в -понятном для человека формате. Например, `10s`, `20m`, `1h`, и т.д. -По умолчанию `1h` - -Если стоит значение 0, Autin будет синхронизироваться после каждой выполненной команды. -Помните, что сервера могут иметь ограничение на количество отправленных запросов. - -``` -sync_frequency = "1h" -``` - -### `db_path` - -Путь до базы данных SQlite. По умолчанию это -`~/.local/share/atuin/history.db`. - -``` -db_path = "~/.history.db" -``` - -### `key_path` - -Путь до ключа шифрования Autin. По умолчанию, -`~/.local/share/atuin/key`. - -``` -key = "~/.atuin-key" -``` - -### `session_path` - -Путь до серверного файла сессии Autin. По умолчанию, -`~/.local/share/atuin/session`. На самом деле это просто API токен. - -``` -key = "~/.atuin-session" -``` - -### `search_mode` - -Определяет, какой режим поиска будет использоваться. Autin поддерживает "prefix", -текст целиком (fulltext) и неточный ("fuzzy") поиск. Режим "prefix" производит -поиск по "запрос\*", "fulltext" по "\*запрос\*", и "fuzzy" использует -[вот такой](#fuzzy-search-syntax) синтаксис. - -По умолчанию стоит значение "fuzzy" - -### `filter_mode` - -Фильтр, по-умолчанию использующийся для поиска - -| Столбец 1 | Столбец 2 | -|------------------|----------------------------------------------------------| -| global (default) | Искать историю команд со всех хостов, сессий и каталогов | -| host | Искать историю команд с этого хоста | -| session | Искать историю команд этой сессии | -| directory | Искать историю команд, выполненных в текущей папке | - -Режимы поиска могут быть изменены через ctrl-r - - -``` -search_mode = "fulltext" -``` - -#### fuzzy search syntax - -Режим поиска "fuzzy" основан на -[fzf search syntax](https://github.com/junegunn/fzf#search-syntax). - -| Токен | Тип совпадений | Описание | -|-----------|----------------------------|-------------------------------------| -| `sbtrkt` | fuzzy-match | Всё, что совпадает с `sbtrkt` | -| `'wild` | exact-match (В кавычках) | Всё, что включает в себя `wild` | -| `^music` | prefix-exact-match | Всё, что начинается с `music` | -| `.mp3$` | suffix-exact-match | Всё, что заканчивается на `.mp3` | -| `!fire` | inverse-exact-match | Всё, что не включает в себя `fire` | -| `!^music` | inverse-prefix-exact-match | Всё, что не начинается с `music` | -| `!.mp3$` | inverse-suffix-exact-match | Всё, что не заканчивается на `.mp3` | - -Знак вертикальной черты означает логическое ИЛИ. Например, запрос ниже вернет -всё, что начинается с `core` и заканчивается либо на `go`, либо на `rb`, либо на `py`. - -``` -^core go$ | rb$ | py$ -``` - -## Серверная конфигурация - -`// TODO` diff --git a/docs-i18n/ru/import_ru.md b/docs-i18n/ru/import_ru.md deleted file mode 100644 index 993d89b8..00000000 --- a/docs-i18n/ru/import_ru.md +++ /dev/null @@ -1,27 +0,0 @@ -# `atuin import` - -Autin может импортировать историю из "старого" файла истории - -`atuin import auto` предпринимает попытку определить тип командного интерфейса -(через \$SHELL) и запускает нужный скрипт импорта. - -К сожалению, эти файлы содержат не так много информации, как Autin, так что не -все функции будут доступны с импортированными данными. - -# zsh - -``` -atuin import zsh -``` - -Если у вас есть HISTFILE, то эта команда должна сработать. Иначе, попробуйте - -``` -HISTFILE=/path/to/history/file atuin import zsh -``` - -Этот параметр поддерживает как и упрощённый, так и полный формат. - -# bash - -TODO diff --git a/docs-i18n/ru/key-binding_ru.md b/docs-i18n/ru/key-binding_ru.md deleted file mode 100644 index d6917e4e..00000000 --- a/docs-i18n/ru/key-binding_ru.md +++ /dev/null @@ -1,39 +0,0 @@ -# Key binding - -По умолчанию, Autin будет переназначать <kbd>Ctrl-r</kbd> и клавишу 'стрелка вверх'. -Если вы не хотите этого, установите параметр ATUIN_NOBIND прежде чем вызывать `atuin init` - -Например, - -``` -export ATUIN_NOBIND="true" -eval "$(atuin init zsh)" -``` - -Таким образом вы можете разрешить переназначение клавиш Autin, если это необходимо. -Делайте это до инициализирующего вызова. - -# zsh - -Autin устанавливает виджет ZLE "atuin-search" - -``` -export ATUIN_NOBIND="true" -eval "$(atuin init zsh)" - -bindkey '^r' atuin-search - -# зависит от режима терминала -bindkey '^[[A' atuin-search -bindkey '^[OA' atuin-search -``` - -# bash - -``` -export ATUIN_NOBIND="true" -eval "$(atuin init bash)" - -# Переопределите ctrl-r, и любые другие сочетания горячих клавиш тут -bind -x '"\C-r": __atuin_history' -``` diff --git a/docs-i18n/ru/list_ru.md b/docs-i18n/ru/list_ru.md deleted file mode 100644 index e40d3045..00000000 --- a/docs-i18n/ru/list_ru.md +++ /dev/null @@ -1,11 +0,0 @@ -# Вывад истории на экран - -``` -atuin history list -``` - -| Аргумент | Описание | -| -------------- | ------------------------------------------------------------------------------ | -| `--cwd/-c` | Каталог, историю команд которой необходимо вывести (по умолчанию все каталоги) | -| `--session/-s` | Выводит историю команд только текущей сессии (по умолчанию false) | -| `--human` | Читаемый формат для времени и периодов времени (по умолчанию false) | diff --git a/docs-i18n/ru/search_ru.md b/docs-i18n/ru/search_ru.md deleted file mode 100644 index 8302decc..00000000 --- a/docs-i18n/ru/search_ru.md +++ /dev/null @@ -1,38 +0,0 @@ -# `atuin search` - -``` -atuin search <query> -``` - -Поиск в Atuin также поддерживает wildcards со знаками `*` или `%`. -По умолчанию, должен быть указан префикс (т.е. все запросы автоматически дополняются wildcard -ами) - -| Аргумент | Описание | -| ------------------ | ------------------------------------------------------------------------------------------- | -| `--cwd/-c` | Каталог, для которого отображается история (по умолчанию, все каталоги)) | -| `--exclude-cwd` | Исключить команды которые запускались в этом каталоге (по умолчанию none) | -| `--exit/-e` | Фильтровать по exit code (по умолчанию none) | -| `--exclude-exit` | Исключить команды, которые завершились с указанным значением (по умолчанию none) | -| `--before` | Включить только команды, которые были запущены до указанного времени (по умолчанию none) | -| `--after` | Включить только команды, которые были запущены после указанного времени (по умолчанию none) | -| `--interactive/-i` | Открыть интерактивный поисковой графический интерфейс (по умолчанию false) | -| `--human` | Использовать читаемое формавтирование для времени и периодов времени (по умолчанию false) | - -## Примеры - -``` -# Начать интерактивный поиск с текстовым пользовательским интерфейсом -atuin search -i - -# Начать интерактивный поиск с текстовым пользовательским интерфейсом и уже введённым запросом -atuin search -i atuin - -# Искать по всем командам, начиная с cargo, которые успешно завершились -atuin search --exit 0 cargo - -# Искать по всем командам которые завершились ошибками и были вызваны в текущей папке и были запущены до первого апреля 2021 -atuin search --exclude-exit 0 --before 01/04/2021 --cwd . - -# Искать по всем командам, начиная с cargo, которые успешно завершились и были запущены после трёх часо дня вчера -atuin search --exit 0 --after "yesterday 3pm" cargo -``` diff --git a/docs-i18n/ru/server_ru.md b/docs-i18n/ru/server_ru.md deleted file mode 100644 index 25b45abf..00000000 --- a/docs-i18n/ru/server_ru.md +++ /dev/null @@ -1,160 +0,0 @@ -# `atuin server` - -Autin позволяет запустить свой собственный сервер синхронизации, если вы -не хотите использовать мой :) - -Здесь есть только одна субкоманда, `atuin server start`, которая запустит -Autin http-сервер синхронизации - -``` -USAGE: - atuin server start [OPTIONS] - -FLAGS: - --help Prints help information - -V, --version Prints version information - -OPTIONS: - -h, --host <host> - -p, --port <port> -``` - -## config - -Серверная конфигурация лежит отдельно от файла пользовательсокй, даже если -это один и тот же бинарный файл. Серверная конфигурация лежит в `~/.config/atuin/server.toml`. - -Этот файл выглядит как-то так: - -```toml -host = "0.0.0.0" -port = 8888 -open_registration = true -db_uri="postgres://user:password@hostname/database" -``` - -Конфигурация так же может находииться в переменных окружения. - -```sh -ATUIN_HOST="0.0.0.0" -ATUIN_PORT=8888 -ATUIN_OPEN_REGISTRATION=true -ATUIN_DB_URI="postgres://user:password@hostname/database" -``` - -### host - -Адрес хоста, который будет прослушиваться сервером Autin - -По умолчанию это `127.0.0.1`. - -### post - -POST, который будет прослушиваться сервером Autin. - -По умолчанию это `8888`. - -### open_registration - -Если `true`, autin будет разрешать регистрацию новых пользователей. -Установите флаг `false`, если после создания вашего аккаута вы не хотите, чтобы другие -могли пользоваться вашим сервером. - -По умолчанию `false`. - -### db_uri - -Действующий URI postgres, где будет сохранён аккаунт пользователя и история. - -## Docker - -Поддерживается образ Docker чтобы сделать проще развертывание сервера в контейнере. - -```sh -docker run -d -v "$USER/.config/atuin:/config" ghcr.io/ellie/atuin:latest server start -``` - -## Docker Compose - -Использование вашего собственного docker-образа с хостингом вашего собственного Autin может быть реализовано через -файл docker-compose. - -Создайте файл `.env` рядом с `docker-compode.yml` с содержанием наподобие этому: - -``` -ATUIN_DB_USERNAME=atuin -# Choose your own secure password -ATUIN_DB_PASSWORD=really-insecure -``` - -Создайте `docker-compose.yml`: - -```yaml -version: '3.5' -services: - atuin: - restart: always - image: ghcr.io/ellie/atuin:main - command: server start - volumes: - - "./config:/config" - links: - - postgresql:db - ports: - - 8888:8888 - environment: - ATUIN_HOST: "0.0.0.0" - ATUIN_OPEN_REGISTRATION: "true" - ATUIN_DB_URI: postgres://$ATUIN_DB_USERNAME:$ATUIN_DB_PASSWORD@db/atuin - postgresql: - image: postgres:14 - restart: unless-stopped - volumes: # Don't remove permanent storage for index database files! - - "./database:/var/lib/postgresql/data/" - environment: - POSTGRES_USER: $ATUIN_DB_USERNAME - POSTGRES_PASSWORD: $ATUIN_DB_PASSWORD - POSTGRES_DB: atuin -``` - -Запустите службы с помощью `docker-compose`: - -```sh -docker-compose up -d -``` - -### Использование systemd для управления сервером Autin - -`systemd` юнит чтобы управлять службами, контролируемыми `docker-compose`: - -``` -[Unit] -Description=Docker Compose Atuin Service -Requires=docker.service -After=docker.service - -[Service] -# Where the docker-compose file is located -WorkingDirectory=/srv/atuin-server -ExecStart=/usr/bin/docker-compose up -ExecStop=/usr/bin/docker-compose down -TimeoutStartSec=0 -Restart=on-failure -StartLimitBurst=3 - -[Install] -WantedBy=multi-user.target -``` - -Включите и запустите службу командой: - -```sh -systemctl enable --now atuin -``` - -Проверьте, работает ли: - -```sh -systemctl status atuin -``` - diff --git a/docs-i18n/ru/shell-completions_ru.md b/docs-i18n/ru/shell-completions_ru.md deleted file mode 100644 index 56fb1602..00000000 --- a/docs-i18n/ru/shell-completions_ru.md +++ /dev/null @@ -1,20 +0,0 @@ -# `atuin gen-completions` - -[Shell completions](https://en.wikipedia.org/wiki/Command-line_completion) для Atuin -могут бять сгенерированы путём указания каталога для вывода и желаемого shell через субкомманду `gen-completions`. - -``` -$ atuin gen-completions --shell bash --out-dir $HOME - -Shell completion for BASH is generated in "/home/user" -``` - -Возможные команды для аргумента `--shell`могут быть следующими: - -- `bash` -- `fish` -- `zsh` -- `powershell` -- `elvish` - -Также рекомендуем прочитать [supported shells](./../../README.md#supported-shells). diff --git a/docs-i18n/ru/stats_ru.md b/docs-i18n/ru/stats_ru.md deleted file mode 100644 index 842ad71b..00000000 --- a/docs-i18n/ru/stats_ru.md +++ /dev/null @@ -1,40 +0,0 @@ -# `atuin stats` - -Atuin также может выводить статистику, основанную на истории. Пока что в очень простом виде, -но скоро должно появиться больше возможностей. - -Статистика выводится пока только на английском -Statistics in english only -# TODO - -``` -$ atuin stats day last friday - -+---------------------+------------+ -| Statistic | Value | -+---------------------+------------+ -| Most used command | git status | -+---------------------+------------+ -| Commands ran | 450 | -+---------------------+------------+ -| Unique commands ran | 213 | -+---------------------+------------+ - -$ atuin stats day 01/01/21 # also accepts absolute dates -``` - -Также, может быть выведена статистика всей известной Autin истории: - -``` -$ atuin stats all - -+---------------------+-------+ -| Statistic | Value | -+---------------------+-------+ -| Most used command | ls | -+---------------------+-------+ -| Commands ran | 8190 | -+---------------------+-------+ -| Unique commands ran | 2996 | -+---------------------+-------+ -``` diff --git a/docs-i18n/ru/sync_ru.md b/docs-i18n/ru/sync_ru.md deleted file mode 100644 index 08831cbd..00000000 --- a/docs-i18n/ru/sync_ru.md +++ /dev/null @@ -1,60 +0,0 @@ -# `atuin sync` - -Autin может сделать резервную копию вашей истории на сервер чтобы обеспечить использование -разными компьютерами одной и той же истории. Вся история будет зашифрована двусторонним шифрованием, -так что сервер _никогда_ не получит ваши данные! - -Можно сделать свой сервер (запустив `atuin server start`, об этом написано в других -файлах документациии), но у меня есть свой https://api.atuin.sh. Это серверный адрес по умолчанию, -который может быть изменён в [конфигурации](config_ru.md). Опять же, я _не_ могу получить ваши данные -и они мне не нужны. - -## Частота синхронизации - -Синхронизация будет происходить автоматически, если обратное не было указано в конфигурации. -Отконфигурировать сей параметр можно в [config](config_ru.md) - -## Синхронизация - -Синхронизироваться также можно вручную, используя команду `atuin sync` - -## Регистрация - -Можно зарегистрировать аккаунт для синхронизации: - -``` -atuin register -u <USERNAME> -e <EMAIL> -p <PASSWORD> -``` - -Имена пользователей должны быть уникальны, и электронная почта должна использваться -только для срочных уведомлений (изменения политик, нарушения безопасности и т.д.) - -Псоле регистрации, вы уже сразу вошли в свой аккаунт :) С этого момента синхронизация -будет проходить автоматически - -## Ключ - -Поскольку все данные шифруются, Autin при работе сгенерирует ваш ключ. Он будет сохранён в -каталоге с данными Autin (`~/.local/share/atuin` на системах с GNU/Linux) - -Также можно сделать это самим: - -``` -atuin key -``` - -Никогда не передавайте никому этот ключ! - -## Вход - -Если вы хотите войти с другого компьютера, вам потребуется ключ безопасности (`atuin key`). - -``` -atuin login -u <USERNAME> -p <PASSWORD> -k <KEY> -``` - -## Выход - -``` -atuin logout -``` diff --git a/docs-i18n/zh-CN/README.md b/docs-i18n/zh-CN/README.md deleted file mode 100644 index 065d1b4d..00000000 --- a/docs-i18n/zh-CN/README.md +++ /dev/null @@ -1,234 +0,0 @@ -<p align="center"> - <picture> - <source media="(prefers-color-scheme: dark)" srcset="https://github.com/atuinsh/atuin/assets/53315310/13216a1d-1ac0-4c99-b0eb-d88290fe0efd"> - <img alt="Text changing depending on mode. Light: 'So light!' Dark: 'So dark!'" src="https://github.com/atuinsh/atuin/assets/53315310/08bc86d4-a781-4aaa-8d7e-478ae6bcd129"> -</picture> -</p> - -<p align="center"> -<em>神奇的 shell 历史记录</em> -</p> - -<hr/> - -<p align="center"> - <a href="https://github.com/atuinsh/atuin/actions?query=workflow%3ARust"><img src="https://img.shields.io/github/actions/workflow/status/atuinsh/atuin/rust.yml?style=flat-square" /></a> - <a href="https://crates.io/crates/atuin"><img src="https://img.shields.io/crates/v/atuin.svg?style=flat-square" /></a> - <a href="https://crates.io/crates/atuin"><img src="https://img.shields.io/crates/d/atuin.svg?style=flat-square" /></a> - <a href="https://github.com/atuinsh/atuin/blob/main/LICENSE"><img src="https://img.shields.io/crates/l/atuin.svg?style=flat-square" /></a> - <a href="https://discord.gg/Fq8bJSKPHh"><img src="https://img.shields.io/discord/954121165239115808" /></a> - <a rel="me" href="https://hachyderm.io/@atuin"><img src="https://img.shields.io/mastodon/follow/109944632283122560?domain=https%3A%2F%2Fhachyderm.io&style=social"/></a> - <a href="https://twitter.com/atuinsh"><img src="https://img.shields.io/twitter/follow/atuinsh?style=social" /></a> -</p> - - -[English] | [简体中文] - -Atuin 使用 SQLite 数据库取代了你现有的 shell 历史,并为你的命令记录了额外的内容。此外,它还通过 Atuin 服务器,在机器之间提供可选的、完全加密的历史记录同步功能。 - -<p align="center"> - <img src="../../demo.gif" alt="animated" width="80%" /> -</p> - -<p align="center"> -<em>显示退出代码、命令持续时间、上次执行时间和执行的命令</em> -</p> - -除了搜索 UI,它还可以执行以下操作: - -``` -# 搜索昨天下午3点之后记录的所有成功的 `make` 命令 -atuin search --exit 0 --after "yesterday 3pm" make -``` - -你可以使用我(ellie)托管的服务器,也可以使用你自己的服务器!或者干脆不使用 sync 功能。所有的历史记录同步都是加密,即使我想,也无法访问你的数据。且我**真的**不想。 - -## 功能 - -- 重新绑定 `up` 和 `ctrl-r` 的全屏历史记录搜索UI界面 -- 使用 sqlite 数据库存储 shell 历史记录 -- 备份以及同步已加密的 shell 历史记录 -- 在不同的终端、不同的会话以及不同的机器上都有相同的历史记录 -- 记录退出代码、cwd、主机名、会话、命令持续时间,等等。 -- 计算统计数据,如 "最常用的命令"。 -- 不替换旧的历史文件 -- 通过 <kbd>Alt-\<num\></kbd> 快捷键快速跳转到之前的记录 -- 通过 ctrl-r 切换过滤模式;可以仅从当前会话、目录或全局来搜索历史记录 - -## 文档 - -- [快速开始](#快速开始) -- [安装](#安装) -- [导入](./import.md) -- [配置](./config.md) -- [历史记录搜索](./search.md) -- [历史记录云端同步](./sync.md) -- [历史记录统计](./stats.md) -- [运行你自己的服务器](./server.md) -- [键绑定](./key-binding.md) -- [shell 补全](./shell-completions.md) - -## 支持的 Shells - -- zsh -- bash -- fish - -## 社区 - -Atuin 有一个 Discord 社区, 可以在 [这里](https://discord.gg/Fq8bJSKPHh) 获得 - -# 快速开始 - -## 使用默认的同步服务器 - -这将为您注册由我托管的默认同步服务器。 一切都是端到端加密的,所以你的秘密是安全的! - -阅读下面的更多信息,了解仅供离线使用或托管您自己的服务器。 - -``` -bash <(curl https://raw.githubusercontent.com/ellie/atuin/main/install.sh) - -atuin register -u <USERNAME> -e <EMAIL> -p <PASSWORD> -atuin import auto -atuin sync -``` - -### 使用活跃图 - -除了托管 Atuin 服务器外,还有一个服务可以用来生成你的 shell 历史记录使用活跃图!这个功能的灵感来自于 GitHub 的使用活跃图。 - -例如,这是我的: - - - -如果你也想要,请在登陆你的同步服务器后,执行 - -``` -curl https://api.atuin.sh/enable -d $(cat ~/.local/share/atuin/session) -``` - -执行结果为你的活跃图 URL 地址。可以共享或嵌入这个 URL 地址,令牌(token)并<i>不是</i>加密的,只是用来防止被枚举攻击。 - -## 仅离线 (不同步) - -``` -bash <(curl https://raw.githubusercontent.com/ellie/atuin/main/install.sh) - -atuin import auto -``` - -## 安装 - -### 脚本 (推荐) - -安装脚本将帮助您完成设置,确保您的 shell 正确配置。 它还将使用以下方法之一,在可能的情况下首选系统包管理器(pacman、homebrew 等)。 - -``` -# 不要以root身份运行,如果需要的话,会要求root。 -bash <(curl https://raw.githubusercontent.com/ellie/atuin/main/install.sh) -``` - -然后可直接看 <a href="#shell-plugin">Shell 插件</a> - -### 通过 cargo - -最好使用 [rustup](https://rustup.rs/) 来设置 Rust 工具链,然后你就可以运行下面的命令: - -``` -cargo install atuin -``` - -然后可直接看 <a href="#shell-plugin">Shell 插件</a> - -### Homebrew - -``` -brew install atuin -``` - -然后可直接看 <a href="#shell-plugin">Shell 插件</a> - -### MacPorts - -Atuin 也可以在 [MacPorts](https://ports.macports.org/port/atuin/) 中找到 - -``` -sudo port install atuin -``` - -然后可直接看 <a href="#shell-plugin">Shell 插件</a> - -### Pacman - -Atuin 在 Arch Linux 的 [社区存储库](https://archlinux.org/packages/community/x86_64/atuin/) 中可用。 - -``` -pacman -S atuin -``` - -然后可直接看 <a href="#shell-plugin">Shell 插件</a> - -### 从源码编译安装 - -``` -git clone https://github.com/ellie/atuin.git -cd atuin/crates/atuin -cargo install --path . -``` - -然后可直接看 <a href="#shell-plugin">Shell 插件</a> - -## <a id="shell-plugin">Shell 插件</a> - -安装二进制文件后,需要安装 shell 插件。 如果你使用的是脚本安装,那么这一切应该都会帮您完成! - -### zsh - -``` -echo 'eval "$(atuin init zsh)"' >> ~/.zshrc -``` - -或使用插件管理器: - -``` -zinit load ellie/atuin -``` - -### bash - -我们需要设置一些钩子(hooks), 所以首先需要安装 bash-preexec : - -``` -curl https://raw.githubusercontent.com/rcaloras/bash-preexec/master/bash-preexec.sh -o ~/.bash-preexec.sh -echo '[[ -f ~/.bash-preexec.sh ]] && source ~/.bash-preexec.sh' >> ~/.bashrc -``` - -然后设置 Atuin - -``` -echo 'eval "$(atuin init bash)"' >> ~/.bashrc -``` - -### fish - -添加 - -``` -atuin init fish | source -``` - -到 `~/.config/fish/config.fish` 文件中的 `is-interactive` 块中 - -### Fig - -通过 [Fig](https://fig.io) 可为 zsh, bash 或 fish 一键安装 `atuin` 脚本插件。 - -<a href="https://fig.io/plugins/other/atuin" target="_blank"><img src="https://fig.io/badges/install-with-fig.svg" /></a> - -## ...这个名字是什么意思? - -Atuin 以 "The Great A'Tuin" 命名, 这是一只来自 Terry Pratchett 的 Discworld 系列书籍的巨龟。 - -[English]: ../../README.md -[简体中文]: ./README.md diff --git a/docs-i18n/zh-CN/config.md b/docs-i18n/zh-CN/config.md deleted file mode 100644 index 3aa63a9e..00000000 --- a/docs-i18n/zh-CN/config.md +++ /dev/null @@ -1,137 +0,0 @@ -# 配置 - -Atuin 维护两个配置文件,存储在 `~/.config/atuin/` 中。 我们将数据存储在 `~/.local/share/atuin` 中(除非被 XDG\_\* 覆盖)。 - -您可以通过设置更改配置目录的路径 `ATUIN_CONFIG_DIR`。 例如 - -``` -export ATUIN_CONFIG_DIR = /home/ellie/.atuin -``` - -## 客户端配置 - -``` -~/.config/atuin/config.toml -``` - -客户端运行在用户的机器上,除非你运行的是服务器,否则这就是你所关心的。 - -见 [config.toml](../../atuin-client/config.toml) 中的例子 - -### `dialect` - -这配置了 [stats](stats.md) 命令解析日期的方式。 它有两个可能的值 - -``` -dialect = "uk" -``` - -或者 - -``` -dialect = "us" -``` - -默认为 "us". - -### `auto_sync` - -配置登录时是否自动同步。默认为 true - -``` -auto_sync = true/false -``` - -### `sync_address` - -同步的服务器地址! 默认为 `https://api.atuin.sh` - -``` -sync_address = "https://api.atuin.sh" -``` - -### `sync_frequency` - -多长时间与服务器自动同步一次。这可以用一种"人类可读"的格式给出。例如,`10s`,`20m`,`1h`,等等。默认为 `1h` 。 - -如果设置为 `0`,Atuin将在每个命令之后进行同步。一些服务器可能有潜在的速率限制,这不会造成任何问题。 - -``` -sync_frequency = "1h" -``` - -### `db_path` - -Atuin SQlite数据库的路径。默认为 -`~/.local/share/atuin/history.db` - -``` -db_path = "~/.history.db" -``` - -### `key_path` - -Atuin加密密钥的路径。默认为 -`~/.local/share/atuin/key` - -``` -key = "~/.atuin-key" -``` - -### `session_path` - -Atuin服务器会话文件的路径。默认为 -`~/.local/share/atuin/session` 。 这本质上只是一个API令牌 - -``` -key = "~/.atuin-session" -``` - -### `search_mode` - -使用哪种搜索模式。Atuin 支持 "prefix"(前缀)、"fulltext"(全文) 和 "fuzzy"(模糊)搜索模式。前缀(prefix)搜索语法为 "query\*",全文(fulltext)搜索语法为 "\*query\*",而模糊搜索适用的搜索语法 [如下所述](#fuzzy-search-syntax) 。 - -默认配置为 "fuzzy" - -### `filter_mode` - -搜索时要使用的默认过滤器 - -| 模式 | 描述 | -|--------------- | --------------- | -| global (default) | 从所有主机、所有会话、所有目录中搜索历史记录 | -| host | 仅从该主机搜索历史记录 | -| session | 仅从当前会话中搜索历史记录 | -| directory | 仅从当前目录搜索历史记录| - -过滤模式仍然可以通过 ctrl-r 来切换 - - -``` -search_mode = "fulltext" -``` - -#### `fuzzy` 的搜索语法 - -`fuzzy` 搜索语法的基础是 [fzf 搜索语法](https://github.com/junegunn/fzf#search-syntax) 。 - -| 内容 | 匹配类型 | 描述 | -| --------- | -------------------------- | ------------------------------------ | -| `sbtrkt` | fuzzy-match | 匹配 `sbtrkt` 的项目 | -| `'wild` | exact-match (quoted) | 包含 `wild` 的项目 | -| `^music` | prefix-exact-match | 以 `music` 开头的项目 | -| `.mp3$` | suffix-exact-match | 以 `.mp3` 结尾的项目 | -| `!fire` | inverse-exact-match | 不包括 `fire` 的项目 | -| `!^music` | inverse-prefix-exact-match | 不以 `music` 开头的项目 | -| `!.mp3$` | inverse-suffix-exact-match | 不以 `.mp3` 结尾的项目 | - - -单个条形字符术语充当 OR 运算符。 例如,以下查询匹配以 `core` 开头并以 `go`、`rb` 或 `py` 结尾的条目。 - -``` -^core go$ | rb$ | py$ -``` - -## 服务端配置 - -`// TODO` diff --git a/docs-i18n/zh-CN/docker.md b/docs-i18n/zh-CN/docker.md deleted file mode 100644 index 64704679..00000000 --- a/docs-i18n/zh-CN/docker.md +++ /dev/null @@ -1,90 +0,0 @@ -# Docker - -Atuin 提供了一个 docker 镜像(image),可以更轻松地将服务器部署为容器(container)。 - -```sh -docker run -d -v "$USER/.config/atuin:/config" ghcr.io/ellie/atuin:latest server start -``` - -# Docker Compose - -使用已有的 docker 镜像(image)来托管你自己的 Atuin,可以使用提供的 docker-compose 文件来完成 - -在 docker-compose.yml 同级目录下创建一个 .env 文件,内容如下: - -``` -ATUIN_DB_USERNAME=atuin -# 填写你的密码 -ATUIN_DB_PASSWORD=really-insecure -``` - -创建 `docker-compose.yml` 文件: - -```yaml -version: '3.5' -services: - atuin: - restart: always - image: ghcr.io/ellie/atuin:main - command: server start - volumes: - - "./config:/config" - links: - - postgresql:db - ports: - - 8888:8888 - environment: - ATUIN_HOST: "0.0.0.0" - ATUIN_OPEN_REGISTRATION: "true" - ATUIN_DB_URI: postgres://$ATUIN_DB_USERNAME:$ATUIN_DB_PASSWORD@db/atuin - postgresql: - image: postgres:14 - restart: unless-stopped - volumes: # 不要删除索引数据库文件的永久存储空间! - - "./database:/var/lib/postgresql/data/" - environment: - POSTGRES_USER: $ATUIN_DB_USERNAME - POSTGRES_PASSWORD: $ATUIN_DB_PASSWORD - POSTGRES_DB: atuin -``` - -使用 `docker-compose` 启动服务: - -```sh -docker-compose up -d -``` - -## 使用 systemd 管理你的 atuin 服务器 - -以下 `systemd` 的配置文件用来管理你的 `docker-compose` 托管服务: - -``` -[Unit] -Description=Docker Compose Atuin Service -Requires=docker.service -After=docker.service - -[Service] -# Where the docker-compose file is located -WorkingDirectory=/srv/atuin-server -ExecStart=/usr/bin/docker-compose up -ExecStop=/usr/bin/docker-compose down -TimeoutStartSec=0 -Restart=on-failure -StartLimitBurst=3 - -[Install] -WantedBy=multi-user.target -``` - -启用服务: - -```sh -systemctl enable --now atuin -``` - -检查服务是否正常运行: - -```sh -systemctl status atuin -``` diff --git a/docs-i18n/zh-CN/import.md b/docs-i18n/zh-CN/import.md deleted file mode 100644 index c1f1d06d..00000000 --- a/docs-i18n/zh-CN/import.md +++ /dev/null @@ -1,25 +0,0 @@ -# `atuin import` - -Atuin 可以从您的“旧”历史文件中导入您的历史记录 - -`atuin import auto` 将尝试找出你的 shell(通过 \$SHELL)并运行正确的导入器 - -不幸的是,这些旧文件没有像 Atuin 那样存储尽可能多的信息,因此并非所有功能都可用于导入的数据。 - -# zsh - -``` -atuin import zsh -``` - -如果你设置了 HISTFILE,这应该会被选中!如果没有,可以尝试以下操作 - -``` -HISTFILE=/path/to/history/file atuin import zsh -``` - -这支持简单和扩展形式 - -# bash - -TODO diff --git a/docs-i18n/zh-CN/k8s.md b/docs-i18n/zh-CN/k8s.md deleted file mode 100644 index ce63aab1..00000000 --- a/docs-i18n/zh-CN/k8s.md +++ /dev/null @@ -1,195 +0,0 @@ -# Kubernetes - -你可以使用 Kubernetes 来托管你的 Atuin 服务器。 - -为数据库凭证创建 [`secrets.yaml`](../../k8s/secrets.yaml) 文件: - -```yaml -apiVersion: v1 -kind: Secret -metadata: - name: atuin-secrets -type: Opaque -stringData: - ATUIN_DB_USERNAME: atuin - ATUIN_DB_PASSWORD: seriously-insecure - ATUIN_HOST: "127.0.0.1" - ATUIN_PORT: "8888" - ATUIN_OPEN_REGISTRATION: "true" - ATUIN_DB_URI: "postgres://atuin:seriously-insecure@localhost/atuin" -immutable: true -``` - -为 Atuin 服务器创建 [`atuin.yaml`](../../k8s/atuin.yaml) 文件: - - -```yaml ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: atuin -spec: - replicas: 1 - selector: - matchLabels: - io.kompose.service: atuin - template: - metadata: - labels: - io.kompose.service: atuin - spec: - containers: - - args: - - server - - start - env: - - name: ATUIN_DB_URI - valueFrom: - secretKeyRef: - name: atuin-secrets - key: ATUIN_DB_URI - optional: false - - name: ATUIN_HOST - value: 0.0.0.0 - - name: ATUIN_PORT - value: "8888" - - name: ATUIN_OPEN_REGISTRATION - value: "true" - image: ghcr.io/atuinsh/atuin:latest - name: atuin - ports: - - containerPort: 8888 - resources: - limits: - cpu: 250m - memory: 1Gi - requests: - cpu: 250m - memory: 1Gi - volumeMounts: - - mountPath: /config - name: atuin-claim0 - - name: postgresql - image: postgres:14 - ports: - - containerPort: 5432 - env: - - name: POSTGRES_DB - value: atuin - - name: POSTGRES_PASSWORD - valueFrom: - secretKeyRef: - name: atuin-secrets - key: ATUIN_DB_PASSWORD - optional: false - - name: POSTGRES_USER - valueFrom: - secretKeyRef: - name: atuin-secrets - key: ATUIN_DB_USERNAME - optional: false - resources: - limits: - cpu: 250m - memory: 1Gi - requests: - cpu: 250m - memory: 1Gi - volumeMounts: - - mountPath: /var/lib/postgresql/data/ - name: database - volumes: - - name: database - persistentVolumeClaim: - claimName: database - - name: atuin-claim0 - persistentVolumeClaim: - claimName: atuin-claim0 ---- -apiVersion: v1 -kind: Service -metadata: - labels: - io.kompose.service: atuin - name: atuin -spec: - type: NodePort - ports: - - name: "8888" - port: 8888 - nodePort: 30530 - selector: - io.kompose.service: atuin ---- -kind: PersistentVolume -apiVersion: v1 -metadata: - name: database-pv - labels: - app: database - type: local -spec: - storageClassName: manual - capacity: - storage: 300Mi - accessModes: - - ReadWriteOnce - hostPath: - path: "/Users/firstname.lastname/.kube/database" ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - labels: - io.kompose.service: database - name: database -spec: - storageClassName: manual - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 300Mi ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - labels: - io.kompose.service: atuin-claim0 - name: atuin-claim0 -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 10Mi -``` - -最后,你可能想让 atuin 使用单独的命名空间(namespace),创建 [`namespace.yaml`](../../k8s/namespaces.yaml) 文件: - -```yaml -apiVersion: v1 -kind: Namespace -metadata: - name: atuin-namespace - labels: - name: atuin -``` - -在企业级安装部署时,你可能想要数据库内容永久存储在集群中,而不是在主机系统中。在上述配置中,`storageClassName` 配置为 `manual`,主机系统的挂载目录配置为 `/Users/firstname.lastname/.kube/database`,请注意,这些配置将会使得数据库内容存储在 kubernetes 集群<i>外部</i>中。 - -你还应该将 `secrets.yaml` 文件中的 `ATUIN_DB_PASSWORD` 和 `ATUIN_DB_URI` 修改为更安全的加密字符串。 - -Atuin 运行在主机系统的 `30530` 端口上。这是通过 `nodePort` 属性进行陪你的。Kubernetes 有一个严格规则,即不允许暴露小于 30000 的端口号。为了使客户端能够正常工作,你需要在你的 `config.toml` 文件中设置端口号,例如 `sync_address = "http://192.168.1.10:30530"`。 - -使用 `kubectl` 部署 Atuin 服务器: - -```shell - kubectl apply -f ./namespaces.yaml - kubectl apply -n atuin-namespace \ - -f ./secrets.yaml \ - -f ./atuin.yaml -``` - -上面示例同时也位于 atuin 仓库(repository)的 [k8s](../../k8s) 目录下。 diff --git a/docs-i18n/zh-CN/key-binding.md b/docs-i18n/zh-CN/key-binding.md deleted file mode 100644 index 54c68b37..00000000 --- a/docs-i18n/zh-CN/key-binding.md +++ /dev/null @@ -1,48 +0,0 @@ -# 键位绑定 - -默认情况下, Atuin 将会重新绑定 <kbd>Ctrl-r</kbd> 和 `up` 键。如果你不想使用默认绑定,请在调用 `atuin init` 之前设置 ATUIN_NOBIND - -例如: - -``` -export ATUIN_NOBIND="true" -eval "$(atuin init zsh)" -``` - -如果需要,你可以在调用 `atuin init` 之后对 Atuin 重新进行键绑定 - -# zsh - -Atuin 定义了 ZLE 部件 "atuin-search" - -``` -export ATUIN_NOBIND="true" -eval "$(atuin init zsh)" - -bindkey '^r' atuin-search - -# 取决于终端模式 -bindkey '^[[A' atuin-search -bindkey '^[OA' atuin-search -``` - -# bash - -``` -export ATUIN_NOBIND="true" -eval "$(atuin init bash)" - -# 绑定到 ctrl-r, 也可以在这里添加任何其他你想要的绑定方式 -bind -x '"\C-r": __atuin_history' -``` - -# fish - -``` -set -gx ATUIN_NOBIND "true" -atuin init fish | source - -# 在 normal 和 insert 模式下绑定到 ctrl-r,你也可以在此处添加其他键位绑定 -bind \cr _atuin_search -bind -M insert \cr _atuin_search -``` diff --git a/docs-i18n/zh-CN/list.md b/docs-i18n/zh-CN/list.md deleted file mode 100644 index fe03529f..00000000 --- a/docs-i18n/zh-CN/list.md +++ /dev/null @@ -1,11 +0,0 @@ -# 历史记录列表 - -``` -atuin history list -``` - -| 参数 | 描述 | -| -------------- | ----------------------------------------------------- | -| `--cwd/-c` | 要列出历史记录的目录(默认:所有目录) | -| `--session/-s` | 只对当前会话启用列表历史(默认:false) | -| `--human` | 对时间戳和持续时间使用人类可读的格式(默认:false)。 | diff --git a/docs-i18n/zh-CN/search.md b/docs-i18n/zh-CN/search.md deleted file mode 100644 index 24e320d5..00000000 --- a/docs-i18n/zh-CN/search.md +++ /dev/null @@ -1,37 +0,0 @@ -# `atuin search` - -``` -atuin search <query> -``` - -Atuin 搜索还支持带有 `*` 或 `%` 字符的通配符。 默认情况下,会执行前缀搜索(即,所有查询都会自动附加通配符)。 - -| 参数 | 描述 | -| ------------------ | ----------------------------------------------------- | -| `--cwd/-c` | 列出历史记录的目录(默认:所有目录) | -| `--exclude-cwd` | 不包括在此目录中运行的命令(默认值:none) | -| `--exit/-e` | 按退出代码过滤(默认:none) | -| `--exclude-exit` | 不包括以该值退出的命令(默认值:none) | -| `--before` | 仅包括在此时间之前运行的命令(默认值:none) | -| `--after` | 仅包含在此时间之后运行的命令(默认值:none) | -| `--interactive/-i` | 打开交互式搜索 UI(默认值:false) | -| `--human` | 对时间戳和持续时间使用人类可读的格式(默认值:false) | - -## 举例 - -``` -# 打开交互式搜索 TUI -atuin search -i - -# 打开预装了查询的交互式搜索 TUI -atuin search -i atuin - -# 搜索所有以 cargo 开头且成功退出的命令。 -atuin search --exit 0 cargo - -# 从当前目录中搜索所有在2021年4月1日之前运行且失败的命令。 -atuin search --exclude-exit 0 --before 01/04/2021 --cwd . - -# 搜索所有以 cargo 开头,成功退出且是在昨天下午3点之后运行的命令。 -atuin search --exit 0 --after "yesterday 3pm" cargo -``` diff --git a/docs-i18n/zh-CN/server.md b/docs-i18n/zh-CN/server.md deleted file mode 100644 index 4cb39df9..00000000 --- a/docs-i18n/zh-CN/server.md +++ /dev/null @@ -1,75 +0,0 @@ -# `atuin server` - -Atuin 允许您运行自己的同步服务器,以防您不想使用我(ellie)托管的服务器 :) - -目前只有一个子命令,`atuin server start`,它将启动 Atuin http 同步服务器。 - -``` -USAGE: - atuin server start [OPTIONS] - -FLAGS: - --help Prints help information - -V, --version Prints version information - -OPTIONS: - -h, --host <host> - -p, --port <port> -``` - -## 配置 - -服务器的配置与客户端的配置是分开的,即使它们是相同的二进制文件。服务器配置可以在 `~/.config/atuin/server.toml` 找到。 - -它看起来像这样: - -```toml -host = "0.0.0.0" -port = 8888 -open_registration = true -db_uri="postgres://user:password@hostname/database" -``` - -另外,配置也可以用环境变量来提供。 - -```sh -ATUIN_HOST="0.0.0.0" -ATUIN_PORT=8888 -ATUIN_OPEN_REGISTRATION=true -ATUIN_DB_URI="postgres://user:password@hostname/database" -``` - -### host - -Atuin 服务器应该监听的地址 - -默认为 `127.0.0.1`. - -### port - -Atuin 服务器应该监听的端口 - -默认为 `8888`. - -### open_registration - -如果为 `true` ,atuin 将接受新用户注册。如果您不希望其他人能够使用您的服务器,请在创建自己的账号后将此设置为 `false` - -默认为 `false`. - -### db_uri - -一个有效的 postgres URI, 用户和历史记录数据将被保存到其中。 - -### path - -path 指的是给 server 添加的路由前缀。值为空字符串将不会添加路由前缀。 - -默认为 `""` - -## 容器部署说明 - -你可以在容器中部署自己的 atuin 服务器: - -* 有关 docker 配置的示例,请参考 [docker](docker.md)。 -* 有关 kubernetes 配置的示例,请参考 [k8s](k8s.md)。 diff --git a/docs-i18n/zh-CN/shell-completions.md b/docs-i18n/zh-CN/shell-completions.md deleted file mode 100644 index 0979dcb0..00000000 --- a/docs-i18n/zh-CN/shell-completions.md +++ /dev/null @@ -1,19 +0,0 @@ -# `atuin gen-completions` - -Atuin 的 [Shell 补全](https://en.wikipedia.org/wiki/Command-line_completion) 可以通过 `gen-completions` 子命令指定输出目录和所需的 shell 来生成。 - -``` -$ atuin gen-completions --shell bash --out-dir $HOME - -Shell completion for BASH is generated in "/home/user" -``` - -`--shell` 参数的可能值如下: - -- `bash` -- `fish` -- `zsh` -- `powershell` -- `elvish` - -此外, 请参阅 [支持的 Shells](./README.md#支持的-Shells). diff --git a/docs-i18n/zh-CN/stats.md b/docs-i18n/zh-CN/stats.md deleted file mode 100644 index 2bf557ba..00000000 --- a/docs-i18n/zh-CN/stats.md +++ /dev/null @@ -1,35 +0,0 @@ -# `atuin stats` - -Atuin 还可以根据你的历史记录进行计算统计数据 - 目前这只是一个小的基本功能,但更多功能即将推出 - -``` -$ atuin stats day last friday - -+---------------------+------------+ -| Statistic | Value | -+---------------------+------------+ -| Most used command | git status | -+---------------------+------------+ -| Commands ran | 450 | -+---------------------+------------+ -| Unique commands ran | 213 | -+---------------------+------------+ - -$ atuin stats day 01/01/21 # 也接受绝对日期 -``` - -它还可以计算所有已知历史记录的统计数据。 - -``` -$ atuin stats all - -+---------------------+-------+ -| Statistic | Value | -+---------------------+-------+ -| Most used command | ls | -+---------------------+-------+ -| Commands ran | 8190 | -+---------------------+-------+ -| Unique commands ran | 2996 | -+---------------------+-------+ -``` diff --git a/docs-i18n/zh-CN/sync.md b/docs-i18n/zh-CN/sync.md deleted file mode 100644 index 2fd451d8..00000000 --- a/docs-i18n/zh-CN/sync.md +++ /dev/null @@ -1,51 +0,0 @@ -# `atuin sync` - -Atuin 可以将您的历史记录备份到服务器,并使用它来确保多台机器具有相同的 shell 历史记录。 这都是端到端加密的,因此服务器操作员_永远_看不到您的数据! - -任何人都可以托管一个服务器(尝试 `atuin server start`,更多文档将在后面介绍),但我(ellie)在 https://api.atuin.sh 上托管了一个。这是默认的服务器地址,可以在 [配置](config.md) 中更改。 同样,我_不能_看到您的数据,也不想。 - -## 同步频率 - -除非另有配置,否则同步将自动执行。同步的频率可在 [配置](config.md) 中配置。 - -## 同步 - -你可以通过 `atuin sync` 来手动触发同步 - -## 注册 - -注册一个同步账号 - -``` -atuin register -u <USERNAME> -e <EMAIL> -p <PASSWORD> -``` - -用户名(USERNAME)必须是唯一的,电子邮件(EMAIL)仅用于重要通知(安全漏洞、服务更改等) - -注册后,意味着你也已经登录了 :) 同步应该从这里自动发生! - -## 密钥 - -由于你的数据是加密的, Atuin 将为你生成一个密钥。它被存储在 Atuin 的数据目录里( Linux 上为 `~/.local/share/atuin`) - -你也可以通过以下方式获得它 - -``` -atuin key -``` - -千万不要跟任何人分享这个! - -## 登录 - -如果你想登录到一个新的机器上,你需要你的加密密钥(`atuin key`)。 - -``` -atuin login -u <USERNAME> -p <PASSWORD> -k <KEY> -``` - -## 登出 - -``` -atuin logout -``` diff --git a/fossier.toml b/fossier.toml deleted file mode 100644 index 45ad0bcd..00000000 --- a/fossier.toml +++ /dev/null @@ -1,17 +0,0 @@ -[repo] -owner = "atuinsh" -name = "atuin" - -[thresholds] -allow_score = 70.0 -deny_score = 40.0 -min_confidence = 0.5 - -[actions.deny] -close_pr = true -comment = true -label = "fossier:spam-likely" - -[actions.review] -comment = true -label = "fossier:needs-review" diff --git a/install.sh b/install.sh deleted file mode 100755 index bd82d6da..00000000 --- a/install.sh +++ /dev/null @@ -1,197 +0,0 @@ -#! /bin/sh -set -eu - -ATUIN_NON_INTERACTIVE="no" - -for arg in "$@"; do - case "$arg" in - --non-interactive) ATUIN_NON_INTERACTIVE="yes" ;; - *) ;; - esac -done - -if [ "$ATUIN_NON_INTERACTIVE" != "yes" ]; then - if [ -t 0 ] || { true </dev/tty; } 2>/dev/null; then - ATUIN_NON_INTERACTIVE="no" - else - ATUIN_NON_INTERACTIVE="yes" - fi -fi - -cat << EOF - _______ _______ __ __ ___ __ _ -| _ || || | | || | | | | | -| |_| ||_ _|| | | || | | |_| | -| | | | | |_| || | | | -| | | | | || | | _ | -| _ | | | | || | | | | | -|__| |__| |___| |_______||___| |_| |__| - -Magical shell history - -Atuin setup -https://github.com/atuinsh/atuin -https://forum.atuin.sh - -Please file an issue or reach out on the forum if you encounter any problems! - -=============================================================================== - -EOF - -__atuin_install_binary(){ - curl --proto '=https' --tlsv1.2 -LsSf https://github.com/atuinsh/atuin/releases/latest/download/atuin-installer.sh | sh -} - -if ! command -v curl > /dev/null; then - echo "curl not installed. Please install curl." - exit -fi - - -__atuin_install_binary - -# TODO: Check which shell is in use -# Use of single quotes around $() is intentional here -# shellcheck disable=SC2016 -if ! grep -q "atuin init zsh" "${ZDOTDIR:-$HOME}/.zshrc"; then - printf '\neval "$(atuin init zsh)"\n' >> "${ZDOTDIR:-$HOME}/.zshrc" -fi - -# Use of single quotes around $() is intentional here -# shellcheck disable=SC2016 - -if ! grep -q "atuin init bash" ~/.bashrc; then - curl --proto '=https' --tlsv1.2 -LsSf https://raw.githubusercontent.com/rcaloras/bash-preexec/master/bash-preexec.sh -o ~/.bash-preexec.sh - printf '\n[[ -f ~/.bash-preexec.sh ]] && source ~/.bash-preexec.sh\n' >> ~/.bashrc - echo 'eval "$(atuin init bash)"' >> ~/.bashrc -fi - -if [ -f "$HOME/.config/fish/config.fish" ]; then - if ! grep -q "atuin init fish" "$HOME/.config/fish/config.fish"; then - printf '\nif status is-interactive\n atuin init fish | source\nend\n' >> "$HOME/.config/fish/config.fish" - fi -fi - -ATUIN_BIN="$HOME/.atuin/bin/atuin" - -__atuin_install_agent_hook(){ - agent="$1" - agent_name="$2" - agent_config_dir="$3" - shift 3 - - detected="no" - - if [ -d "$agent_config_dir" ]; then - detected="yes" - else - for agent_command in "$@"; do - if command -v "$agent_command" > /dev/null 2>&1; then - detected="yes" - break - fi - done - fi - - if [ "$detected" = "yes" ]; then - echo "Detected $agent_name — installing Atuin hooks..." - if ! "$ATUIN_BIN" hook install "$agent"; then - echo "Failed to install Atuin hooks for $agent_name (this version of Atuin may not support it yet)." - fi - echo "" - fi -} - -__atuin_install_agent_hook "claude-code" "Claude Code" "$HOME/.claude" claude -__atuin_install_agent_hook "codex" "Codex" "$HOME/.codex" codex -__atuin_install_agent_hook "pi" "pi" "$HOME/.config/pi" pi - -echo "" -echo "Atuin installed successfully!" -echo "" - -if [ "$ATUIN_NON_INTERACTIVE" != "yes" ]; then - - printf "Would you like to import your existing shell history into Atuin? [Y/n] " - read -r import_answer </dev/tty || import_answer="n" - import_answer="${import_answer:-y}" - - case "$import_answer" in - [yY]*) - echo "" - if ! "$ATUIN_BIN" import auto; then - echo "" - echo "History import failed. You can retry later with 'atuin import auto'." - fi - echo "" - ;; - *) - echo "Skipping history import. You can always run 'atuin import auto' later." - echo "" - ;; - esac - - cat << EOF -Sync your history across all your machines with Atuin Cloud: - - - End-to-end encrypted — only you can read your data - - Access your history from any device - - Never lose your history, even if you wipe a machine - -EOF - - printf "Sign up for a sync account? [Y/n] " - read -r sync_answer </dev/tty || sync_answer="n" - sync_answer="${sync_answer:-y}" - - case "$sync_answer" in - [yY]*) - echo "" - if ! "$ATUIN_BIN" register </dev/tty; then - echo "" - echo "Registration did not complete. You can run 'atuin register' any time to try again." - fi - ;; - *) - echo "" - printf "Already have an account? Log in with 'atuin login'.\n" - echo "You can also run 'atuin register' any time to create one." - ;; - esac - -else - echo "Non-interactive environment detected — skipping setup prompts." - echo "You can run the following commands manually after installation:" - echo "" - echo " atuin import auto Import your existing shell history" - echo " atuin register Sign up for a sync account" - echo " atuin login Log in to an existing sync account" -fi - -if [ "$ATUIN_NON_INTERACTIVE" != "yes" ]; then - "$ATUIN_BIN" setup </dev/tty -fi - -cat << EOF - - _______ __ __ _______ __ _ ___ _ __ __ _______ __ __ -| || | | || _ || | | || | | | | | | || || | | | -|_ _|| |_| || |_| || |_| || |_| | | |_| || _ || | | | - | | | || || || _| | || | | || |_| | - | | | || || _ || |_ |_ _|| |_| || | - | | | _ || _ || | | || _ | | | | || | - |___| |__| |__||__| |__||_| |__||___| |_| |___| |_______||_______| - -Thanks for installing Atuin! I really hope you like it. - -If you have any issues, please open an issue on GitHub or visit our forum (https://forum.atuin.sh)! - -If you love Atuin, please give us a star on GitHub! It really helps ⭐️ https://github.com/atuinsh/atuin - -=============================================================================== - - ⚠️ Please restart your shell or open a new terminal for Atuin to take effect! - -=============================================================================== -EOF diff --git a/k8s/atuin.yaml b/k8s/atuin.yaml deleted file mode 100644 index e537e0ac..00000000 --- a/k8s/atuin.yaml +++ /dev/null @@ -1,156 +0,0 @@ ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: atuin -spec: - replicas: 1 - selector: - matchLabels: - io.kompose.service: atuin - template: - metadata: - labels: - io.kompose.service: atuin - spec: - containers: - - args: - - start - env: - - name: ATUIN_DB_URI - valueFrom: - secretKeyRef: - name: atuin-secrets - key: ATUIN_DB_URI - optional: false - - name: ATUIN_HOST - value: 0.0.0.0 - - name: ATUIN_PORT - value: "8888" - - name: ATUIN_OPEN_REGISTRATION - value: "true" - image: ghcr.io/atuinsh/atuin:latest - name: atuin - ports: - - containerPort: &port 8888 - resources: - limits: - cpu: 250m - memory: 1Gi - requests: - cpu: 250m - memory: 1Gi - startupProbe: - httpGet: - path: /healthz - port: *port - failureThreshold: 30 - periodSeconds: 10 - livenessProbe: - httpGet: - path: /healthz - port: *port - initialDelaySeconds: 3 - periodSeconds: 3 - readinessProbe: - tcpSocket: - port: *port - initialDelaySeconds: 15 - periodSeconds: 10 - volumeMounts: - - mountPath: /config - name: atuin-claim0 - - name: postgresql - image: postgres:14 - ports: - - containerPort: 5432 - env: - - name: POSTGRES_DB - value: atuin - - name: POSTGRES_PASSWORD - valueFrom: - secretKeyRef: - name: atuin-secrets - key: ATUIN_DB_PASSWORD - optional: false - - name: POSTGRES_USER - valueFrom: - secretKeyRef: - name: atuin-secrets - key: ATUIN_DB_USERNAME - optional: false - resources: - limits: - cpu: 250m - memory: 1Gi - requests: - cpu: 250m - memory: 1Gi - volumeMounts: - - mountPath: /var/lib/postgresql/data/ - name: database - volumes: - - name: database - persistentVolumeClaim: - claimName: database - - name: atuin-claim0 - persistentVolumeClaim: - claimName: atuin-claim0 ---- -apiVersion: v1 -kind: Service -metadata: - labels: - io.kompose.service: atuin - name: atuin -spec: - type: NodePort - ports: - - name: "8888" - port: 8888 - nodePort: 31929 - selector: - io.kompose.service: atuin ---- -kind: PersistentVolume -apiVersion: v1 -metadata: - name: database-pv - labels: - app: database - type: local -spec: - storageClassName: manual - capacity: - storage: 300Mi - accessModes: - - ReadWriteOnce - hostPath: - path: "/Users/firstname.lastname/.kube/database" ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - labels: - io.kompose.service: database - name: database -spec: - storageClassName: manual - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 300Mi ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - labels: - io.kompose.service: atuin-claim0 - name: atuin-claim0 -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 10Mi diff --git a/k8s/namespaces.yaml b/k8s/namespaces.yaml deleted file mode 100644 index 20a401f6..00000000 --- a/k8s/namespaces.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - name: atuin-namespace - labels: - name: atuin diff --git a/k8s/secrets.yaml b/k8s/secrets.yaml deleted file mode 100644 index d6391fad..00000000 --- a/k8s/secrets.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: v1 -kind: Secret -metadata: - name: atuin-secrets -type: Opaque -stringData: - ATUIN_DB_USERNAME: atuin - ATUIN_DB_PASSWORD: seriously-insecure - ATUIN_HOST: "127.0.0.1" - ATUIN_PORT: "8888" - ATUIN_OPEN_REGISTRATION: "true" - ATUIN_DB_URI: "postgres://atuin:seriously-insecure@localhost/atuin" -immutable: true diff --git a/rust-toolchain.toml b/rust-toolchain.toml deleted file mode 100644 index 0f87b448..00000000 --- a/rust-toolchain.toml +++ /dev/null @@ -1,2 +0,0 @@ -[toolchain] -channel = "1.96.0" diff --git a/scripts/release.sh b/scripts/release.sh deleted file mode 100755 index 8e0717a2..00000000 --- a/scripts/release.sh +++ /dev/null @@ -1,508 +0,0 @@ -#!/usr/bin/env bash -# -# Atuin CLI Release Script -# -# But first — make a cup of tea. Releases without tea are a crime. 🫖 -# - -set -euo pipefail - -WORKDIR="" - -cleanup_on_error() { - if [[ $? -ne 0 && -n "$WORKDIR" ]]; then - echo "" - echo -e " \033[0;31m✗\033[0m Script failed. Working directory preserved at:" - echo -e " \033[2m$WORKDIR\033[0m" - fi -} -trap cleanup_on_error EXIT - -# ════════════════════════════════════════════════════════════════════ -# Formatting -# ════════════════════════════════════════════════════════════════════ - -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -CYAN='\033[0;36m' -MAGENTA='\033[0;35m' -BOLD='\033[1m' -DIM='\033[2m' -NC='\033[0m' - -info() { echo -e " ${BLUE}▸${NC} $*"; } -success() { echo -e " ${GREEN}✓${NC} $*"; } -warn() { echo -e " ${YELLOW}⚠${NC} $*"; } -die() { echo -e " ${RED}✗${NC} $*" >&2; exit 1; } - -step() { - echo "" - echo -e " ${MAGENTA}${BOLD}━━━ $* ━━━${NC}" - echo "" -} - -confirm() { - echo -en " ${CYAN}▸${NC} $1 ${DIM}[y/N]${NC} " - read -r reply - [[ "$reply" =~ ^[Yy]$ ]] -} - -# ════════════════════════════════════════════════════════════════════ -# Banner -# ════════════════════════════════════════════════════════════════════ - -banner() { - echo "" - echo -e "${CYAN}" - cat <<'BANNER' - - : - =#*#= - #*+*#. - #**++*+ - =#*++++#. - **+++++** - :#++++++*#. - **+++++++*# - -#*+++++++*#- - ##*****#####* - -*##########:.+####*. - ***********####*****+ - :**#############*#+ - #+----------------*- - -*###########**+++##-----=##=-----=##=# - .#*-==.. =*------------------* - -#-::::::*=----------#*---------=----=--=* - +*:::::::--:::::::::::**---+#=----===---=* - #*::::::::=::::::::::::**-----+#*=-----+#- - .#+::::::::=-::::::::::::**--------=*#### - #=::::::::=*:::::::::::::+*---------=#-*#= - ##-:::-**+=+*-:::::::::::-#=--------=#=##- - :#+**+========++=::::-=++=#+--------+#+#* - +##++============+*#+=====*+--------+#*# - *=*#*+==+**++++*#++*====+###--------*###* - *=-*##=+#=-------#**===+#+---------=##*=# - *=-=*#**+---------#*+==+#----------*##--# - :#*- ###=---------#+*==+#=-------=###=-=# - +=---------#+#+++#*++++*##*== .. # - ...... +=--*++*+=-#####+-. -+****=. - ....... =*== . + ........... - ............::-:............................ - ............................................ - ....###....########.##.....##.####.##....##. - ...##.##......##....##.....##..##..###...##. - ..##...##.....##....##.....##..##..####..##. - .##.....##....##....##.....##..##..##.##.##. - .#########....##....##.....##..##..##..####. - .##.....##....##....##.....##..##..##...###. - .##.....##....##.....#######..####.##....##. - ............................................ - - ~ Magical Shell History ~ - Release Script - -BANNER - echo -e "${NC}" - echo "" -} - -# ════════════════════════════════════════════════════════════════════ -# 1. Dependency check -# ════════════════════════════════════════════════════════════════════ - -check_deps() { - step "Dependencies" - - local missing=() - local deps=(git gsed cargo gh git-cliff) - - for cmd in "${deps[@]}"; do - if command -v "$cmd" &>/dev/null; then - success "${BOLD}$cmd${NC} ${DIM}$(command -v "$cmd")${NC}" - else - echo -e " ${RED}✗${NC} ${BOLD}$cmd${NC} not found" - missing+=("$cmd") - fi - done - - if (( ${#missing[@]} )); then - echo "" - die "Missing required tools: ${missing[*]}\n Install with: ${DIM}brew install ${missing[*]}${NC}" - fi -} - -# ════════════════════════════════════════════════════════════════════ -# 2. Clone into working directory -# ════════════════════════════════════════════════════════════════════ - -setup_workdir() { - step "Working Directory" - - WORKDIR=$(mktemp -d) - info "Created ${DIM}$WORKDIR${NC}" - - info "Cloning atuinsh/atuin..." - git clone --quiet git@github.com:atuinsh/atuin.git "$WORKDIR" - cd "$WORKDIR" - success "Repository cloned" -} - -# ════════════════════════════════════════════════════════════════════ -# 3. Version -# ════════════════════════════════════════════════════════════════════ - -detect_current_version() { - sed -n '/^\[workspace\.package\]/,/^\[/s/^version = "\(.*\)"/\1/p' Cargo.toml -} - -get_version() { - step "Version" - - CURRENT_VERSION=$(detect_current_version) - info "Current version: ${BOLD}$CURRENT_VERSION${NC}" - - # Suggest the next version based on conventional commits - local suggested - suggested=$(git-cliff --bumped-version 2>/dev/null | sed 's/^v//' || true) - if [[ -n "$suggested" && "$suggested" != "$CURRENT_VERSION" ]]; then - info "Suggested next: ${BOLD}$suggested${NC} ${DIM}(based on conventional commits)${NC}" - fi - - echo "" - - if [[ -n "${NEW_VERSION:-}" ]]; then - info "Using version from environment: ${BOLD}$NEW_VERSION${NC}" - else - echo -en " ${CYAN}▸${NC} New version ${DIM}(without 'v' prefix)${NC}: " - read -r NEW_VERSION - fi - - [[ -n "$NEW_VERSION" ]] || die "Version cannot be empty" - - IS_PRERELEASE=false - if [[ "$NEW_VERSION" == *-* ]]; then - IS_PRERELEASE=true - warn "Pre-release detected" - fi - - echo "" - info "${BOLD}$CURRENT_VERSION${NC} → ${BOLD}$NEW_VERSION${NC}" - echo "" - confirm "Proceed with release?" || { info "Aborted."; exit 0; } -} - -# ════════════════════════════════════════════════════════════════════ -# 4. Update version numbers -# ════════════════════════════════════════════════════════════════════ - -update_versions() { - step "Updating Versions" - - info "Creating release branch: ${BOLD}$NEW_VERSION${NC}" - git checkout -b "$NEW_VERSION" --quiet - - local version_pattern="${CURRENT_VERSION//./\\.}" - - info "Replacing ${DIM}$CURRENT_VERSION${NC} → ${DIM}$NEW_VERSION${NC} in Cargo.toml files..." - find . -type f -name 'Cargo.toml' -not -path './.git/*' \ - -exec gsed -i "s/$version_pattern/$NEW_VERSION/g" {} \; - - info "Running ${DIM}cargo check${NC} to update Cargo.lock (this may take a moment)..." - cargo check --quiet 2>&1 || cargo check - - echo "" - info "Changed files:" - git diff --stat | sed 's/^/ /' - - echo "" - - # Verify the workspace version was updated - local new_ws_version - new_ws_version=$(detect_current_version) - if [[ "$new_ws_version" == "$NEW_VERSION" ]]; then - success "Workspace version updated" - else - die "Workspace version is '$new_ws_version', expected '$NEW_VERSION'" - fi - - # Verify we didn't break anything unexpected — show version-related - # lines in the diff for review - echo "" - info "Version changes in diff:" - git diff --unified=0 -- '*.toml' \ - | grep -E '^\+.*version' \ - | grep -v '^\+\+\+' \ - | sed 's/^/ /' || true - echo "" - - confirm "Version changes look correct?" || { die "Aborting — fix versions manually in $WORKDIR"; } -} - -# ════════════════════════════════════════════════════════════════════ -# 5. Changelog -# ════════════════════════════════════════════════════════════════════ - -update_changelog() { - step "Changelog" - - # cliff.toml's ignore_tags already ignores beta/alpha tags, so - # --unreleased always gives us everything since the last stable release. - # - # Prereleases: heading is ## [unreleased] (running tally) - # Stable: heading is ## X.Y.Z (versioned entry) - local cliff_args=(--unreleased --strip all) - - if $IS_PRERELEASE; then - info "Updating ${BOLD}Unreleased${NC} section..." - else - cliff_args+=(--tag "v$NEW_VERSION") - info "Generating changelog for ${BOLD}$NEW_VERSION${NC}..." - fi - - local new_entry - new_entry=$(git-cliff "${cliff_args[@]}" 2>/dev/null || true) - - # Check if the entry is empty (just a heading with no content) - if [[ -z "$new_entry" ]] || [[ "$(echo "$new_entry" | grep -c '[a-zA-Z]')" -le 1 ]]; then - warn "No unreleased changes detected by git-cliff" - warn "You may want to add entries manually in the editor" - if $IS_PRERELEASE; then - new_entry="## [unreleased]" - else - new_entry="## $NEW_VERSION" - fi - else - local commit_count - commit_count=$(echo "$new_entry" | grep -c '^- ' || true) - success "Generated entry with ${BOLD}$commit_count${NC} item(s)" - fi - - # Remove any existing [unreleased] section — we'll replace it with - # either an updated unreleased section or a versioned one - if grep -qi '^\## \[unreleased\]' CHANGELOG.md; then - info "Removing old Unreleased section..." - awk ' - /^## \[[Uu]nreleased\]/ { skip=1; next } - /^## / { skip=0 } - !skip - ' CHANGELOG.md > CHANGELOG.md.tmp - mv CHANGELOG.md.tmp CHANGELOG.md - fi - - # Insert the new entry before the first existing version heading - local insert_line - insert_line=$(grep -n '^## ' CHANGELOG.md | head -1 | cut -d: -f1) - - if [[ -n "$insert_line" ]]; then - { - head -n "$((insert_line - 1))" CHANGELOG.md - echo "$new_entry" - echo "" - echo "" - tail -n "+$insert_line" CHANGELOG.md - } > CHANGELOG.md.tmp - mv CHANGELOG.md.tmp CHANGELOG.md - else - warn "No existing version headings found — appending to end" - echo "" >> CHANGELOG.md - echo "$new_entry" >> CHANGELOG.md - fi - - echo "" - info "Opening CHANGELOG.md in your editor for review..." - info "${DIM}Verify the entry, make any edits, then save and close.${NC}" - echo "" - echo -en " ${DIM}Press Enter to open editor...${NC}" - read -r - "${EDITOR:-${VISUAL:-vi}}" CHANGELOG.md - success "Changelog finalized" -} - -# ════════════════════════════════════════════════════════════════════ -# 6. Commit and push -# ════════════════════════════════════════════════════════════════════ - -commit_and_push() { - step "Commit & Push" - - git add . - git commit --quiet -m "chore(release): prepare for release $NEW_VERSION" - success "Committed" - - info "Pushing branch..." - git push --quiet --set-upstream origin "$(git branch --show-current)" 2>&1 - success "Pushed to origin/${BOLD}$NEW_VERSION${NC}" -} - -# ════════════════════════════════════════════════════════════════════ -# 7. Pull request -# ════════════════════════════════════════════════════════════════════ - -extract_changelog_entry() { - # Extract the changelog body (without the heading) for the entry we just wrote. - # Prereleases use ## [unreleased], stable uses ## X.Y.Z - local heading - if $IS_PRERELEASE; then - heading='## \[unreleased\]' - else - heading="## ${NEW_VERSION//./\\.}" - fi - awk "/^${heading}/{found=1; next} /^## /{if(found) exit} found" CHANGELOG.md -} - -create_pr() { - step "Pull Request" - - local changelog_body - changelog_body=$(extract_changelog_entry) - - local pr_body - pr_body="Release preparation for v${NEW_VERSION}." - if [[ -n "$changelog_body" ]]; then - pr_body="$(cat <<EOF -Release preparation for v${NEW_VERSION}. - -## Changelog - -$changelog_body -EOF -)" - fi - - info "Creating PR..." - PR_URL=$(gh pr create \ - --title "chore(release): prepare for release $NEW_VERSION" \ - --body "$pr_body" \ - --repo atuinsh/atuin) - - success "PR created: ${BOLD}$PR_URL${NC}" - - local pr_number - pr_number=$(echo "$PR_URL" | grep -o '[0-9]*$') - - echo "" - info "Waiting for PR #${BOLD}$pr_number${NC} to be merged..." - info "${DIM}Review and merge the PR — this script will detect it automatically.${NC}" - echo "" - - while true; do - local state - state=$(gh pr view "$pr_number" --repo atuinsh/atuin --json state --jq '.state' 2>/dev/null || echo "UNKNOWN") - - case "$state" in - MERGED) - echo "" - success "PR #$pr_number merged!" - break - ;; - CLOSED) - echo "" - die "PR #$pr_number was closed without merging" - ;; - *) - printf "\r ${DIM}⏳ PR #%s is %s — checking again in 5s...${NC} " "$pr_number" "$state" - sleep 5 - ;; - esac - done -} - -# ════════════════════════════════════════════════════════════════════ -# 8. Tag -# ════════════════════════════════════════════════════════════════════ - -tag_release() { - step "Tag & Release" - - info "Switching to main and pulling..." - git checkout main --quiet - git pull --quiet - - info "Creating tag ${BOLD}v$NEW_VERSION${NC}" - git tag "v$NEW_VERSION" - - info "Pushing tag..." - git push --tags - success "Tag ${BOLD}v$NEW_VERSION${NC} pushed — release workflow triggered" -} - -# ════════════════════════════════════════════════════════════════════ -# 9. Publish to crates.io -# ════════════════════════════════════════════════════════════════════ - -publish_crates() { - step "Publish to crates.io" - - if $IS_PRERELEASE; then - warn "Pre-release — skipping crates.io publish" - return - fi - - if ! confirm "Publish to crates.io?"; then - info "Skipping" - return - fi - - local crates=( - atuin-common - atuin-client - atuin-ai - atuin-dotfiles - atuin-history - atuin-nucleo/matcher - atuin-nucleo - atuin-daemon - atuin-kv - atuin-scripts - atuin-server-database - atuin-server-postgres - atuin-server-sqlite - atuin-server - atuin-pty-proxy - atuin - ) - - for crate in "${crates[@]}"; do - info "Publishing ${BOLD}$crate${NC}..." - local output - # --no-verify: skip rebuild during publish — the code already passed - # CI, and verification fails on workspace crates whose freshly-published - # dependencies haven't been indexed by crates.io yet - if output=$(cd "crates/$crate" && cargo publish --no-verify 2>&1); then - success "$crate published" - elif echo "$output" | grep -q "already uploaded"; then - warn "$crate already published, skipping" - else - echo "$output" >&2 - die "Failed to publish $crate" - fi - done -} - -# ════════════════════════════════════════════════════════════════════ -# Main -# ════════════════════════════════════════════════════════════════════ - -main() { - banner - check_deps - setup_workdir - get_version - update_versions - update_changelog - commit_and_push - create_pr - tag_release - publish_crates - - step "Done 🎉" - success "Released ${BOLD}v$NEW_VERSION${NC}" - echo "" - info "Working directory: ${DIM}$WORKDIR${NC}" - info "Clean up with: ${DIM}rm -rf $WORKDIR${NC}" - echo "" -} - -main "$@" diff --git a/scripts/span-table.ts b/scripts/span-table.ts deleted file mode 100755 index 3656f129..00000000 --- a/scripts/span-table.ts +++ /dev/null @@ -1,420 +0,0 @@ -#!/usr/bin/env bun -/** - * Analyze span timing JSON logs generated with ATUIN_SPAN - * - * Usage: bun scripts/span-table.ts <file.json> [options] - * --filter <pattern> Only show spans matching pattern (regex) - * --sort <field> Sort by: calls, avg, total, p99 (default: total) - * --top <n> Show top N spans (default: 20) - * --detail <span> Show individual calls for a specific span - * --all Include internal/library spans - */ - -import { readFileSync } from "fs"; - -interface SpanEvent { - timestamp: string; - level: string; - fields: { - message: string; - "time.busy"?: string; - "time.idle"?: string; - }; - target: string; - span?: { - name: string; - [key: string]: unknown; - }; - spans?: Array<{ name: string; [key: string]: unknown }>; -} - -interface SpanStats { - name: string; - calls: number; - busyTimes: number[]; // in microseconds - idleTimes: number[]; - parentCounts: Map<string, number>; // parent span name -> count -} - -// Parse duration strings like "1.23ms", "456µs", "789ns" to microseconds -function parseDuration(duration: string): number { - const match = duration.match(/^([\d.]+)(ns|µs|us|ms|s)$/); - if (!match) return 0; - - const value = parseFloat(match[1]); - const unit = match[2]; - - switch (unit) { - case "ns": - return value / 1000; - case "µs": - case "us": - return value; - case "ms": - return value * 1000; - case "s": - return value * 1_000_000; - default: - return 0; - } -} - -// Format microseconds for display -function formatDuration(us: number): string { - if (us < 1) { - return `${(us * 1000).toFixed(0)}ns`; - } else if (us < 1000) { - return `${us.toFixed(2)}µs`; - } else if (us < 1_000_000) { - return `${(us / 1000).toFixed(2)}ms`; - } else { - return `${(us / 1_000_000).toFixed(2)}s`; - } -} - -function percentile(arr: number[], p: number): number { - if (arr.length === 0) return 0; - const sorted = [...arr].sort((a, b) => a - b); - const idx = Math.floor(sorted.length * p); - return sorted[Math.min(idx, sorted.length - 1)]; -} - -function parseJsonLines(content: string): SpanEvent[] { - const events: SpanEvent[] = []; - for (const line of content.trim().split("\n")) { - if (!line.trim()) continue; - try { - events.push(JSON.parse(line)); - } catch { - // Skip malformed lines - } - } - return events; -} - -function main() { - const args = process.argv.slice(2); - - // Parse arguments - let filterPattern: RegExp | null = null; - let sortField = "total"; - let topN = 20; - let detailSpan: string | null = null; - let showAll = false; - const files: string[] = []; - - for (let i = 0; i < args.length; i++) { - if (args[i] === "--filter" && args[i + 1]) { - filterPattern = new RegExp(args[++i]); - } else if (args[i] === "--sort" && args[i + 1]) { - sortField = args[++i]; - } else if (args[i] === "--top" && args[i + 1]) { - topN = parseInt(args[++i], 10); - } else if (args[i] === "--detail" && args[i + 1]) { - detailSpan = args[++i]; - } else if (args[i] === "--all") { - showAll = true; - } else if (!args[i].startsWith("-")) { - files.push(args[i]); - } - } - - if (files.length === 0) { - console.error("Usage: bun scripts/span-table.ts <file.json> [options]"); - console.error(" --filter <pattern> Only show spans matching pattern (regex)"); - console.error(" --sort <field> Sort by: calls, avg, total, p99 (default: total)"); - console.error(" --top <n> Show top N spans (default: 20)"); - console.error(" --detail <span> Show individual calls for a specific span"); - console.error(" --all Include internal/library spans"); - process.exit(1); - } - - // Parse all files - const allEvents: SpanEvent[] = []; - for (const file of files) { - const content = readFileSync(file, "utf-8"); - for (const event of parseJsonLines(content)) { - allEvents.push(event); - } - } - - // Filter to close events and aggregate by span name - const spans = new Map<string, SpanStats>(); - - for (const event of allEvents) { - if (event.fields?.message !== "close") continue; - if (!event.span?.name) continue; - if (!event.fields["time.busy"]) continue; - - const name = event.span.name; - - // Apply filter if specified - if (filterPattern && !filterPattern.test(name)) continue; - - // Skip noisy internal spans unless explicitly requested - if ( - !showAll && - !filterPattern && - !detailSpan && - (name.startsWith("FramedRead::") || - name.startsWith("FramedWrite::") || - name.startsWith("Prioritize::") || - name === "poll" || - name === "poll_ready" || - name === "Connection" || - name.startsWith("assign_") || - name.startsWith("reserve_") || - name.startsWith("try_") || - name.startsWith("send_") || - name.startsWith("pop_")) - ) { - continue; - } - - if (!spans.has(name)) { - spans.set(name, { name, calls: 0, busyTimes: [], idleTimes: [], parentCounts: new Map() }); - } - - const stats = spans.get(name)!; - stats.calls++; - stats.busyTimes.push(parseDuration(event.fields["time.busy"])); - if (event.fields["time.idle"]) { - stats.idleTimes.push(parseDuration(event.fields["time.idle"])); - } - - // Track parent relationship (immediate parent is the last element in spans array) - const parents = event.spans || []; - const parentName = parents.length > 0 ? parents[parents.length - 1].name : "__root__"; - stats.parentCounts.set(parentName, (stats.parentCounts.get(parentName) || 0) + 1); - } - - if (spans.size === 0) { - console.error("No matching span close events found"); - process.exit(1); - } - - // Detail mode: show individual calls for a specific span - if (detailSpan) { - const detailEvents: Array<{ - timestamp: string; - busy: number; - idle: number; - fields: Record<string, unknown>; - parents: string[]; - }> = []; - - for (const event of allEvents) { - if (event.fields?.message !== "close") continue; - if (event.span?.name !== detailSpan) continue; - if (!event.fields["time.busy"]) continue; - - // Extract span fields (excluding name) - const fields: Record<string, unknown> = {}; - if (event.span) { - for (const [k, v] of Object.entries(event.span)) { - if (k !== "name") fields[k] = v; - } - } - - // Get parent span names - const parents = (event.spans || []).map((s) => s.name); - - detailEvents.push({ - timestamp: event.timestamp, - busy: parseDuration(event.fields["time.busy"]), - idle: event.fields["time.idle"] ? parseDuration(event.fields["time.idle"]) : 0, - fields, - parents, - }); - } - - if (detailEvents.length === 0) { - console.error(`No events found for span "${detailSpan}"`); - process.exit(1); - } - - console.log(""); - console.log(`Individual calls for: ${detailSpan}`); - console.log("-".repeat(110)); - console.log( - "#".padStart(4) + - "Wall".padStart(12) + - "Busy".padStart(12) + - "Idle".padStart(12) + - " Fields" - ); - console.log("-".repeat(110)); - - detailEvents.forEach((e, i) => { - const fieldsStr = Object.keys(e.fields).length > 0 - ? JSON.stringify(e.fields) - : ""; - - console.log( - (i + 1).toString().padStart(4) + - formatDuration(e.busy + e.idle).padStart(12) + - formatDuration(e.busy).padStart(12) + - formatDuration(e.idle).padStart(12) + - " " + - fieldsStr - ); - }); - - // Summary stats - const busyTimes = detailEvents.map((e) => e.busy); - const wallTimes = detailEvents.map((e) => e.busy + e.idle); - console.log(""); - console.log( - `Summary: ${detailEvents.length} calls\n` + - ` Wall: avg=${formatDuration(wallTimes.reduce((a, b) => a + b, 0) / wallTimes.length)}, ` + - `min=${formatDuration(Math.min(...wallTimes))}, ` + - `max=${formatDuration(Math.max(...wallTimes))}, ` + - `p50=${formatDuration(percentile(wallTimes, 0.5))}, ` + - `p99=${formatDuration(percentile(wallTimes, 0.99))}\n` + - ` Busy: avg=${formatDuration(busyTimes.reduce((a, b) => a + b, 0) / busyTimes.length)}, ` + - `min=${formatDuration(Math.min(...busyTimes))}, ` + - `max=${formatDuration(Math.max(...busyTimes))}, ` + - `p50=${formatDuration(percentile(busyTimes, 0.5))}, ` + - `p99=${formatDuration(percentile(busyTimes, 0.99))}` - ); - return; - } - - // Calculate stats - const results = [...spans.values()].map((s) => { - // Calculate wall times (busy + idle) for each call - const wallTimes = s.busyTimes.map((busy, i) => busy + (s.idleTimes[i] || 0)); - - // Find most common parent - let mostCommonParent = "__root__"; - let maxCount = 0; - for (const [parent, count] of s.parentCounts) { - if (count > maxCount) { - maxCount = count; - mostCommonParent = parent; - } - } - - return { - name: s.name, - calls: s.calls, - total: s.busyTimes.reduce((a, b) => a + b, 0), - avg: s.busyTimes.reduce((a, b) => a + b, 0) / s.calls, - min: Math.min(...s.busyTimes), - max: Math.max(...s.busyTimes), - p50: percentile(s.busyTimes, 0.5), - p99: percentile(s.busyTimes, 0.99), - avgWall: wallTimes.reduce((a, b) => a + b, 0) / s.calls, - p50Wall: percentile(wallTimes, 0.5), - p99Wall: percentile(wallTimes, 0.99), - parent: mostCommonParent, - }; - }); - - // Build tree structure - const childrenOf = new Map<string, string[]>(); - childrenOf.set("__root__", []); - for (const r of results) { - if (!childrenOf.has(r.name)) { - childrenOf.set(r.name, []); - } - if (!childrenOf.has(r.parent)) { - childrenOf.set(r.parent, []); - } - childrenOf.get(r.parent)!.push(r.name); - } - - // Sort children by the specified field - const resultMap = new Map(results.map(r => [r.name, r])); - const sortChildren = (children: string[]) => { - children.sort((a, b) => { - const ra = resultMap.get(a); - const rb = resultMap.get(b); - if (!ra || !rb) return 0; - switch (sortField) { - case "calls": - return rb.calls - ra.calls; - case "avg": - return rb.avg - ra.avg; - case "p99": - return rb.p99 - ra.p99; - case "total": - default: - return rb.total - ra.total; - } - }); - }; - - // Traverse tree to build ordered display list with depths - const displayResults: Array<{ result: typeof results[0]; depth: number }> = []; - const visited = new Set<string>(); - - function traverse(name: string, depth: number) { - if (visited.has(name)) return; - visited.add(name); - - const result = resultMap.get(name); - if (result) { - displayResults.push({ result, depth }); - } - - const children = childrenOf.get(name) || []; - sortChildren(children); - for (const child of children) { - traverse(child, depth + 1); - } - } - - // Start from roots - const roots = childrenOf.get("__root__") || []; - sortChildren(roots); - for (const root of roots) { - traverse(root, 0); - } - - // Add any orphaned spans (whose parent wasn't in our span list) - for (const r of results) { - if (!visited.has(r.name)) { - displayResults.push({ result: r, depth: 0 }); - } - } - - // Apply topN limit - const limitedResults = displayResults.slice(0, topN); - - console.log(""); - console.log( - "Span Name".padEnd(40) + - "Calls".padStart(6) + - "Avg(wall)".padStart(11) + - "P50(wall)".padStart(11) + - "P99(wall)".padStart(11) + - "Avg(busy)".padStart(11) + - "P50(busy)".padStart(11) + - "P99(busy)".padStart(11) - ); - console.log("-".repeat(112)); - - for (const { result: r, depth } of limitedResults) { - const indent = " ".repeat(depth); - const maxNameLen = 38 - indent.length; - const truncatedName = r.name.length > maxNameLen ? "..." + r.name.slice(-(maxNameLen - 3)) : r.name; - const displayName = indent + truncatedName; - - console.log( - displayName.padEnd(40) + - r.calls.toString().padStart(6) + - formatDuration(r.avgWall).padStart(11) + - formatDuration(r.p50Wall).padStart(11) + - formatDuration(r.p99Wall).padStart(11) + - formatDuration(r.avg).padStart(11) + - formatDuration(r.p50).padStart(11) + - formatDuration(r.p99).padStart(11) - ); - } - - console.log(""); - console.log(`Showing ${limitedResults.length} of ${results.length} spans (sorted by ${sortField})`); -} - -main(); |
