mcpField
F
finalize

finalize

github.com/terrylicaクリエイティブ・メディア190 回インストール1 日前に更新
リポジトリ

finalize について

finalizeは、未処理のasciinema録画を処理するスキルです。録画や実行中のプロセスを検出して停止し、ファイルを検証・zstd圧縮したうえで、orphanブランチへプッシュできます。

主な機能

  1. 01実行中プロセスと未処理録画の検出
  2. 02録画プロセスの通常停止または強制停止
  3. 03録画ファイルの整合性確認
  4. 04zstdによる.castファイルの圧縮
  5. 05任意でプッシュしローカル原本を削除

活用シーン

  1. 01中断後に残った録画の処理
  2. 02選択した録画の圧縮と保管
  3. 03完了した録画のorphanブランチへのプッシュ

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/terrylica/cc-skills --skill finalize

インストール後、Claude Code で/finalizeを入力して読み込まれたか確認します。

同梱ファイルreferences/evolution-log.md

詳細

/asciinema-tools:finalize

孤立した asciinema 録画を確定します。実行中のプロセスを正常に停止し、圧縮して、孤立ブランチにプッシュします。

自己進化するスキル:このスキルは使用を通じて改善されます。指示が誤っていた場合、パラメーターにずれがあった場合、または回避策が必要だった場合は、先延ばしにせず、このファイルをすぐに修正してください。実際に再現できる問題だけを更新してください。

引数

ArgumentDescription
file確定する特定の .cast ファイル
--all未処理の .cast ファイルをすべて確定します
--force正常な停止に失敗した場合は SIGKILL を使用します
--no-push孤立ブランチへのプッシュをスキップします(ローカルのみ)
--keep-local圧縮後もローカルの .cast を保持します

ワークフロー

  1. 検出:実行中の asciinema プロセスと未処理の .cast ファイルを探します
  2. 選択:処理するファイルを AskUserQuestion で確認します
  3. 停止:実行中のプロセスを正常に停止します(SIGTERM → SIGINT → SIGKILL)
  4. 検証:停止後にファイルの整合性を確認します
  5. 圧縮:.cast ファイルを zstd で圧縮します
  6. プッシュ:孤立ブランチにプッシュします(設定されている場合)
  7. クリーンアップ:ローカルの .cast を削除します(任意)

実行

フェーズ 1:検出
/usr/bin/env bash << 'DISCOVER_EOF'
echo "=== Running asciinema processes ==="
PROCS=$(ps aux | grep -E "asciinema rec" | grep -v grep)
if [[ -n "$PROCS" ]]; then
  echo "$PROCS" | while read -r line; do
    PID=$(echo "$line" | awk '{print $2}')
    CAST_FILE=$(echo "$line" | grep -oE '[^ ]+\.cast' | head -1)
    if [[ -n "$CAST_FILE" ]]; then
      SIZE=$(ls -lh "$CAST_FILE" 2>/dev/null | awk '{print $5}' || echo "?")
      echo "PID $PID: $CAST_FILE ($SIZE)"
    else
      echo "PID $PID: (no file detected)"
    fi
  done
else
  echo "No running asciinema processes"
fi

echo ""
echo "=== Unhandled .cast files ==="
find ~/eon -name "*.cast" -size +1M -mtime -30 2>/dev/null | while read -r f; do
  SIZE=$(ls -lh "$f" | awk '{print $5}')
  echo "$f ($SIZE)"
done
DISCOVER_EOF
フェーズ 2:選択
AskUserQuestion:
  question: "Which recordings should be finalized?"
  header: "Select"
  multiSelect: true
  options:
    - label: "All running processes"
      description: "Stop all asciinema rec processes and finalize their files"
    - label: "All unhandled files"
      description: "Finalize all .cast files found in ~/eon"
    - label: "Specific file"
      description: "Enter path to specific .cast file"
フェーズ 3:実行中のプロセスを停止

PID のリストをこのブロックに渡します。ユーザーが /asciinema-tools:finalize を --force 付きで実行した場合は、--force も渡してください。このブロックは自身の引数から --force を解析します。個別の bash ヒアドキュメントは別々のプロセスとして実行されるため、$FORCE は、それを使用する同じブロック内で解決する必要があります(独立した解析フェーズでは、ブロック間で値を引き継げません)。

/usr/bin/env bash << 'STOP_EOF'
# Arguments: PID list, plus optional --force (documented in argument-hint).
# Split flags from PIDs so the documented --force flag actually takes effect.
FORCE=false
PIDS=""
for arg in "$@"; do
  case "$arg" in
    --force) FORCE=true ;;
    *) PIDS="$PIDS $arg" ;;
  esac
done

for PID in $PIDS; do
  echo "Stopping PID $PID..."

  # Try SIGTERM first (graceful)
  kill -TERM "$PID" 2>/dev/null
  sleep 2

  if kill -0 "$PID" 2>/dev/null; then
    echo "  SIGTERM ignored, trying SIGINT..."
    kill -INT "$PID" 2>/dev/null
    sleep 2
  fi

  if kill -0 "$PID" 2>/dev/null; then
    echo "  Process still running. Use --force for SIGKILL"
    # Only SIGKILL with --force flag
    if [[ "$FORCE" == "true" ]]; then
      echo "  Sending SIGKILL (file may be truncated)..."
      kill -9 "$PID" 2>/dev/null
      sleep 1
    fi
  fi

  if ! kill -0 "$PID" 2>/dev/null; then
    echo "  ✓ Process stopped"
  else
    echo "  ✗ Process still running"
  fi
done
STOP_EOF
フェーズ 4:ファイルの整合性チェック
/usr/bin/env bash << 'CHECK_EOF'
CAST_FILE="$1"

echo "Checking file integrity: $CAST_FILE"

# Check if file exists
if [[ ! -f "$CAST_FILE" ]]; then
  echo "  ✗ File not found"
  exit 1
fi

# Check file size
SIZE=$(stat -f%z "$CAST_FILE" 2>/dev/null || stat -c%s "$CAST_FILE")
echo "  Size: $(numfmt --to=iec-i "$SIZE" 2>/dev/null || echo "$SIZE bytes")"

# Check last line (NDJSON should have complete JSON arrays)
LAST_LINE=$(tail -c 500 "$CAST_FILE" | tail -1)
if [[ "$LAST_LINE" == *"]"* ]]; then
  echo "  ✓ File appears complete (ends with JSON array)"
else
  echo "  ⚠ File may be truncated (incomplete JSON)"
  echo "  Note: asciinema 2.0+ streams to disk, so most data is preserved"
fi

# Test with asciinema cat (quick validation)
if timeout 5 asciinema cat "$CAST_FILE" > /dev/null 2>&1; then
  echo "  ✓ File is playable"
else
  echo "  ⚠ File may have issues (but often still usable)"
fi
CHECK_EOF
フェーズ 5:圧縮
/usr/bin/env bash << 'COMPRESS_EOF'
CAST_FILE="$1"
ZSTD_LEVEL="${2:-6}"

echo "Compressing: $CAST_FILE"

OUTPUT="${CAST_FILE}.zst"
if zstd -"$ZSTD_LEVEL" -f "$CAST_FILE" -o "$OUTPUT"; then
  ORIG_SIZE=$(stat -f%z "$CAST_FILE" 2>/dev/null || stat -c%s "$CAST_FILE")
  COMP_SIZE=$(stat -f%z "$OUTPUT" 2>/dev/null || stat -c%s "$OUTPUT")
  RATIO=$(echo "scale=1; $ORIG_SIZE / $COMP_SIZE" | bc 2>/dev/null || echo "?")
  echo "  ✓ Compressed: $(basename "$OUTPUT")"
  echo "  Compression ratio: ${RATIO}:1"
else
  echo "  ✗ Compression failed"
  exit 1
fi
COMPRESS_EOF
フェーズ 6:孤立ブランチにプッシュ
/usr/bin/env bash << 'PUSH_EOF'
COMPRESSED_FILE="$1"
RECORDINGS_DIR="$HOME/asciinema_recordings"

# Find the local recordings clone
REPO_DIR=$(find "$RECORDINGS_DIR" -maxdepth 1 -type d -name "*" | head -1)
if [[ -z "$REPO_DIR" ]] || [[ ! -d "$REPO_DIR/.git" ]]; then
  echo "  ⚠ No orphan branch clone found at $RECORDINGS_DIR"
  echo "  Run /asciinema-tools:bootstrap to set up orphan branch"
  exit 1
fi

echo "Pushing to orphan branch..."

# Copy compressed file
BASENAME=$(basename "$COMPRESSED_FILE")
DEST="$REPO_DIR/recordings/$BASENAME"
mkdir -p "$(dirname "$DEST")"
cp "$COMPRESSED_FILE" "$DEST"

# Commit and push
cd "$REPO_DIR"
git add -A
git commit -m "finalize: $BASENAME" 2>/dev/null || true

# Push with token (prefer env var to avoid process spawning)
GH_TOKEN="${GH_TOKEN:-${GITHUB_TOKEN:-$(gh auth token 2>/dev/null || echo "")}}"
if [[ -n "$GH_TOKEN" ]]; then
  REMOTE_URL=$(git remote get-url origin)
  # Convert to token-authenticated URL
  TOKEN_URL=$(echo "$REMOTE_URL" | sed "s|https://github.com|https://[email protected]|")
  if git push "$TOKEN_URL" HEAD 2>/dev/null; then
    echo "  ✓ Pushed to orphan branch"
  else
    echo "  ✗ Push failed (check credentials)"
  fi
else
  echo "  ⚠ No GitHub token, skipping push"
fi
PUSH_EOF
フェーズ 7:クリーンアップの確認
AskUserQuestion:
  question: "Delete local .cast file after successful compression/push?"
  header: "Cleanup"
  options:
    - label: "Yes, delete local .cast"
      description: "Remove original .cast file (compressed version preserved)"
    - label: "No, keep local"
      description: "Keep both .cast and .cast.zst files"

使用例

# Interactive mode - discover and select
/asciinema-tools:finalize

# Finalize specific file
/asciinema-tools:finalize ~/eon/project/tmp/session.cast

# Finalize all with force stop
/asciinema-tools:finalize --all --force

# Local only (no push)
/asciinema-tools:finalize session.cast --no-push

トラブルシューティング

IssueCauseSolution
プロセスが停止しないasciinema プロセスがハングしているSIGKILL を使用するには --force フラグを指定します
ファイルが切り詰められている可能性がある強制停止によってファイル処理が中断されたほとんどのデータは保持されています。再生してみてください
zstd が見つからないzstd がインストールされていないbrew install zstd
プッシュに失敗したGitHub トークンがないGH_TOKEN を設定するか、gh auth login を実行します
孤立ブランチがないクローンが設定されていないまず /asciinema-tools:bootstrap を実行します
ファイルが見つからないパスが間違っているか、すでに移動されている/daemon-status で確認します

関連コマンド

  • /asciinema-tools:daemon-status - ステータスを表示し、未処理のファイルを探します
  • /asciinema-tools:convert - .cast を解析用の .txt に変換します
  • /asciinema-tools:summarize - 録画を AI で分析します

実行後の振り返り

このスキルの実行が完了したら、タスクを終了する前に振り返ってください。

  1. 現在の場所を確認する。 — 編集前に、この SKILL.md の正式なパスを確認します。
  2. 何が失敗したか? — 原因となった指示を修正します。
  3. 予想以上にうまくいったことは? — 推奨される方法として取り入れます。
  4. 何がずれていたか? — 現状と一致しなくなったスクリプト、参照先、依存関係を修正します。
  5. 記録する。 — きっかけ、修正内容、根拠を進化ログに記録します。

先延ばしにしないでください。次回の実行には、ここに残した状態が引き継がれます。

コメント