diff --git a/bin/convert-prompts-folder-to-prompt-log b/bin/convert-prompts-folder-to-prompt-log new file mode 100755 index 0000000..3597f6d --- /dev/null +++ b/bin/convert-prompts-folder-to-prompt-log @@ -0,0 +1,101 @@ +#!/usr/bin/env bash + +convert-prompts-folder-to-prompt-log() { + local repo_path="${1:-.}" + + if [[ ! -d "$repo_path/.git" ]]; then + echo "Error: No .git directory found in $repo_path." + return 1 + fi + + local prompts_dir="$repo_path/prompts" + + if [[ ! -d "$prompts_dir" ]]; then + echo "No prompts directory found at $prompts_dir." + return 0 + fi + + local original_dir + original_dir="$(pwd)" + cd "$repo_path" || { echo "Cannot change to $repo_path"; return 1; } + + if [[ ! -d "tmp/prompt-log" ]] || ! git worktree list | grep -qF "$(pwd)/tmp/prompt-log"; then + echo "Creating prompt-log worktree." + if ! git show-ref --verify --quiet refs/heads/prompt-log; then + local current_branch + current_branch="$(git rev-parse --abbrev-ref HEAD)" + if [[ "$current_branch" == "prompt-log" ]]; then + echo "Error: Cannot create prompt-log worktree while on prompt-log branch." + cd "$original_dir" || true + return 1 + fi + local empty_tree="4b825dc642cb6eb9a060e54bf8d69288fbee4904" + local orphan_commit + orphan_commit="$(echo "init: prompt-log branch" | git commit-tree "$empty_tree")" + git branch prompt-log "$orphan_commit" + fi + mkdir -p tmp + git worktree add "tmp/prompt-log" prompt-log + fi + + local worktree_path="tmp/prompt-log" + local -a skipped + local converted=0 + + for file in "$prompts_dir"/*.md; do + if [[ ! -f "$file" ]]; then + continue + fi + + local filename + filename="$(basename "$file")" + + local creation_commit + creation_commit="$(git log --follow --diff-filter=A --format="%h" -- "$file" | tail -n 1)" + + if [[ -z "$creation_commit" ]]; then + skipped+=("$filename") + continue + fi + + local title + title="$(grep -m1 '^title:' "$file" | sed 's/^title:[[:space:]]*//; s/^"\(.*\)"$/\1/; s/'"'"'\(.*\)'"'"'$/\1/')" + + if [[ -z "$title" ]]; then + title="untitled" + fi + + local slug + slug=$(echo "$title" | tr '[:upper:]' '[:lower:]' | tr '.' '-' | tr ' ' '-' | tr -cd '[:alnum:]-') + + local target_filename="${creation_commit}-${slug}.md" + local target_path="$worktree_path/$target_filename" + + cp "$file" "$target_path" + + ( + cd "$worktree_path" || exit 1 + git add "$target_filename" + git commit -m "feat: add prompt file" -m "$target_filename" + ) || { echo "Error: Failed to commit $target_filename"; continue; } + + converted=$((converted + 1)) + done + + if [[ ${#skipped[@]} -gt 0 ]]; then + echo "Skipped files with no discoverable creation commit:" + printf '%s\n' "${skipped[@]}" + fi + + echo "Converted $converted prompt file(s)." + + if [[ $converted -gt 0 ]]; then + rm -rf "$prompts_dir" + echo "Removed old $prompts_dir folder." + fi + + cd "$original_dir" || true +} +cpfpl() { + convert-prompts-folder-to-prompt-log "$@" +} diff --git a/bin/create-prompt b/bin/create-prompt index 55f540c..8d6d80d 100755 --- a/bin/create-prompt +++ b/bin/create-prompt @@ -5,57 +5,27 @@ create-prompt() { if [[ -z "$title" ]]; then echo "Error: Title cannot be empty." - echo "Usage: task create-prompt " + echo "Usage: task create-prompt <title> [repo-path]" return 1 fi - - local prompts_dir="prompts" - if [ -n "$2" ]; then - prompts_dir="$2/prompts" - fi - if [[ ! -d "$prompts_dir" ]]; then - mkdir -p "$prompts_dir" - fi - - local highest_num=0 - for file in "$prompts_dir"/[0-9][0-9]_*.md; do - if [[ -f "$file" ]]; then - local num=${file#"$prompts_dir"/} - num=${num%%_*} - num=${num//[!0-9]/} - if [[ -n "$num" ]] && (( 10#$num > highest_num )); then - highest_num=$((10#$num)) - fi - fi - done + local repo_path="${2:-.}" + local prompt_file="$repo_path/prompt.md" + + local git_author + git_author="$(git log --format="%an <%ae>" -1 2>/dev/null || echo '')" - local next_num=$((highest_num + 1)) - local padded_num=$(printf "%02d" "$next_num") - - local slug=$(echo "$title" | tr '[:upper:]' '[:lower:]'| tr '.' '-' | tr ' ' '-' | tr -cd '[:alnum:]-') - local filename="${padded_num}_${slug}.md" - local filepath="$prompts_dir/$filename" - - if [[ -f "$filepath" ]]; then - echo "Error: File $filepath already exists." - return 1 - fi - export PROMPT_TITLE="$title" - export PROMPT_ID="$padded_num" - envsubst < "$HOME/taskfile.build/prompt.md.template" > "$filepath" - + export PROMPT_AUTHOR="${git_author:-}" + + envsubst < "$HOME/taskfile.build/prompt.md.template" > "$prompt_file" + if [[ -n "$EDITOR" ]]; then - "$EDITOR" "$filepath" + "$EDITOR" "$prompt_file" fi - echo 'File created:' - echo "$filepath" - - # Copy path to clipboard - echo "$filepath" | copy-to-clipboard - echo "Path to prompt file copied to clipboard." + echo "File created:" + echo "$prompt_file" } crp() { create-prompt "$@" diff --git a/bin/edit-prompt b/bin/edit-prompt new file mode 100755 index 0000000..364f8a6 --- /dev/null +++ b/bin/edit-prompt @@ -0,0 +1,93 @@ +#!/usr/bin/env bash + +edit-prompt() { + local commit="" + local repo_path="${2:-.}" + + if [[ -n "$1" ]]; then + if [[ -n "$2" ]]; then + commit="$1" + elif [[ "$1" == */* ]] || [[ "$1" == "." ]]; then + repo_path="$1" + else + commit="$1" + fi + fi + + if [[ ! -d "$repo_path/.git" ]]; then + echo "Error: No .git directory found in $repo_path." + return 1 + fi + + local worktree_path="$repo_path/tmp/prompt-log" + + if [[ ! -d "$worktree_path" ]]; then + echo "No prompt-log worktree found. Run init-prompt-log first." + return 1 + fi + + local target_file + + if [[ -z "$commit" ]]; then + if ! command -v fzf &> /dev/null; then + echo "Error: fzf is required for interactive selection." + return 1 + fi + + local selected + selected="$( + for f in "$worktree_path"/*.md; do + if [[ -f "$f" ]]; then + local f_title + f_title="$(grep -m1 '^title:' "$f" | sed 's/^title:[[:space:]]*//; s/^"\(.*\)"$/\1/; s/'"'"'\(.*\)'"'"'$/\1/')" + echo "$(basename "$f"): $f_title" + fi + done | fzf | cut -d: -f1 + )" + + if [[ -z "$selected" ]]; then + echo "No prompt selected." + return 0 + fi + + target_file="$worktree_path/$selected" + else + local matching_files=() + for f in "$worktree_path"/${commit}*.md; do + if [[ -f "$f" ]]; then + matching_files+=("$f") + fi + done + + if [[ ${#matching_files[@]} -eq 0 ]]; then + echo "Error: No prompt file found starting with commit prefix '$commit'." + return 1 + elif [[ ${#matching_files[@]} -gt 1 ]]; then + echo "Error: Ambiguous commit prefix '$commit'. Matches:" + printf '%s\n' "${matching_files[@]}" + return 1 + fi + + target_file="${matching_files[0]}" + fi + + if [[ -n "$EDITOR" ]]; then + "$EDITOR" "$target_file" + else + echo "Set EDITOR to open the prompt file automatically." + return 1 + fi + + local filename + filename="$(basename "$target_file")" + + ( + cd "$worktree_path" || exit 1 + git add "$filename" + git commit -m "feat: update prompt file" -m "$filename" + git push 2>/dev/null || echo "Warning: push failed." + ) || echo "Warning: commit/push step failed." +} +ep() { + edit-prompt "$@" +} diff --git a/bin/init-prompt-log b/bin/init-prompt-log new file mode 100755 index 0000000..957d505 --- /dev/null +++ b/bin/init-prompt-log @@ -0,0 +1,54 @@ +#!/usr/bin/env bash + +init-prompt-log() { + local repo_path="${1:-.}" + + if [[ ! -d "$repo_path/.git" ]]; then + echo "Error: No .git directory found in $repo_path." + return 1 + fi + + local original_dir + original_dir="$(pwd)" + cd "$repo_path" || { echo "Cannot change to $repo_path"; return 1; } + + local current_branch + current_branch="$(git rev-parse --abbrev-ref HEAD)" + + if [[ "$current_branch" == "prompt-log" ]]; then + if [[ -d "tmp/prompt-log" ]] && git worktree list | grep -qF "$(pwd)/tmp/prompt-log"; then + echo "prompt-log worktree already exists at tmp/prompt-log." + cd "$original_dir" || true + return 0 + fi + echo "Error: Cannot create prompt-log worktree while on prompt-log branch. Switch to another branch first." + cd "$original_dir" || true + return 1 + fi + + if ! git show-ref --verify --quiet refs/heads/prompt-log; then + local empty_tree="4b825dc642cb6eb9a060e54bf8d69288fbee4904" + local orphan_commit + orphan_commit="$(echo "init: prompt-log branch" | git commit-tree "$empty_tree")" + git branch prompt-log "$orphan_commit" + fi + + if git rev-parse --abbrev-ref origin/prompt-log &>/dev/null; then + echo "Remote branch origin/prompt-log already exists." + elif git remote &>/dev/null; then + git push -u origin prompt-log 2>/dev/null || echo "Warning: could not push prompt-log to remote." + fi + + if [[ -d "tmp/prompt-log" ]] && git worktree list | grep -qF "$(pwd)/tmp/prompt-log"; then + echo "prompt-log worktree already exists at tmp/prompt-log." + else + mkdir -p tmp + git worktree add "tmp/prompt-log" prompt-log + echo "Created prompt-log worktree at tmp/prompt-log." + fi + + cd "$original_dir" || true +} +ipl() { + init-prompt-log "$@" +} diff --git a/bin/list-prompts b/bin/list-prompts index 75f11bc..bb2e77f 100755 --- a/bin/list-prompts +++ b/bin/list-prompts @@ -1,58 +1,87 @@ #!/usr/bin/env bash list-prompts() { - local prompts_dir="prompts" - if [ -n "$1" ]; then - prompts_dir="$1/prompts" + local repo_path="${1:-.}" + + if [[ ! -d "$repo_path/.git" ]]; then + echo "Error: No .git directory found in $repo_path." + return 1 fi - - if [[ ! -d "$prompts_dir" ]]; then - echo "No prompts directory found." + + local worktree_path="$repo_path/tmp/prompt-log" + + if [[ ! -d "$worktree_path" ]]; then + echo "No prompt-log worktree found." return 0 fi - - local files=("$prompts_dir"/[0-9][0-9]_*.md) - - if [[ ${#files[@]} -eq 0 ]]; then + + local files=("$worktree_path"/*.md) + + if [[ ! -f "${files[0]}" ]]; then echo "No prompt files found." return 0 fi - - local max_id_len=2 - local max_title_len=10 + + local max_date_len=4 + local max_title_len=5 local max_state_len=5 + local max_commit_len=6 + + local -a rows for file in "${files[@]}"; do - local id=${file#"$prompts_dir"/} - id=${id%%_*} - - local title=$(grep -m1 '^title:' "$file" | sed 's/^title:[[:space:]]*//; s/^"\(.*\)"$/\1/') - local state=$(grep -m1 '^state:' "$file" | sed 's/^state:[[:space:]]*//; s/^"\(.*\)"$/\1/') - - if [[ ${#id} -gt max_id_len ]]; then - max_id_len=${#id} + if [[ ! -f "$file" ]]; then + continue fi + local title + title="$(grep -m1 '^title:' "$file" | sed 's/^title:[[:space:]]*//; s/^"\(.*\)"$/\1/; s/'"'"'\(.*\)'"'"'$/\1/')" + + local state + state="$(grep -m1 '^state:' "$file" | sed 's/^state:[[:space:]]*//; s/^"\(.*\)"$/\1/; s/'"'"'\(.*\)'"'"'$/\1/')" + + local filename + filename="$(basename "$file")" + local commit="${filename%%-*}" + + local date + date="$(cd "$worktree_path" && git log --diff-filter=A --follow --format="%ad" --date=short -- "$filename" | tail -n 1)" + + if [[ -z "$date" ]]; then + date="N/A" + fi + + rows+=("$date|$title|$state|$commit") + + if [[ ${#date} -gt max_date_len ]]; then + max_date_len=${#date} + fi if [[ ${#title} -gt max_title_len ]]; then max_title_len=${#title} fi - if [[ ${#state} -gt max_state_len ]]; then max_state_len=${#state} fi + if [[ ${#commit} -gt max_commit_len ]]; then + max_commit_len=${#commit} + fi done - printf "| %-${max_id_len}s | %-${max_title_len}s | %-${max_state_len}s |\n" "id" "title" "state" - printf "|-%s-|-%s-|-%s-|\n" "$(printf '%*s' "$max_id_len" '' | tr ' ' '-')" "$(printf '%*s' "$max_title_len" '' | tr ' ' '-')" "$(printf '%*s' "$max_state_len" '' | tr ' ' '-')" + printf "| %-${max_date_len}s | %-${max_title_len}s | %-${max_state_len}s | %-${max_commit_len}s |\n" "date" "title" "state" "commit" + printf "|-%s-|-%s-|-%s-|-%s-|\n" \ + "$(printf '%*s' "$max_date_len" '' | tr ' ' '-')" \ + "$(printf '%*s' "$max_title_len" '' | tr ' ' '-')" \ + "$(printf '%*s' "$max_state_len" '' | tr ' ' '-')" \ + "$(printf '%*s' "$max_commit_len" '' | tr ' ' '-')" - for file in "${files[@]}"; do - local id=${file#"$prompts_dir"/} - id=${id%%_*} + local -a sorted + while IFS= read -r line; do + sorted+=("$line") + done < <(printf '%s\n' "${rows[@]}" | sort -t'|' -k1,1) - local title=$(grep -m1 '^title:' "$file" | sed 's/^title:[[:space:]]*//; s/^"\(.*\)"$/\1/') - local state=$(grep -m1 '^state:' "$file" | sed 's/^state:[[:space:]]*//; s/^"\(.*\)"$/\1/') - - printf "| %-${max_id_len}s | %-${max_title_len}s | %-${max_state_len}s |\n" "$id" "$title" "$state" + for row in "${sorted[@]}"; do + IFS='|' read -r date title state commit <<< "$row" + printf "| %-${max_date_len}s | %-${max_title_len}s | %-${max_state_len}s | %-${max_commit_len}s |\n" "$date" "$title" "$state" "$commit" done } lp() { diff --git a/bin/log-prompt b/bin/log-prompt new file mode 100755 index 0000000..0b5d00d --- /dev/null +++ b/bin/log-prompt @@ -0,0 +1,74 @@ +#!/usr/bin/env bash + +log-prompt() { + local repo_path="${1:-.}" + + if [[ ! -d "$repo_path/.git" ]]; then + echo "Error: No .git directory found in $repo_path." + return 1 + fi + + local original_dir + original_dir="$(pwd)" + cd "$repo_path" || { echo "Cannot change to $repo_path"; return 1; } + + local prompt_file="prompt.md" + + if [[ ! -f "$prompt_file" ]]; then + echo "Error: $prompt_file not found in $repo_path." + cd "$original_dir" || true + return 1 + fi + + if [[ ! -d "tmp/prompt-log" ]] || ! git worktree list | grep -qF "$(pwd)/tmp/prompt-log"; then + echo "Creating prompt-log worktree." + if ! git show-ref --verify --quiet refs/heads/prompt-log; then + local current_branch + current_branch="$(git rev-parse --abbrev-ref HEAD)" + if [[ "$current_branch" == "prompt-log" ]]; then + echo "Error: Cannot create prompt-log worktree while on prompt-log branch." + cd "$original_dir" || true + return 1 + fi + local empty_tree="4b825dc642cb6eb9a060e54bf8d69288fbee4904" + local orphan_commit + orphan_commit="$(echo "init: prompt-log branch" | git commit-tree "$empty_tree")" + git branch prompt-log "$orphan_commit" + fi + mkdir -p tmp + git worktree add "tmp/prompt-log" prompt-log + fi + + local commit_hash + commit_hash="$(git rev-parse --short HEAD)" + + local title + title="$(grep -m1 '^title:' "$prompt_file" | sed 's/^title:[[:space:]]*//; s/^"\(.*\)"$/\1/; s/'"'"'\(.*\)'"'"'$/\1/')" + + if [[ -z "$title" ]]; then + echo "Error: Could not read title from $prompt_file frontmatter." + cd "$original_dir" || true + return 1 + fi + + local slug + slug=$(echo "$title" | tr '[:upper:]' '[:lower:]' | tr '.' '-' | tr ' ' '-' | tr -cd '[:alnum:]-') + + local worktree_path="tmp/prompt-log" + local filename="${commit_hash}-${slug}.md" + local target_path="$worktree_path/$filename" + + cp "$prompt_file" "$target_path" + + ( + cd "$worktree_path" || exit 1 + git add "$filename" + git commit -m "feat: add prompt file" -m "$filename" + git push 2>/dev/null || echo "Warning: push failed." + ) || { echo "Error: Failed to store prompt."; cd "$original_dir" || true; return 1; } + + cd "$original_dir" || true +} +lop() { + log-prompt "$@" +} diff --git a/bin/prompt-with-pi b/bin/prompt-with-pi new file mode 100755 index 0000000..5415741 --- /dev/null +++ b/bin/prompt-with-pi @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +prompt-with-pi() { + local prompt_file="${1:-prompt.md}" + + if [[ ! -f "$prompt_file" ]]; then + echo "Error: Prompt file not found: $prompt_file" + return 1 + fi + + pi < "$prompt_file" +} +pwp() { + prompt-with-pi "$@" +} diff --git a/bin/show-prompt b/bin/show-prompt new file mode 100755 index 0000000..850235c --- /dev/null +++ b/bin/show-prompt @@ -0,0 +1,78 @@ +#!/usr/bin/env bash + +show-prompt() { + local commit="" + local repo_path="${2:-.}" + + if [[ -n "$1" ]]; then + if [[ -n "$2" ]]; then + commit="$1" + elif [[ "$1" == */* ]] || [[ "$1" == "." ]]; then + repo_path="$1" + else + commit="$1" + fi + fi + + if [[ ! -d "$repo_path/.git" ]]; then + echo "Error: No .git directory found in $repo_path." + return 1 + fi + + local worktree_path="$repo_path/tmp/prompt-log" + + if [[ ! -d "$worktree_path" ]]; then + echo "No prompt-log worktree found. Run init-prompt-log first." + return 1 + fi + + local target_file + + if [[ -z "$commit" ]]; then + if ! command -v fzf &> /dev/null; then + echo "Error: fzf is required for interactive selection." + return 1 + fi + + local selected + selected="$( + for f in "$worktree_path"/*.md; do + if [[ -f "$f" ]]; then + local f_title + f_title="$(grep -m1 '^title:' "$f" | sed 's/^title:[[:space:]]*//; s/^"\(.*\)"$/\1/; s/'"'"'\(.*\)'"'"'$/\1/')" + echo "$(basename "$f"): $f_title" + fi + done | fzf | cut -d: -f1 + )" + + if [[ -z "$selected" ]]; then + echo "No prompt selected." + return 0 + fi + + target_file="$worktree_path/$selected" + else + local matching_files=() + for f in "$worktree_path"/${commit}*.md; do + if [[ -f "$f" ]]; then + matching_files+=("$f") + fi + done + + if [[ ${#matching_files[@]} -eq 0 ]]; then + echo "Error: No prompt file found starting with commit prefix '$commit'." + return 1 + elif [[ ${#matching_files[@]} -gt 1 ]]; then + echo "Error: Ambiguous commit prefix '$commit'. Matches:" + printf '%s\n' "${matching_files[@]}" + return 1 + fi + + target_file="${matching_files[0]}" + fi + + cat "$target_file" +} +shp() { + show-prompt "$@" +} diff --git a/prompts/convert-help-table-to-dynamic-width.md b/convert-help-table-to-dynamic-width.md similarity index 100% rename from prompts/convert-help-table-to-dynamic-width.md rename to convert-help-table-to-dynamic-width.md diff --git a/library.md b/library.md index afbef5f..7b1c47c 100644 --- a/library.md +++ b/library.md @@ -290,16 +290,52 @@ The last parameter can be either a direct prompt string or a path to a text file rows+=("update-changelog-with-llm|[num_lines]|Update CHANGELOG.md with changes from staged git diff using LLM.") ``` +### init-prompt-log + +```bash +rows+=("init-prompt-log||Initialize prompt-log branch and worktree.") +``` + ### create-prompt ```bash -rows+=("create-prompt|[path]|Create a new prompt file from template.") +rows+=("create-prompt|<title>[repo-path]|Create prompt.md from template.") +``` + +### prompt-with-pi + +```bash +rows+=("prompt-with-pi|[path]|Run pi with prompt.md.") +``` + +### log-prompt + +```bash +rows+=("log-prompt|[repo-path]|Log prompt.md to prompt-log branch.") ``` ### list-prompts ```bash -rows+=("list-prompts|[path]|List all prompt files.") +rows+=("list-prompts|[repo-path]|List prompts from prompt-log branch.") +``` + +### edit-prompt + +```bash +rows+=("edit-prompt|[commit][repo-path]|Edit prompt directly in prompt-log worktree.") +``` + +### show-prompt + +```bash +rows+=("show-prompt|[commit][repo-path]|Show prompt content from prompt-log.") +``` + +### convert-prompts-folder-to-prompt-log + +```bash +rows+=("convert-prompts-folder-to-prompt-log|[repo-path]|Convert prompts folder to prompt-log branch.") ``` <!-- ===LLM=== --> diff --git a/prompts/22_implement-prompt-log-commands.md b/prompt.md similarity index 57% rename from prompts/22_implement-prompt-log-commands.md rename to prompt.md index 9fb9126..f7eb4e8 100644 --- a/prompts/22_implement-prompt-log-commands.md +++ b/prompt.md @@ -1,21 +1,22 @@ --- title: "Implement prompt log commands" -state: draft -date_completed: YYYY-MM-DD -model: -input_tokens: -output_tokens: +author: "Janik von Rotz <login@janikvonrotz.ch>" +state: completed +date_completed: 2026-09-25 +model: moonshotai/Kimi-K2.6 +input_tokens: "~67000" +output_tokens: "~280" --- # Implement prompt log commands -Note: @Clanker refers to the "ai agent" (you) who is working on this prompt. +Note: @Clanker refers to the "ai agent" (you) who is working on this prompt file. -@Clanker when working on this prompt, make sure to: +@Clanker when working on this prompt file, make sure to: - Read context and task section first - Prepare a list of todos -- Update the todo list while working on the task +- Update the todo list while working on task ## Context @@ -29,12 +30,10 @@ Instead of storing the prompts in the `prompts` folder I would like to store the ### Design decisions -Settled points that aren't otherwise spelled out in the Commands section below: - - **Worktree lifecycle:** every command assumes the `prompt-log` git worktree exists and creates it on demand (same logic as `init-prompt-log`) if it doesn't — don't require the user to run `init-prompt-log` first every time. - **Clipboard copy:** the clipboard-copy step in the current `create-prompt` is dropped entirely, not carried over. - **`repo-path` argument:** wherever `[repo-path]` appears below, it means "operate on a different git repository" (worktree, branch, and `prompt.md` resolved relative to that path) — applied consistently, not just where spelled out under `create-prompt`. -- **`prompt.md.template`:** remove the `${PROMPT_ID}` placeholder (no more numbering) and stop `create-prompt` from exporting `PROMPT_ID`; add the new `prompt_log_commit` frontmatter field, empty by default. +- **`prompt.md.template`:** remove the `${PROMPT_ID}` placeholder (no more numbering) and stop `create-prompt` from exporting `PROMPT_ID`. - **Session token/model capture:** out of scope for this task — `model`, `input_tokens`, `output_tokens` stay manually filled in. ### Commands @@ -53,13 +52,9 @@ Runs the `pi` command and pipes the content of `prompt.md` as query. The harness By default it uses the `prompt.md` of the current directory. It can also take a path to a prompt file. -`store-prompt [repo-path]` +`log-prompt [repo-path]` -Reads the current commit hash (`git rev-parse --short HEAD`) of the project and the content of `prompt.md`. - -If `prompt.md`'s frontmatter has no `prompt_log_commit` set: creates a file named `<commit-hash>-<title-with-dashes-and-lowercase>.md` in the `prompt-log` worktree, storing the content. Commits it with message title `feat: add prompt file` and the filename in the message body. Pushes `prompt-log` to the remote, warning (not failing) if the push doesn't succeed. - -If `prompt.md`'s frontmatter has `prompt_log_commit` set: looks up the prompt file whose name starts with that commit prefix (erroring if ambiguous), updates its content from `prompt.md`, commits with message `feat: update prompt file` and the filename in the body, pushes the same way, and clears `prompt_log_commit` from `prompt.md` on success. +Reads the current commit hash (`git rev-parse --short HEAD`) of the project and the content of `prompt.md`. Creates a file named `<commit-hash>-<title-with-dashes-and-lowercase>.md` in the `prompt-log` worktree, storing the content. Commits it with message title `feat: add prompt file` and the filename in the message body. Pushes `prompt-log` to the remote, warning (not failing) if the push doesn't succeed. `list-prompts [repo-path]` @@ -74,11 +69,15 @@ Rows are sorted by date. `edit-prompt [commit] [repo-path]` -If commit is not given, shows an `fzf` dialog of all files in the `prompt-log` branch, listing the frontmatter title. Selecting a file loads its content into `prompt.md` and opens it in `$EDITOR`. If commit is given, loads that target file directly and opens it in `$EDITOR`. Either way, writes the resolved commit hash into `prompt.md`'s `prompt_log_commit` frontmatter field. The user then runs `store-prompt` to push the update to the `prompt-log` branch. +If commit is not given, shows an `fzf` dialog of all files in the `prompt-log` branch, listing the frontmatter title. Selecting a file opens it directly in `$EDITOR` within the `tmp/prompt-log` worktree. If commit is given, opens that target file directly in `$EDITOR`. After the editor closes, the change is committed with `feat: update prompt file` and pushed (warning on failure). The file is edited in place; `prompt.md` is not involved. + +`show-prompt [commit] [repo-path]` + +Similar to `edit-prompt` but outputs the prompt content directly to stdout instead of opening in `$EDITOR`. Accepts an optional commit prefix or shows an `fzf` dialog when no commit is given. `convert-prompts-folder-to-prompt-log [repo-path]` -Converts an existing `prompts` folder to the new format. For each file, looks up the commit on which it was first added (`git log --follow --diff-filter=A`) and commits it as `<commit-hash>-<title-with-dashes-and-lowercase>.md` in the `prompt-log` branch, using the same commit-message convention as `store-prompt`. Files with no discoverable creation commit are reported and skipped. On success, deletes the old `prompts/` folder and its files. +Converts an existing `prompts` folder to the new format. For each file, looks up the commit on which it was first added (`git log --follow --diff-filter=A`) and commits it as `<commit-hash>-<title-with-dashes-and-lowercase>.md` in the `prompt-log` branch, using the same commit-message convention as `log-prompt`. Files with no discoverable creation commit are reported and skipped. On success, deletes the old `prompts/` folder and its files. ### Alias @@ -87,38 +86,22 @@ Add an alias to each command: - `init-prompt-log` → `ipl` - `create-prompt` → `crp` (existing) - `prompt-with-pi` → `pwp` -- `store-prompt` → `sp` +- `log-prompt` → `lop` - `list-prompts` → `lp` (existing) - `edit-prompt` → `ep` +- `show-prompt` → `shp` - `convert-prompts-folder-to-prompt-log` → `cpfpl` -Check these don't collide with existing aliases elsewhere in the library before finalizing. - ### Docs -This is a major rehaul of the `prompt` commands. Update `library.md` with the commands in the LLM section. - -Then register the help row in the `task.template` file. - -### Test - -You can use this git project to test the commands. Make sure that a normal workflow works: - -```bash -task init-prompt-log -task create-prompt "Test Prompt" -# Assume user runs 'task prompt-with-pi' -# Assume user commits the resulting code changes -task store-prompt -task list-prompts -task edit-prompt $commit_hash -# Assume user edits and saves prompt.md -task store-prompt -task convert-prompts-folder-to-prompt-log -``` +Update `library.md` with the commands in the LLM section. Register the help row in the `task.template` file. ## Worklog -@Clanker Add a summary here once the task has been completed. - -@Clanker Set frontmatter state to completed and update date and model. If you have access to session info also add token count. +- Created new bin scripts: `init-prompt-log`, `prompt-with-pi`, `log-prompt`, `edit-prompt`, `show-prompt`, `convert-prompts-folder-to-prompt-log` +- Rewrote `bin/create-prompt` to output `prompt.md` directly with `author` from git log +- Rewrote `bin/list-prompts` to read from `tmp/prompt-log` worktree +- Updated `prompt.md.template` with `author` field +- Added aliases and verified no collisions with existing aliases +- Tested full workflow: init → create → store → list → edit → show → convert +- Updated `library.md` and `task.template` with all new commands diff --git a/prompt.md.template b/prompt.md.template index fcf7904..64757d7 100644 --- a/prompt.md.template +++ b/prompt.md.template @@ -1,5 +1,6 @@ --- title: "$PROMPT_TITLE" +author: "$PROMPT_AUTHOR" state: draft date_completed: YYYY-MM-DD model: @@ -27,6 +28,6 @@ Note: @Clanker refers to the "ai agent" (you) who is working on this prompt file ## Worklog -@Clanker Add a summary here once the task is completed. +@Clanker Add a summary here once the task has been completed. @Clanker Set frontmatter state to completed and update date and model. If you have access to session info also add token count. diff --git a/task.template b/task.template index 607d68d..0847299 100755 --- a/task.template +++ b/task.template @@ -42,8 +42,14 @@ help-table() { rows+=("commit-with-llm||Commit with llm generated commit message.") rows+=("update-with-llm|<glob><prompt>|Feed files matching glob to LLM and apply changes.") rows+=("update-changelog-with-llm|[num_lines]|Update CHANGELOG.md with changes from staged git diff using LLM.") - rows+=("create-prompt||Create a new prompt file from template.") - rows+=("list-prompts|[path]|List all prompt files.") + rows+=("init-prompt-log||Initialize prompt-log branch and worktree.") + rows+=("create-prompt|<title>[repo-path]|Create prompt.md from template.") + rows+=("prompt-with-pi|[path]|Run pi with prompt.md.") + rows+=("log-prompt|[repo-path]|Log prompt.md to prompt-log branch.") + rows+=("list-prompts|[repo-path]|List prompts from prompt-log branch.") + rows+=("edit-prompt|[commit][repo-path]|Edit prompt directly in prompt-log worktree.") + rows+=("show-prompt|[commit][repo-path]|Show prompt content from prompt-log.") + rows+=("convert-prompts-folder-to-prompt-log|[repo-path]|Convert prompts folder to prompt-log branch.") rows+=("===Logging===| | ") rows+=("log-error||Colored output for errors.") rows+=("log-success||Colored output for success.")