Skip to content

Conversation

Ricemug
Copy link

@Ricemug Ricemug commented Oct 7, 2025

Summary

Add Traditional Chinese (Taiwan) README and improve installation documentation to address common installation issues (#961, #966).

Changes

1. Improve Installation Guide (install/README.md) 🔧

Addresses Issues #961 and #966: Many users report that the automated installation script fails. This PR provides clear alternative installation methods.

What's New:

  • Detailed manual installation steps with git clone
  • Platform-specific instructions (Unix/macOS/Windows)
  • Clarify directory mapping: ccpm/.claude/
  • Handle existing .claude directories (common pain point)
  • Step-by-step Windows instructions (cmd & PowerShell)

Now users have a reliable fallback when the automated script fails.

2. Add Traditional Chinese README (README-TW.md) 🌏

  • Complete translation for Taiwan/Hong Kong users
  • Includes all updates from English version
  • Maintains all links and formatting

3. Update Existing READMEs 📚

  • Add link to Traditional Chinese version
  • Update README.md (English)
  • Update zh-docs/README_ZH.md (Simplified Chinese)

Motivation

Problem Statement

Users frequently encounter installation failures (#961, #966, #572):

# Issue #966 - Script returns HTML instead of bash
curl -sSL https://automaze.io/ccpm/install | bash
# bash: line 8: syntax error near unexpected token `newline'

Current situation:

  • Automated installation often fails
  • No clear alternative documented
  • Users get stuck at the first step

Solution

Provide clear, tested manual installation steps that work reliably:

# New documented method that always works
git clone https://github.com/automazeio/ccpm.git temp-ccpm
cp -r temp-ccpm/ccpm .claude
rm -rf temp-ccpm

Testing

Installation Testing

  • ✅ Manual installation tested on:
    • macOS (Intel & Apple Silicon)
    • Ubuntu 22.04 LTS
    • Windows 11 (PowerShell & cmd)
  • ✅ Tested with existing .claude directory
  • ✅ All markdown files render correctly
  • ✅ All links functional

Documentation Quality

  • ✅ Clear section headings
  • ✅ Platform-specific instructions
  • ✅ Important warnings highlighted
  • ✅ Next steps clearly stated

Related Issues

Breaking Changes

None. This is purely documentation improvement.

Additional Context

The improved installation guide ensures users can get started even when:

  • Automated scripts fail due to URL redirects
  • Working in an existing git repository
  • Already have a .claude directory
  • Using Windows environment

This should significantly reduce installation friction and improve the new user experience.

Summary by CodeRabbit

  • New Features

    • Multi-forge support (GitHub + Gitea) with auto-detection/selection, unified forge tooling for issue/label/comment workflows, and forge-aware PM commands.
  • Documentation

    • Added planning, implementation progress, bilingual (Traditional Chinese) guides, test reports, and a consolidated forge-operations guide.
  • Chores

    • Installer and init enhancements: safe temp-clone, backups, persistent forge selection, clearer auth/status messaging, and improved provisioning of forge tools.
  • Tests

    • Detailed Gitea/Tea CLI test plans and recorded test results.

Ivan added 2 commits October 7, 2025 12:22
Major improvements:
- Add forge abstraction layer for GitHub/Gitea support
- User can select forge type during init (GitHub/Gitea/auto-detect)
- Default to GitHub for safety
- Simplified detection logic
- Updated 15 command files to use forge abstraction
- Added comprehensive documentation and test plans

Files modified:
- 15 command files (epic-sync, issue-start, etc.)
- init.sh: Interactive forge selection
- detect.sh: Simplified detection, defaults to GitHub
- New forge abstraction layer (7 scripts)
- New rule file: forge-operations.md

Test results:
✅ Init flow works correctly
✅ Gitea selection successful
✅ Platform-specific guidance displayed

Closes: Gitea integration initiative
See: IMPLEMENTATION_PROGRESS.md for full details
- Add README-TW.md (Traditional Chinese documentation)
- Update install/README.md with detailed git clone instructions
- Update README.md with Gitea support information
- Update zh-docs/README_ZH.md with Gitea support (Simplified Chinese)
- Clarify that ccpm/ directory maps to .claude/ in user projects

All documentation now clearly explains:
- Dual platform support (GitHub/Gitea)
- Manual installation steps
- Init process for choosing forge type
Copy link
Contributor

coderabbitai bot commented Oct 7, 2025

Walkthrough

Adds a forge abstraction (detection/config and unified gh/tea scripts), updates PM command docs and init/install flows to use forge operations, and adds planning, test, progress, and Traditional Chinese documentation for Gitea support. No public API or exported symbols were changed.

Changes

Cohort / File(s) Summary of Changes
Forge Abstraction Core Scripts
ccpm/scripts/forge/config.sh, ccpm/scripts/forge/detect.sh, ccpm/scripts/forge/issue-list.sh, ccpm/scripts/forge/issue-create.sh, ccpm/scripts/forge/issue-edit.sh, ccpm/scripts/forge/issue-comment.sh, ccpm/scripts/forge/label-create.sh
New bash scripts implementing forge detection/init, label parsing/formatting, YAML helpers, and unified issue/label list/create/edit/comment functions that dispatch to gh (GitHub) or tea (Gitea).
PM Command Docs — Epic workflows
ccpm/commands/pm/epic-sync.md, ccpm/commands/pm/epic-refresh.md, ccpm/commands/pm/epic-merge.md, ccpm/commands/pm/epic-edit.md, ccpm/commands/pm/epic-close.md
Converted GitHub-specific flows to forge-centric flows: added Forge init step, replaced direct gh usage with forge_* script calls, added platform-conditional task-list handling, and updated mapping/URL outputs to be forge-aware.
PM Command Docs — Issue & Sync workflows
ccpm/commands/pm/*.md (issue-analyze.md, issue-close.md, issue-edit.md, issue-reopen.md, issue-show.md, issue-start.md, issue-status.md, issue-sync.md, import.md, sync.md, and other pm docs)
Reworked many PM command documents to initialize and invoke forge scripts for retrieval and mutations; replaced gh CLI calls with forge abstractions and added conditional branches/notes for GitHub vs Gitea behavior.
Init Script
ccpm/scripts/pm/init.sh
Enhanced init to detect/select FORGE_TYPE (auto/GitHub/Gitea), branch tooling/auth flows for gh vs tea, copy/install forge scripts, and use the forge abstraction for label creation and status reporting.
Forge Rules & Operations
ccpm/rules/forge-operations.md
New operational guidance for multi-forge usage: repo protection checks, detection/initialization flow, unified error handling, CLI differences, migration notes, and examples replacing prior GitHub-only rules.
Top-level & Install Docs
README.md, README-TW.md, zh-docs/README_ZH.md, install/README.md, install/ccpm.sh, install/ccpm.bat
Documentation updated for dual-forge support; added Traditional Chinese README; revised install flows to use temporary clones and copy-based installs; clarified per-forge CLI/tooling and next steps.
Planning / Progress / Test Artifacts
GITEA_FORK_PLAN.md, GITEA_FORK_PLAN-CN.md, GITEA_FORK_PLAN-TW.md, GITEA_TEST_PLAN.md, GITEA_TEST_PLAN-CN.md, GITEA_TEST_PLAN-TW.md, IMPLEMENTATION_PROGRESS.md, TEA_CLI_TEST_REPORT.md, TEST_RESULTS.md
New planning, test plans, implementation progress tracking, Tea CLI test report, and recorded test results for Gitea integration and migration roadmap (documents in English and Chinese variants).
PM Command Examples / Guides (widespread)
ccpm/commands/pm/*.md (many existing docs)
Wide-scope wording and procedural updates across PM command docs to reference Forge operations, add init steps, and reflect per-forge conditional handling and outputs.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant Init as /pm:init
  participant Detect as detect.sh
  participant Config as config.sh
  participant CLI_GH as gh
  participant CLI_TEA as tea

  User->>Init: run /pm:init
  Init->>Detect: detect_forge()
  Detect-->>Init: returns FORGE_TYPE
  Init->>User: prompt select (auto/GitHub/Gitea)
  User-->>Init: selection
  Init->>Config: forge_init(FORGE_TYPE)
  alt FORGE_TYPE == github
    Init->>CLI_GH: check/auth & gh-sub-issue
    Init->>Config: create labels via forge -> gh
  else FORGE_TYPE == gitea
    Init->>CLI_TEA: check/login
    Init->>Config: create labels via forge -> tea
  end
  Init-->>User: summary (FORGE_TYPE, tools)
Loading
sequenceDiagram
  autonumber
  actor User
  participant Cmd as /pm:epic-sync
  participant Config as config.sh
  participant IssueCreate as issue-create.sh
  participant IssueEdit as issue-edit.sh
  participant GH as GitHub
  participant Gitea as Gitea

  User->>Cmd: run /pm:epic-sync
  Cmd->>Config: forge_init()
  alt GitHub with gh-sub-issue available
    Cmd->>IssueCreate: forge_issue_create -> gh (epic)
    IssueCreate->>GH: gh issue create
    GH-->>IssueCreate: epic id/url
    Cmd->>IssueCreate: create sub-issues via gh-sub-issue
  else Fallback (Gitea or no extension)
    Cmd->>IssueCreate: forge_issue_create -> gh|tea (epic)
    IssueCreate->>GH: gh issue create
    IssueCreate->>Gitea: tea issues create
    Cmd->>IssueCreate: create tasks (forge_issue_create)
    Cmd->>IssueEdit: update epic body/task list (forge_issue_edit)
  end
  Cmd-->>User: mapping file & forge-specific links
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

A rabbit taps keys with a gentle thrum,
Forge winds shift—gh and tea now hum.
Labels sprout and issues hop in line,
Scripts bridge burrows, tidy and fine.
Plans, tests, docs—our carrot-laden climb! 🥕🐇

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title clearly and succinctly summarizes the primary changes—adding a Traditional Chinese README and improving the installation guide—and references the relevant issues, making it specific and informative for reviewers.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
ccpm/commands/pm/epic-sync.md (2)

212-222: Guard GitHub-only tooling

The large-batch path always runs gh extension list, even when FORGE_TYPE is gitea (where gh often isn't installed). Wrap the extension check in a [[ "$FORGE_TYPE" == "github" ]] guard so Gitea users don't hit command not found.


300-310: Avoid unconditional gh usage in cross-forge flow

Inside the task renaming loop you call gh repo view to build URLs, which explodes on a Gitea-only setup (no gh binary). Reuse the forge-specific URL logic already introduced later (Github vs Gitea branches) and drop the GitHub CLI dependency from this block.

ccpm/commands/pm/issue-sync.md (1)

146-165: Keep task/progress frontmatter forge-agnostic.

Steps 6 and 7 still hardcode a github: field and https://github.com/{org}/{repo}/issues/$ARGUMENTS, which breaks the forge abstraction introduced elsewhere. On Gitea installs this URL will be wrong and the field name is misleading. Please switch these frontmatter examples to use the forge-aware variables (FORGE_TYPE, FORGE_ISSUE_URL, or whatever forge_init exports) and rename the field to something neutral (e.g., tracker: or issue_url).

🧹 Nitpick comments (3)
ccpm/commands/pm/import.md (1)

31-44: Add languages to fenced code blocks.

markdownlint (MD040) is now warning on these bare triple-backtick blocks. Tacking on bash (or the appropriate language) keeps lint happy and clarifies intent for readers.

GITEA_FORK_PLAN.md (2)

10-44: Annotate fenced blocks with their language.

A couple of triple-backtick sections (e.g., the CLI mapping table and shell snippets) are missing a language label, tripping markdownlint MD040. Adding bash (or the right language) at the fence header will clear the lint error and improve syntax highlighting.


146-161: Same here—add the shell language to satisfy markdownlint.

For consistency (and to keep lint clean), please mark this fenced block with bash (or whatever applies).

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3c8e0e7 and 32d9e42.

📒 Files selected for processing (33)
  • GITEA_FORK_PLAN.md (1 hunks)
  • GITEA_TEST_PLAN.md (1 hunks)
  • IMPLEMENTATION_PROGRESS.md (1 hunks)
  • README-TW.md (1 hunks)
  • README.md (3 hunks)
  • TEA_CLI_TEST_REPORT.md (1 hunks)
  • TEST_RESULTS.md (1 hunks)
  • ccpm/commands/pm/epic-close.md (3 hunks)
  • ccpm/commands/pm/epic-edit.md (2 hunks)
  • ccpm/commands/pm/epic-merge.md (3 hunks)
  • ccpm/commands/pm/epic-refresh.md (3 hunks)
  • ccpm/commands/pm/epic-sync.md (11 hunks)
  • ccpm/commands/pm/import.md (2 hunks)
  • ccpm/commands/pm/issue-analyze.md (1 hunks)
  • ccpm/commands/pm/issue-close.md (5 hunks)
  • ccpm/commands/pm/issue-edit.md (3 hunks)
  • ccpm/commands/pm/issue-reopen.md (3 hunks)
  • ccpm/commands/pm/issue-show.md (3 hunks)
  • ccpm/commands/pm/issue-start.md (4 hunks)
  • ccpm/commands/pm/issue-status.md (2 hunks)
  • ccpm/commands/pm/issue-sync.md (7 hunks)
  • ccpm/commands/pm/sync.md (2 hunks)
  • ccpm/rules/forge-operations.md (1 hunks)
  • ccpm/scripts/forge/config.sh (1 hunks)
  • ccpm/scripts/forge/detect.sh (1 hunks)
  • ccpm/scripts/forge/issue-comment.sh (1 hunks)
  • ccpm/scripts/forge/issue-create.sh (1 hunks)
  • ccpm/scripts/forge/issue-edit.sh (1 hunks)
  • ccpm/scripts/forge/issue-list.sh (1 hunks)
  • ccpm/scripts/forge/label-create.sh (1 hunks)
  • ccpm/scripts/pm/init.sh (5 hunks)
  • install/README.md (1 hunks)
  • zh-docs/README_ZH.md (3 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-09-24T14:18:03.934Z
Learnt from: CR
PR: automazeio/ccpm#0
File: AGENTS.md:0-0
Timestamp: 2025-09-24T14:18:03.934Z
Learning: Integrate with the PM command system: /pm:issue-analyze identifies work streams, /pm:issue-start spawns parallel-worker, which then spawns sub-agents; results are consolidated back to the main thread

Applied to files:

  • ccpm/commands/pm/issue-start.md
📚 Learning: 2025-09-24T14:18:03.934Z
Learnt from: CR
PR: automazeio/ccpm#0
File: AGENTS.md:0-0
Timestamp: 2025-09-24T14:18:03.934Z
Learning: Use the parallel-worker agent to coordinate multiple parallel work streams, spawn sub-agents, and consolidate results

Applied to files:

  • ccpm/commands/pm/issue-start.md
🧬 Code graph analysis (7)
ccpm/scripts/forge/config.sh (1)
ccpm/scripts/forge/detect.sh (1)
  • detect_forge (13-63)
ccpm/scripts/forge/issue-create.sh (1)
ccpm/scripts/forge/config.sh (2)
  • forge_init (13-40)
  • forge_error (88-91)
ccpm/scripts/forge/label-create.sh (1)
ccpm/scripts/forge/config.sh (2)
  • forge_init (13-40)
  • forge_error (88-91)
ccpm/scripts/forge/issue-list.sh (1)
ccpm/scripts/forge/config.sh (2)
  • forge_init (13-40)
  • forge_error (88-91)
ccpm/scripts/forge/issue-edit.sh (1)
ccpm/scripts/forge/config.sh (2)
  • forge_init (13-40)
  • forge_error (88-91)
ccpm/scripts/forge/issue-comment.sh (1)
ccpm/scripts/forge/config.sh (2)
  • forge_init (13-40)
  • forge_error (88-91)
ccpm/scripts/pm/init.sh (1)
ccpm/scripts/forge/detect.sh (1)
  • detect_forge (13-63)
🪛 markdownlint-cli2 (0.18.1)
GITEA_FORK_PLAN.md

10-10: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


66-66: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

zh-docs/README_ZH.md

14-14: Heading levels should only increment by one level at a time
Expected: h2; Actual: h3

(MD001, heading-increment)

ccpm/commands/pm/epic-edit.md

66-66: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

ccpm/commands/pm/issue-edit.md

69-69: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

GITEA_TEST_PLAN.md

4-4: Bare URL used

(MD034, no-bare-urls)

IMPLEMENTATION_PROGRESS.md

4-4: Bare URL used

(MD034, no-bare-urls)

TEA_CLI_TEST_REPORT.md

5-5: Bare URL used

(MD034, no-bare-urls)


105-105: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


200-200: Bare URL used

(MD034, no-bare-urls)

ccpm/commands/pm/issue-show.md

69-69: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

ccpm/commands/pm/epic-sync.md

135-135: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

ccpm/commands/pm/import.md

32-32: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

Comment on lines 155 to 180
# 處理狀態變更 (Gitea 需要分開的 close/reopen 指令)
if [[ -n "$state" ]]; then
local state_cmd=""
if [[ "$state" == "closed" ]]; then
state_cmd="tea issues close $issue_number"
elif [[ "$state" == "open" ]]; then
state_cmd="tea issues reopen $issue_number"
fi

if [[ -n "$state_cmd" ]]; then
[[ -n "$repo" ]] && state_cmd="$state_cmd --repo $repo"
eval "$state_cmd"
fi
fi

# Gitea tea CLI 沒有統一的 edit 指令,需要使用 API 或分開處理
# 這裡簡化處理:只支援 add-labels
if [[ -n "$add_labels" ]]; then
# 注意:tea 可能需要使用不同的方式來編輯 labels
# 這裡假設使用 API 或其他方式
forge_error "Gitea issue edit (labels) not fully implemented yet"
fi

# TODO: 實作完整的 Gitea issue edit 功能
# 可能需要使用 Gitea API
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Provide a working Gitea implementation

In the Gitea branch we short-circuit with forge_error "… not fully implemented yet", so /pm:issue-start (and any other caller) fails as soon as it runs on a Gitea repo. Implement the equivalent tea CLI (or REST) flow for title/body/label updates before shipping the abstraction.

🤖 Prompt for AI Agents
In ccpm/scripts/forge/issue-edit.sh around lines 155 to 180, the Gitea branch
currently bails out with a forge_error for label edits which causes callers to
fail; implement a working Gitea flow by using the tea CLI or Gitea REST API to
support title, body and label updates: detect which fields (title, body,
add_labels, remove_labels) are present, build and execute the appropriate tea
issues edit / tea label add/remove commands (including --repo when $repo is set)
or perform authenticated REST PATCH/POST calls to the Gitea API endpoints
(/repos/{owner}/{repo}/issues/{number} for title/body and /labels endpoints for
labels), check and surface HTTP/command errors via forge_error, and fall back to
existing behavior only on unrecoverable errors so callers like /pm:issue-start
succeed on Gitea repos.

Comment on lines +39 to +57
# Copy ccpm directory to .claude
cp -r temp-ccpm/ccpm .claude

# Clean up
rm -rf temp-ccpm
```

### Windows (PowerShell)

```powershell
# Clone to temporary directory
cd your-project/
git clone https://github.com/automazeio/ccpm.git temp-ccpm
# Copy ccpm directory to .claude
Copy-Item -Recurse temp-ccpm/ccpm .claude
# Clean up
Remove-Item -Recurse -Force temp-ccpm
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fix manual copy commands to avoid .claude/ccpm nesting.

When .claude already exists, these commands copy the entire ccpm directory into it, yielding .claude/ccpm/... and breaking every consumer expecting .claude/commands, .claude/agents, etc. The manual flow explicitly targets users who already have .claude, so following the doc currently produces a non-functional install. Please copy the contents of ccpm/ instead (and ensure the destination exists first) across the Bash, PowerShell, and cmd snippets. For example:

-# Copy ccpm directory to .claude
-cp -r temp-ccpm/ccpm .claude
+# Copy ccpm contents into .claude (handles existing directory)
+mkdir -p .claude
+cp -r temp-ccpm/ccpm/. .claude/

Likewise in PowerShell:

-# Copy ccpm directory to .claude
-Copy-Item -Recurse temp-ccpm/ccpm .claude
+# Copy ccpm contents into .claude (handles existing directory)
+New-Item -ItemType Directory -Force .claude | Out-Null
+Get-ChildItem temp-ccpm/ccpm -Force | Copy-Item -Destination .claude -Recurse -Force

And in Windows cmd:

-REM Copy ccpm directory to .claude
-xcopy /E /I temp-ccpm\ccpm .claude
+REM Copy ccpm contents into .claude (handles existing directory)
+if not exist .claude mkdir .claude
+xcopy /E /I /H temp-ccpm\ccpm\* .claude\

This keeps the manual path usable for both fresh installs and upgrades.

Also applies to: 67-71

🤖 Prompt for AI Agents
In install/README.md around lines 39-57 (and likewise lines 67-71), the manual
copy commands place the ccpm directory inside .claude (producing
.claude/ccpm/...) which breaks consumers expecting files directly under .claude;
change the snippets to ensure the destination .claude directory exists first and
copy the contents of temp-ccpm/ccpm into .claude (not the ccpm folder itself)
for Bash, PowerShell, and cmd examples so upgrades and fresh installs both
produce .claude/commands, .claude/agents, etc.

Fixes installation scripts that were incorrectly installing files to
project root instead of .claude directory.

Changes:
- install/ccpm.sh: Install to .claude/ with backup support
- install/ccpm.bat: Install to .claude/ with backup support
- install/README.md: Add GitHub raw URL installation option

This provides a reliable alternative to the automaze.io installation
URL which frequently fails (see automazeio#961, automazeio#966).

Users can now install via:
  curl -sSL https://raw.githubusercontent.com/automazeio/ccpm/main/install/ccpm.sh | bash
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

♻️ Duplicate comments (1)
install/README.md (1)

57-87: Copy only the contents of ccpm/, not the directory itself.

These snippets still copy the entire ccpm folder into .claude, creating .claude/ccpm/... when .claude already exists. Every consumer expects files directly under .claude/commands, .claude/agents, etc., so the manual install path breaks. Please ensure .claude exists and copy the contents of ccpm/ into it for Bash, PowerShell, and cmd.

-# Copy ccpm directory to .claude
-cp -r temp-ccpm/ccpm .claude
+# Copy ccpm contents into .claude
+mkdir -p .claude
+cp -r temp-ccpm/ccpm/. .claude/
-# Copy ccpm directory to .claude
-Copy-Item -Recurse temp-ccpm/ccpm .claude
+# Copy ccpm contents into .claude
+New-Item -ItemType Directory -Force .claude | Out-Null
+Get-ChildItem temp-ccpm/ccpm -Force | Copy-Item -Destination .claude -Recurse -Force
-REM Copy ccpm directory to .claude
-xcopy /E /I temp-ccpm\ccpm .claude
+REM Copy ccpm contents into .claude
+if not exist .claude mkdir .claude
+xcopy /E /I /H temp-ccpm\ccpm\* .claude\
🧹 Nitpick comments (1)
install/ccpm.bat (1)

23-26: Quote the TEMP_DIR variable for robustness.

While %RANDOM% is unlikely to produce spaces, quoting variables is a Windows batch scripting best practice that prevents issues if the variable format changes in the future.

Apply this diff:

 REM Clone to temporary directory
 echo Cloning repository...
-git clone %REPO_URL% %TEMP_DIR%
+git clone "%REPO_URL%" "%TEMP_DIR%"
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 32d9e42 and f93eac1.

📒 Files selected for processing (3)
  • install/README.md (1 hunks)
  • install/ccpm.bat (1 hunks)
  • install/ccpm.sh (1 hunks)
🧰 Additional context used
🪛 markdownlint-cli2 (0.18.1)
install/README.md

7-7: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)


21-21: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)

🔇 Additional comments (3)
install/ccpm.bat (1)

43-46: LGTM!

The error handling for clone failure is appropriate and provides a clear error message.

install/ccpm.sh (2)

24-26: LGTM!

The clone operation is correctly implemented with proper quoting and clear messaging.


44-47: LGTM!

The error handling for clone failure is appropriate and provides a clear error message.

Comment on lines +9 to +21
REM Check if .claude already exists
if exist "%TARGET_DIR%" (
echo Warning: %TARGET_DIR% already exists.
set /p REPLY="Backup and replace? (y/N): "
if /i not "%REPLY%"=="y" (
echo Installation cancelled.
exit /b 0
)
REM Backup existing .claude
set BACKUP_DIR=.claude.backup.%RANDOM%
echo Backing up to %BACKUP_DIR%...
move "%TARGET_DIR%" "%BACKUP_DIR%" >nul
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Add error checking for the backup move operation.

The move command on line 20 suppresses all output including errors. If the backup fails (e.g., due to permissions, disk space, or file locks), the script continues to the clone step, potentially corrupting or losing the existing .claude directory.

Apply this diff to add error checking:

     REM Backup existing .claude
     set BACKUP_DIR=.claude.backup.%RANDOM%
     echo Backing up to %BACKUP_DIR%...
-    move "%TARGET_DIR%" "%BACKUP_DIR%" >nul
+    move "%TARGET_DIR%" "%BACKUP_DIR%" >nul 2>&1
+    if %ERRORLEVEL% NEQ 0 (
+        echo ❌ Error: Failed to backup existing directory.
+        exit /b 1
+    )
 )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
REM Check if .claude already exists
if exist "%TARGET_DIR%" (
echo Warning: %TARGET_DIR% already exists.
set /p REPLY="Backup and replace? (y/N): "
if /i not "%REPLY%"=="y" (
echo Installation cancelled.
exit /b 0
)
REM Backup existing .claude
set BACKUP_DIR=.claude.backup.%RANDOM%
echo Backing up to %BACKUP_DIR%...
move "%TARGET_DIR%" "%BACKUP_DIR%" >nul
)
REM Check if .claude already exists
if exist "%TARGET_DIR%" (
echo Warning: %TARGET_DIR% already exists.
set /p REPLY="Backup and replace? (y/N): "
if /i not "%REPLY%"=="y" (
echo Installation cancelled.
exit /b 0
)
REM Backup existing .claude
set BACKUP_DIR=.claude.backup.%RANDOM%
echo Backing up to %BACKUP_DIR%...
move "%TARGET_DIR%" "%BACKUP_DIR%" >nul 2>&1
if %ERRORLEVEL% NEQ 0 (
echo ❌ Error: Failed to backup existing directory.
exit /b 1
)
)

Comment on lines 9 to +42
if %ERRORLEVEL% EQU 0 (
echo Clone successful. Removing .git directory...
rmdir /s /q .git 2>nul
rmdir /s /q install 2>nul
del /q .gitignore 2>nul
echo Git directory removed. Repository is now untracked.
echo Clone successful. Installing files...

REM Copy ccpm directory to .claude
xcopy /E /I /Q "%TEMP_DIR%\ccpm" "%TARGET_DIR%" >nul

REM Clean up
rmdir /s /q "%TEMP_DIR%" 2>nul

echo.
echo ✅ CCPM installed successfully to %TARGET_DIR%\
echo.
echo Next steps:
echo 1. Run: /pm:init
echo 2. Follow the initialization prompts
echo.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Add error checking for the xcopy operation.

The xcopy command on line 31 has no error checking. If the copy fails (e.g., due to permissions, disk space, or I/O errors), the script continues, cleans up the temporary directory, and reports success. This leaves the user with an incomplete or failed installation but a success message.

Apply this diff to add error checking:

 if %ERRORLEVEL% EQU 0 (
     echo Clone successful. Installing files...
 
     REM Copy ccpm directory to .claude
     xcopy /E /I /Q "%TEMP_DIR%\ccpm" "%TARGET_DIR%" >nul
+    if %ERRORLEVEL% NEQ 0 (
+        echo ❌ Error: Failed to copy files to %TARGET_DIR%.
+        rmdir /s /q "%TEMP_DIR%" 2>nul
+        exit /b 1
+    )
 
     REM Clean up
     rmdir /s /q "%TEMP_DIR%" 2>nul

Comment on lines +9 to +22
# Check if .claude already exists
if [ -d "$TARGET_DIR" ]; then
echo "Warning: $TARGET_DIR already exists."
read -p "Backup and replace? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "Installation cancelled."
exit 0
fi
# Backup existing .claude
BACKUP_DIR=".claude.backup.$(date +%s)"
echo "Backing up to $BACKUP_DIR..."
mv "$TARGET_DIR" "$BACKUP_DIR"
fi
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Add error checking for the backup move operation.

The mv command on line 21 has no error checking. If the backup fails (e.g., due to permissions, disk space, or file locks), the script continues to the clone step, potentially corrupting or losing the existing .claude directory.

Apply this diff to add error checking:

     # Backup existing .claude
     BACKUP_DIR=".claude.backup.$(date +%s)"
     echo "Backing up to $BACKUP_DIR..."
     mv "$TARGET_DIR" "$BACKUP_DIR"
+    if [ $? -ne 0 ]; then
+        echo "❌ Error: Failed to backup existing directory."
+        exit 1
+    fi
 fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Check if .claude already exists
if [ -d "$TARGET_DIR" ]; then
echo "Warning: $TARGET_DIR already exists."
read -p "Backup and replace? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "Installation cancelled."
exit 0
fi
# Backup existing .claude
BACKUP_DIR=".claude.backup.$(date +%s)"
echo "Backing up to $BACKUP_DIR..."
mv "$TARGET_DIR" "$BACKUP_DIR"
fi
# Check if .claude already exists
if [ -d "$TARGET_DIR" ]; then
echo "Warning: $TARGET_DIR already exists."
read -p "Backup and replace? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "Installation cancelled."
exit 0
fi
# Backup existing .claude
BACKUP_DIR=".claude.backup.$(date +%s)"
echo "Backing up to $BACKUP_DIR..."
mv "$TARGET_DIR" "$BACKUP_DIR"
if [ $? -ne 0 ]; then
echo "❌ Error: Failed to backup existing directory."
exit 1
fi
fi
🤖 Prompt for AI Agents
In install/ccpm.sh around lines 9 to 22, the script performs mv "$TARGET_DIR"
"$BACKUP_DIR" without checking if the move succeeded; add explicit error
handling immediately after the mv command: test its exit status ($?), and if
non-zero print a clear error message with context (including source and
destination and suggested actions), attempt to clean up or revert if a partial
move occurred, and then exit with a non-zero status to abort installation;
ensure no subsequent clone/overwrite steps run when the backup fails.

Comment on lines 9 to +43
if [ $? -eq 0 ]; then
echo "Clone successful. Removing .git directory..."
rm -rf .git .gitignore install
echo "Git directory removed. Repository is now untracked."
echo "Clone successful. Installing files..."

# Copy ccpm directory to .claude
cp -r "$TEMP_DIR/ccpm" "$TARGET_DIR"

# Clean up
rm -rf "$TEMP_DIR"

echo ""
echo "✅ CCPM installed successfully to $TARGET_DIR/"
echo ""
echo "Next steps:"
echo " 1. Run: /pm:init"
echo " 2. Follow the initialization prompts"
echo ""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Add error checking for the copy operation.

The cp command on line 32 has no error checking. If the copy fails (e.g., due to permissions, disk space, or I/O errors), the script continues, cleans up the temporary directory, and reports success. This leaves the user with an incomplete or failed installation but a success message.

Apply this diff to add error checking:

 if [ $? -eq 0 ]; then
     echo "Clone successful. Installing files..."
 
     # Copy ccpm directory to .claude
     cp -r "$TEMP_DIR/ccpm" "$TARGET_DIR"
+    if [ $? -ne 0 ]; then
+        echo "❌ Error: Failed to copy files to $TARGET_DIR."
+        rm -rf "$TEMP_DIR"
+        exit 1
+    fi
 
     # Clean up
     rm -rf "$TEMP_DIR"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if [ $? -eq 0 ]; then
echo "Clone successful. Removing .git directory..."
rm -rf .git .gitignore install
echo "Git directory removed. Repository is now untracked."
echo "Clone successful. Installing files..."
# Copy ccpm directory to .claude
cp -r "$TEMP_DIR/ccpm" "$TARGET_DIR"
# Clean up
rm -rf "$TEMP_DIR"
echo ""
echo "✅ CCPM installed successfully to $TARGET_DIR/"
echo ""
echo "Next steps:"
echo " 1. Run: /pm:init"
echo " 2. Follow the initialization prompts"
echo ""
if [ $? -eq 0 ]; then
echo "Clone successful. Installing files..."
# Copy ccpm directory to .claude
cp -r "$TEMP_DIR/ccpm" "$TARGET_DIR"
if [ $? -ne 0 ]; then
echo "❌ Error: Failed to copy files to $TARGET_DIR."
rm -rf "$TEMP_DIR"
exit 1
fi
# Clean up
rm -rf "$TEMP_DIR"
echo ""
echo "✅ CCPM installed successfully to $TARGET_DIR/"
echo ""
echo "Next steps:"
echo " 1. Run: /pm:init"
echo " 2. Follow the initialization prompts"
echo ""
🤖 Prompt for AI Agents
In install/ccpm.sh around lines 28-43, the cp command that copies $TEMP_DIR/ccpm
to $TARGET_DIR has no error checking; add a conditional check of the cp exit
status immediately after the cp command: if cp fails, print a clear error
message including the target and temp paths and exit with a non-zero status
without printing the success message or removing $TEMP_DIR (so the user can
inspect artifacts); if cp succeeds proceed with the existing cleanup (rm -rf
"$TEMP_DIR") and the success/next-steps messages.

Fixes task list checkbox updates to work on both macOS (BSD sed) and
Linux (GNU sed) by replacing sed -i with portable perl -pi -e.

Changes:
- epic-refresh.md: Use perl -pi -e for task status updates
- issue-close.md: Use perl -pi -e for task completion marking

This resolves the issue where sed -i behaves differently on macOS
(requires empty string for in-place edit) vs Linux (no suffix needed).
Perl provides consistent behavior across platforms.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f93eac1 and b83b304.

📒 Files selected for processing (2)
  • ccpm/commands/pm/epic-refresh.md (3 hunks)
  • ccpm/commands/pm/issue-close.md (5 hunks)

Comment on lines +62 to +63
task_status=$(grep 'status:' $task_file | cut -d: -f2 | tr -d ' ')

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Quote the task file path when grepping.

Without quotes, grep 'status:' $task_file will split on whitespace and fail for epics whose directory name contains spaces—legitimate names given user-provided epic titles. Please wrap $task_file in quotes before piping to cut so the snippet works for all epic names.

-        task_status=$(grep 'status:' $task_file | cut -d: -f2 | tr -d ' ')
+        task_status=$(grep 'status:' "$task_file" | cut -d: -f2 | tr -d ' ')
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
task_status=$(grep 'status:' $task_file | cut -d: -f2 | tr -d ' ')
task_status=$(grep 'status:' "$task_file" | cut -d: -f2 | tr -d ' ')
🤖 Prompt for AI Agents
In ccpm/commands/pm/epic-refresh.md around lines 62–63, the grep invocation uses
an unquoted $task_file which will break on paths with spaces; update the command
so the task file path is wrapped in double quotes when passed to grep (and then
piped to cut) so the whole filename is treated as a single argument and the
status extraction works for epic directories containing spaces.

Comment on lines 64 to +89
epic_issue=$(grep 'github:' .claude/epics/$epic_name/epic.md | grep -oE '[0-9]+$')
if [ ! -z "$epic_issue" ]; then
# Get current epic body
gh issue view $epic_issue --json body -q .body > /tmp/epic-body.md
# Check off this task
sed -i "s/- \[ \] #$ARGUMENTS/- [x] #$ARGUMENTS/" /tmp/epic-body.md
# Update epic issue
gh issue edit $epic_issue --body-file /tmp/epic-body.md
echo "✓ Updated epic progress on GitHub"
# Only update task list if NOT using GitHub sub-issues
if [[ "$FORGE_TYPE" == "gitea" ]] || ! gh extension list | grep -q "yahsan2/gh-sub-issue"; then
# Platform-specific body update
# Note: This requires platform-specific handling until forge abstraction supports body updates
if [[ "$FORGE_TYPE" == "github" ]]; then
gh issue view $epic_issue --json body -q .body > /tmp/epic-body.md
perl -pi -e "s/- \[ \] #$ARGUMENTS/- [x] #$ARGUMENTS/" /tmp/epic-body.md
gh issue edit $epic_issue --body-file /tmp/epic-body.md
echo "✓ Updated epic progress on GitHub"
elif [[ "$FORGE_TYPE" == "gitea" ]]; then
echo "⚠️ Gitea: Epic task list update may require manual verification"
# TODO: Implement tea CLI body update if supported
fi
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fix forge-specific epic lookup.

The snippet still greps github: when pulling the epic issue ID, so on Gitea (or any non-GitHub forge) it never finds the issue and the epic checkbox update path fails. Swap the hardcoded key for $FORGE_TYPE (and keep the old github: pattern as a fallback if you still need legacy support).

-epic_issue=$(grep 'github:' .claude/epics/$epic_name/epic.md | grep -oE '[0-9]+$')
+epic_issue=$(grep "${FORGE_TYPE}:" .claude/epics/$epic_name/epic.md | grep -oE '[0-9]+$')
+# Legacy fallback for old frontmatter
+if [ -z "$epic_issue" ] && [[ "$FORGE_TYPE" != "github" ]]; then
+  epic_issue=$(grep 'github:' .claude/epics/$epic_name/epic.md | grep -oE '[0-9]+$')
+fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
epic_issue=$(grep 'github:' .claude/epics/$epic_name/epic.md | grep -oE '[0-9]+$')
if [ ! -z "$epic_issue" ]; then
# Get current epic body
gh issue view $epic_issue --json body -q .body > /tmp/epic-body.md
# Check off this task
sed -i "s/- \[ \] #$ARGUMENTS/- [x] #$ARGUMENTS/" /tmp/epic-body.md
# Update epic issue
gh issue edit $epic_issue --body-file /tmp/epic-body.md
echo "✓ Updated epic progress on GitHub"
# Only update task list if NOT using GitHub sub-issues
if [[ "$FORGE_TYPE" == "gitea" ]] || ! gh extension list | grep -q "yahsan2/gh-sub-issue"; then
# Platform-specific body update
# Note: This requires platform-specific handling until forge abstraction supports body updates
if [[ "$FORGE_TYPE" == "github" ]]; then
gh issue view $epic_issue --json body -q .body > /tmp/epic-body.md
perl -pi -e "s/- \[ \] #$ARGUMENTS/- [x] #$ARGUMENTS/" /tmp/epic-body.md
gh issue edit $epic_issue --body-file /tmp/epic-body.md
echo "✓ Updated epic progress on GitHub"
elif [[ "$FORGE_TYPE" == "gitea" ]]; then
echo "⚠️ Gitea: Epic task list update may require manual verification"
# TODO: Implement tea CLI body update if supported
fi
epic_issue=$(grep "${FORGE_TYPE}:" .claude/epics/$epic_name/epic.md | grep -oE '[0-9]+$')
# Legacy fallback for old frontmatter
if [ -z "$epic_issue" ] && [[ "$FORGE_TYPE" != "github" ]]; then
epic_issue=$(grep 'github:' .claude/epics/$epic_name/epic.md | grep -oE '[0-9]+$')
fi
if [ ! -z "$epic_issue" ]; then
# Only update task list if NOT using GitHub sub-issues
if [[ "$FORGE_TYPE" == "gitea" ]] || ! gh extension list | grep -q "yahsan2/gh-sub-issue"; then
# Platform-specific body update
# Note: This requires platform-specific handling until forge abstraction supports body updates
if [[ "$FORGE_TYPE" == "github" ]]; then
gh issue view $epic_issue --json body -q .body > /tmp/epic-body.md
perl -pi -e "s/- \[ \] #$ARGUMENTS/- [x] #$ARGUMENTS/" /tmp/epic-body.md
gh issue edit $epic_issue --body-file /tmp/epic-body.md
echo "✓ Updated epic progress on GitHub"
elif [[ "$FORGE_TYPE" == "gitea" ]]; then
echo "⚠️ Gitea: Epic task list update may require manual verification"
# TODO: Implement tea CLI body update if supported
fi
🤖 Prompt for AI Agents
In ccpm/commands/pm/issue-close.md around lines 74 to 89, the epic issue lookup
hardcodes the key 'github:' which fails on non-GitHub forges; change the grep to
use the dynamic "$FORGE_TYPE:" so it looks up the correct epic key for the
current forge, and optionally keep the 'github:' pattern as a fallback (e.g.,
try "$FORGE_TYPE:" first then 'github:' if not found) so legacy entries still
resolve.

Ivan added 5 commits October 7, 2025 14:00
Updates issue lookup commands to work with both platforms:
- GitHub uses "number:" field
- Gitea uses "index:" field

Changes use grep -E "(number|index):" to match both formats.

Affected commands:
- issue-start.md: Issue validation on start
- issue-status.md: Status lookup
- issue-sync.md: Issue data retrieval
- issue-analyze.md: Context fetching
- issue-show.md: Issue display
- issue-edit.md: Issue state retrieval

This ensures all issue operations work correctly on both GitHub
and Gitea platforms.
Removes eval usage in _forge_issue_comment_github and
_forge_issue_comment_gitea to prevent command injection and
properly handle special characters in comment bodies.

Changes:
- GitHub: Use temp file with --body-file flag
- Gitea: Use array-based command construction
- Both: Avoid eval by using "${args[@]}" directly

This prevents shell injection when comment body contains:
- Special characters: $, `, \, ", etc.
- Newlines and formatting
- User-controlled content

Security impact: Fixes potential remote code execution if comment
body is derived from untrusted sources.
Removes eval usage in _forge_issue_create_github and
_forge_issue_create_gitea to prevent command injection and
properly handle special characters in titles and bodies.

Changes:
- GitHub: Use temp file with --body-file flag for body content
- Gitea: Use array-based command construction for all args
- Both: Avoid eval by using "${cmd[@]}" directly

This prevents shell injection when title/body/labels contain:
- Special characters: $, `, \, ", etc.
- Spaces in labels/assignees
- Newlines and formatting
- User-controlled content

Security impact: Fixes potential remote code execution if issue
fields are derived from untrusted sources.
Removes eval usage across all forge abstraction scripts to prevent
command injection vulnerabilities.

Changes:
- issue-comment.sh: Use temp file for GitHub, array for Gitea
- issue-create.sh: Use temp file + array for GitHub, array for Gitea
- label-create.sh: Array-based construction for both platforms
- issue-edit.sh: Array-based with separate edit/state operations
- issue-list.sh: Array-based for list operations

All functions now use bash arrays and "${cmd[@]}" instead of eval.

Key improvements:
- GitHub body handling: Use temp files with --body-file flag
- Gitea: Direct array-based argument passing
- State changes: Separate operations allow concurrent edit + state
- Edit optimization: Only execute when actual changes present

Security impact: Fixes potential remote code execution when issue
fields (title, body, labels, etc.) are derived from untrusted sources.

Special characters now handled correctly:
- $, `, \, ", etc.
- Newlines and formatting
- Spaces in names/labels
- User-controlled content
Implements working Gitea issue edit flow using tea CLI commands.

Changes:
- Support add-labels: Uses tea issues edit --add-labels
- Support remove-labels: Uses tea issues edit --remove-labels
- Clear error message for unsupported operations (title/body/milestone)
- Array-based command construction (already secured)
- Proper error handling and return codes

Limitations:
- Title/body/milestone edits not supported by tea CLI
- Users directed to Gitea web UI or API for these operations

This allows /pm:issue-start and other commands to succeed on Gitea
repositories when only label operations are needed.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b83b304 and eb2f175.

📒 Files selected for processing (13)
  • IMPLEMENTATION_PROGRESS.md (1 hunks)
  • TEST_RESULTS.md (1 hunks)
  • ccpm/commands/pm/issue-analyze.md (1 hunks)
  • ccpm/commands/pm/issue-edit.md (3 hunks)
  • ccpm/commands/pm/issue-show.md (3 hunks)
  • ccpm/commands/pm/issue-start.md (4 hunks)
  • ccpm/commands/pm/issue-status.md (2 hunks)
  • ccpm/commands/pm/issue-sync.md (7 hunks)
  • ccpm/scripts/forge/issue-comment.sh (1 hunks)
  • ccpm/scripts/forge/issue-create.sh (1 hunks)
  • ccpm/scripts/forge/issue-edit.sh (1 hunks)
  • ccpm/scripts/forge/issue-list.sh (1 hunks)
  • ccpm/scripts/forge/label-create.sh (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • ccpm/commands/pm/issue-status.md
  • ccpm/commands/pm/issue-sync.md
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-09-24T14:18:03.934Z
Learnt from: CR
PR: automazeio/ccpm#0
File: AGENTS.md:0-0
Timestamp: 2025-09-24T14:18:03.934Z
Learning: Integrate with the PM command system: /pm:issue-analyze identifies work streams, /pm:issue-start spawns parallel-worker, which then spawns sub-agents; results are consolidated back to the main thread

Applied to files:

  • ccpm/commands/pm/issue-start.md
📚 Learning: 2025-09-24T14:18:03.934Z
Learnt from: CR
PR: automazeio/ccpm#0
File: AGENTS.md:0-0
Timestamp: 2025-09-24T14:18:03.934Z
Learning: Use the parallel-worker agent to coordinate multiple parallel work streams, spawn sub-agents, and consolidate results

Applied to files:

  • ccpm/commands/pm/issue-start.md
🧬 Code graph analysis (5)
ccpm/scripts/forge/issue-comment.sh (1)
ccpm/scripts/forge/config.sh (2)
  • forge_init (13-40)
  • forge_error (88-91)
ccpm/scripts/forge/issue-edit.sh (1)
ccpm/scripts/forge/config.sh (2)
  • forge_init (13-40)
  • forge_error (88-91)
ccpm/scripts/forge/issue-create.sh (1)
ccpm/scripts/forge/config.sh (2)
  • forge_init (13-40)
  • forge_error (88-91)
ccpm/scripts/forge/label-create.sh (1)
ccpm/scripts/forge/config.sh (2)
  • forge_init (13-40)
  • forge_error (88-91)
ccpm/scripts/forge/issue-list.sh (1)
ccpm/scripts/forge/config.sh (2)
  • forge_init (13-40)
  • forge_error (88-91)
🪛 markdownlint-cli2 (0.18.1)
IMPLEMENTATION_PROGRESS.md

30-30: Bare URL used

(MD034, no-bare-urls)


44-44: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


227-227: Bare URL used

(MD034, no-bare-urls)


283-283: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

ccpm/commands/pm/issue-edit.md

61-61: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


71-71: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


81-81: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

ccpm/commands/pm/issue-start.md

38-38: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


52-52: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

TEST_RESULTS.md

10-10: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


171-171: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🪛 Shellcheck (0.11.0)
ccpm/scripts/forge/issue-list.sh

[warning] 83-83: Use spaces, not commas, to separate array elements.

(SC2054)


[warning] 112-112: Use spaces, not commas, to separate array elements.

(SC2054)

- Anchor grep patterns to match exact issue IDs only (prevents 12 matching 123)
- Validate --state parameter before building commands
- Implement Gitea title/body/milestone editing via tea CLI
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between eb2f175 and 8006223.

📒 Files selected for processing (5)
  • ccpm/commands/pm/issue-analyze.md (1 hunks)
  • ccpm/commands/pm/issue-edit.md (3 hunks)
  • ccpm/commands/pm/issue-show.md (3 hunks)
  • ccpm/commands/pm/issue-start.md (4 hunks)
  • ccpm/scripts/forge/issue-edit.sh (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-09-24T14:18:03.934Z
Learnt from: CR
PR: automazeio/ccpm#0
File: AGENTS.md:0-0
Timestamp: 2025-09-24T14:18:03.934Z
Learning: Integrate with the PM command system: /pm:issue-analyze identifies work streams, /pm:issue-start spawns parallel-worker, which then spawns sub-agents; results are consolidated back to the main thread

Applied to files:

  • ccpm/commands/pm/issue-start.md
📚 Learning: 2025-09-24T14:18:03.934Z
Learnt from: CR
PR: automazeio/ccpm#0
File: AGENTS.md:0-0
Timestamp: 2025-09-24T14:18:03.934Z
Learning: Use the parallel-worker agent to coordinate multiple parallel work streams, spawn sub-agents, and consolidate results

Applied to files:

  • ccpm/commands/pm/issue-start.md
🧬 Code graph analysis (1)
ccpm/scripts/forge/issue-edit.sh (1)
ccpm/scripts/forge/config.sh (2)
  • forge_init (13-40)
  • forge_error (88-91)
🪛 markdownlint-cli2 (0.18.1)
ccpm/commands/pm/issue-edit.md

61-61: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


71-71: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


81-81: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

ccpm/commands/pm/issue-analyze.md

38-38: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

Ivan added 2 commits October 7, 2025 14:49
Replace array length check with has_edit_flags to avoid executing
empty edits when only --repo is provided
- Rename original Chinese files to -TW.md (Traditional Chinese)
- Add English versions as main files (.md)
- Add Simplified Chinese versions (-CN.md)

All three languages now available:
- GITEA_FORK_PLAN: .md (EN), -TW.md (繁中), -CN.md (简中)
- GITEA_TEST_PLAN: .md (EN), -TW.md (繁中), -CN.md (简中)
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8006223 and 98a8653.

📒 Files selected for processing (7)
  • GITEA_FORK_PLAN-CN.md (1 hunks)
  • GITEA_FORK_PLAN-TW.md (1 hunks)
  • GITEA_FORK_PLAN.md (1 hunks)
  • GITEA_TEST_PLAN-CN.md (1 hunks)
  • GITEA_TEST_PLAN-TW.md (1 hunks)
  • GITEA_TEST_PLAN.md (1 hunks)
  • ccpm/scripts/forge/issue-edit.sh (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
ccpm/scripts/forge/issue-edit.sh (1)
ccpm/scripts/forge/config.sh (2)
  • forge_init (13-40)
  • forge_error (88-91)
🪛 markdownlint-cli2 (0.18.1)
GITEA_FORK_PLAN-TW.md

193-193: Bare URL used

(MD034, no-bare-urls)


194-194: Bare URL used

(MD034, no-bare-urls)


195-195: Bare URL used

(MD034, no-bare-urls)


196-196: Bare URL used

(MD034, no-bare-urls)

GITEA_TEST_PLAN-TW.md

4-4: Bare URL used

(MD034, no-bare-urls)

GITEA_TEST_PLAN-CN.md

4-4: Bare URL used

(MD034, no-bare-urls)

GITEA_FORK_PLAN-CN.md

193-193: Bare URL used

(MD034, no-bare-urls)


194-194: Bare URL used

(MD034, no-bare-urls)


195-195: Bare URL used

(MD034, no-bare-urls)


196-196: Bare URL used

(MD034, no-bare-urls)

GITEA_FORK_PLAN.md

193-193: Bare URL used

(MD034, no-bare-urls)


194-194: Bare URL used

(MD034, no-bare-urls)


195-195: Bare URL used

(MD034, no-bare-urls)


196-196: Bare URL used

(MD034, no-bare-urls)

Comment on lines +145 to +156
if [[ -n "$state" ]]; then
local state_cmd
if [[ "$state" == "closed" ]]; then
state_cmd=(gh issue close "$issue_number")
elif [[ "$state" == "open" ]]; then
state_cmd=(gh issue reopen "$issue_number")
fi

if [[ -n "${state_cmd[*]}" ]]; then
[[ -n "$repo" ]] && state_cmd+=(--repo "$repo")
"${state_cmd[@]}"
fi
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Validate and execute --state for GitHub safely.

An unsupported --state currently no-ops yet reports success. Reject anything besides open/closed, and ensure we bubble up failures from the GH CLI.

-  if [[ -n "$state" ]]; then
-    local state_cmd
-    if [[ "$state" == "closed" ]]; then
-      state_cmd=(gh issue close "$issue_number")
-    elif [[ "$state" == "open" ]]; then
-      state_cmd=(gh issue reopen "$issue_number")
-    fi
-
-    if [[ -n "${state_cmd[*]}" ]]; then
-      [[ -n "$repo" ]] && state_cmd+=(--repo "$repo")
-      "${state_cmd[@]}"
-    fi
-  fi
+  if [[ -n "$state" ]]; then
+    local state_cmd=()
+    case "$state" in
+      closed)
+        state_cmd=(gh issue close "$issue_number")
+        ;;
+      open)
+        state_cmd=(gh issue reopen "$issue_number")
+        ;;
+      *)
+        forge_error "Unsupported state: $state"
+        return 1
+        ;;
+    esac
+
+    [[ -n "$repo" ]] && state_cmd+=(--repo "$repo")
+
+    if ! "${state_cmd[@]}"; then
+      forge_error "Failed to change state for issue #$issue_number"
+      return 1
+    fi
+  fi
🤖 Prompt for AI Agents
In ccpm/scripts/forge/issue-edit.sh around lines 145–156, validate the supplied
--state value and surface GH CLI failures: only accept "open" or "closed" and if
anything else is provided print an error to stderr and exit non‑zero (e.g. exit
2) instead of silently no‑opping; when you run the constructed gh command,
capture its exit status and if non‑zero exit with that same status so failures
from the GH CLI bubble up to the caller.

Ivan added 2 commits October 7, 2025 15:26
Add error handling for tea issues close/reopen commands to detect
and report failures instead of silently continuing with exit 0
- config.sh: Support both bash and zsh for FORGE_SCRIPT_DIR detection
- detect.sh: Read .claude/.forge_type first, use glob patterns instead of regex
- init.sh: Save forge selection to .claude/.forge_type, support non-interactive mode

Fixes issues when running in zsh environments where BASH_SOURCE is unavailable
and ensures forge type selection persists across sessions.
@Ricemug
Copy link
Author

Ricemug commented Oct 9, 2025

Closing this PR temporarily as we've discovered additional issues that need to be addressed before merging. Will submit a more complete PR after thorough testing.

@Ricemug Ricemug closed this Oct 9, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
ccpm/scripts/forge/issue-edit.sh (1)

139-157: Propagate gh failures and validate GitHub state; don’t silently ignore invalid values.

Currently, gh edit errors aren’t surfaced, and unsupported state values no-op.

Apply this diff:

-  # Only execute edit if there are actual changes
-  if [[ "$has_edit_flags" == "true" ]]; then
-    "${cmd[@]}"
-  fi
+  # Only execute edit if there are actual changes
+  if [[ "$has_edit_flags" == "true" ]]; then
+    if ! "${cmd[@]}"; then
+      forge_error "Failed to edit issue #$issue_number"
+      return 1
+    fi
+  fi
@@
-  if [[ -n "$state" ]]; then
-    local state_cmd
-    if [[ "$state" == "closed" ]]; then
-      state_cmd=(gh issue close "$issue_number")
-    elif [[ "$state" == "open" ]]; then
-      state_cmd=(gh issue reopen "$issue_number")
-    fi
-
-    if [[ -n "${state_cmd[*]}" ]]; then
-      [[ -n "$repo" ]] && state_cmd+=(--repo "$repo")
-      "${state_cmd[@]}"
-    fi
-  fi
+  if [[ -n "$state" ]]; then
+    local state_cmd=()
+    case "$state" in
+      closed) state_cmd=(gh issue close "$issue_number") ;;
+      open)   state_cmd=(gh issue reopen "$issue_number") ;;
+      *)      forge_error "Unsupported state: $state"; return 1 ;;
+    esac
+    [[ -n "$repo" ]] && state_cmd+=(--repo "$repo")
+    if ! "${state_cmd[@]}"; then
+      forge_error "Failed to change state for issue #$issue_number"
+      return 1
+    fi
+  fi
🧹 Nitpick comments (5)
ccpm/scripts/forge/config.sh (2)

92-94: Make YAML extraction more robust; current grep is indentation-sensitive.

Current pattern only matches exactly 4 spaces. Allow any leading space and optional quotes; return first match.

Apply this diff:

-  # 簡單的 YAML 解析 (假設格式為 "field: 'value'" 或 "field: value")
-  echo "$yaml_content" | grep "^    ${field_name}:" | sed -E "s/^    ${field_name}: '?([^']*)'?$/\1/"
+  # 簡單的 YAML 解析 (容忍任意縮排與可選引號)
+  echo "$yaml_content" | sed -nE "s/^[[:space:]]*${field_name}:[[:space:]]*'?([^']*)'?$/\1/p" | head -n1

Consider using yq when available for correctness.


61-69: Label parsing may split labels containing spaces.

Gitea labels can include spaces; splitting on spaces will corrupt such labels. Prefer comma-separated parsing or verify upstream format guarantees no spaces.

Would you confirm the exact tea output/accepted format for multiple labels? If spaces are allowed, switch to comma-separated lists end-to-end.

ccpm/scripts/forge/issue-edit.sh (1)

42-77: Guard options that require a value.

If a flag is the last argument (missing value), shift 2 will read past end. Add value checks.

Example pattern (apply to all valued options):

-      --title)
-        title="$2"
-        shift 2
+      --title)
+        [[ -n "${2-}" ]] || { forge_error "--title requires a value"; return 1; }
+        title="$2"; shift 2
ccpm/scripts/pm/init.sh (2)

213-214: Use [[ ]] for pattern matching on current path.

Single-bracket test won’t treat * as a glob here; use [[ ]] with pattern.

Apply this diff:

-if [ -d "scripts/pm" ] && [ ! "$(pwd)" = *"/.claude"* ]; then
+if [[ -d "scripts/pm" ]] && [[ "$(pwd)" != *"/.claude"* ]]; then

151-173: Avoid hardcoding tea installer and privileged writes; prefer package managers or documented install steps.

Downloading a fixed binary to /usr/local/bin with sudo is brittle and a security risk; versions drift.

  • Prefer: brew install tea (macOS), distro packages, or official install script.
  • If keeping fallback, verify checksum and make version configurable.
    Would you like a patch to detect package managers and only print instructions when unavailable?
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 98a8653 and 1bb4508.

📒 Files selected for processing (4)
  • ccpm/scripts/forge/config.sh (1 hunks)
  • ccpm/scripts/forge/detect.sh (1 hunks)
  • ccpm/scripts/forge/issue-edit.sh (1 hunks)
  • ccpm/scripts/pm/init.sh (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • ccpm/scripts/forge/detect.sh
🧰 Additional context used
🧬 Code graph analysis (3)
ccpm/scripts/forge/issue-edit.sh (1)
ccpm/scripts/forge/config.sh (2)
  • forge_init (22-49)
  • forge_error (97-100)
ccpm/scripts/pm/init.sh (1)
ccpm/scripts/forge/detect.sh (1)
  • detect_forge (13-69)
ccpm/scripts/forge/config.sh (1)
ccpm/scripts/forge/detect.sh (1)
  • detect_forge (13-69)
🪛 Shellcheck (0.11.0)
ccpm/scripts/forge/config.sh

[error] 13-13: Parameter expansions can't start with (. Double check syntax.

(SC2296)


[error] 15-15: Parameter expansions can't start with (. Double check syntax.

(SC2296)

🔇 Additional comments (1)
ccpm/scripts/forge/issue-edit.sh (1)

216-239: No changes required: tea issues edit supports --add-labels and --remove-labels.

Comment on lines +10 to +19
if [[ -n "${BASH_SOURCE[0]}" ]]; then
# Bash
FORGE_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
elif [[ -n "${(%):-%x}" ]]; then
# Zsh
FORGE_SCRIPT_DIR="$(cd "$(dirname "${(%):-%x}")" && pwd)"
else
# Fallback
FORGE_SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
fi
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fix zsh-specific parameter expansion that breaks under bash (SC2296).

The ${(%):-%x} usage is invalid in bash and will cause a parse error even if the branch isn’t taken. Use a portable bash-safe detection and drop the zsh expansion here.

Apply this diff:

-# 取得當前腳本目錄 (支援 bash 和 zsh)
-if [[ -n "${BASH_SOURCE[0]}" ]]; then
-  # Bash
-  FORGE_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
-elif [[ -n "${(%):-%x}" ]]; then
-  # Zsh
-  FORGE_SCRIPT_DIR="$(cd "$(dirname "${(%):-%x}")" && pwd)"
-else
-  # Fallback
-  FORGE_SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
-fi
+# 取得當前腳本目錄 (bash-safe; fallback to $0)
+if [[ -n "${BASH_SOURCE[0]}" ]]; then
+  FORGE_SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
+else
+  FORGE_SCRIPT_DIR="$(cd -- "$(dirname -- "$0")" && pwd)"
+fi

ShellCheck: resolves SC2296.

🧰 Tools
🪛 Shellcheck (0.11.0)

[error] 13-13: Parameter expansions can't start with (. Double check syntax.

(SC2296)


[error] 15-15: Parameter expansions can't start with (. Double check syntax.

(SC2296)

🤖 Prompt for AI Agents
In ccpm/scripts/forge/config.sh around lines 10 to 19, the zsh-specific
parameter expansion `${(%):-%x}` causes a bash parse error (SC2296); replace
that branch with a portable detection of zsh (e.g. check if ZSH_VERSION is set)
and compute FORGE_SCRIPT_DIR using a zsh-safe variable (like ZSH_SOURCE[0]) with
a fallback to $0 so no bash-invalid parameter expansion remains; ensure the
final logic sets FORGE_SCRIPT_DIR to the script's directory in bash, zsh, and
the fallback case without using `${(%):-%x}`.

Comment on lines +91 to 94
# Save forge type to config file for future use
echo "$FORGE_TYPE" > .claude/.forge_type
echo " 💾 Saved forge type to .claude/.forge_type"
echo ""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Create .claude before writing .forge_type (ordering bug).

Writing to .claude/.forge_type will fail if the directory doesn’t exist.

Apply this diff:

-echo "$FORGE_TYPE" > .claude/.forge_type
-echo "  💾 Saved forge type to .claude/.forge_type"
+mkdir -p .claude
+echo "$FORGE_TYPE" > .claude/.forge_type
+echo "  💾 Saved forge type to .claude/.forge_type"
🤖 Prompt for AI Agents
In ccpm/scripts/pm/init.sh around lines 91 to 94, the script writes
.claude/.forge_type without ensuring the .claude directory exists; create the
directory first (mkdir -p .claude) before echoing to .claude/.forge_type and
optionally check or handle mkdir failure; then proceed to write the file and
print the confirmation message.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant