feat: redesign prompt log system with worktree-based branch management and update command specifications
This commit is contained in:
13 files changed
+564
-124
No files matched your search
Executable
+101
@@ -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 "$@"
|
||||
}
|
||||
+13
-43
@@ -5,57 +5,27 @@ create-prompt() {
|
||||
|
||||
if [[ -z "$title" ]]; then
|
||||
echo "Error: Title cannot be empty."
|
||||
echo "Usage: task create-prompt <title>"
|
||||
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 "$@"
|
||||
|
||||
Executable
+93
@@ -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 "$@"
|
||||
}
|
||||
Executable
+54
@@ -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 "$@"
|
||||
}
|
||||
+60
-31
@@ -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() {
|
||||
|
||||
Executable
+74
@@ -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 "$@"
|
||||
}
|
||||
Executable
+15
@@ -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 "$@"
|
||||
}
|
||||
Executable
+78
@@ -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 "$@"
|
||||
}
|
||||
File renamed without changes.
+38
-2
@@ -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=== -->
|
||||
|
||||
@@ -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
|
||||
+2
-1
@@ -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.
|
||||
+8
-2
@@ -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.")
|
||||
|
||||
Reference in new issue
Block a user