-
Notifications
You must be signed in to change notification settings - Fork 545
docs: Add Traditional Chinese README and improve installation guide (fixes #961, #966) #970
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
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
WalkthroughAdds 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
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)
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
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this 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 toolingThe large-batch path always runs
gh extension list
, even whenFORGE_TYPE
is gitea (where gh often isn't installed). Wrap the extension check in a[[ "$FORGE_TYPE" == "github" ]]
guard so Gitea users don't hitcommand not found
.
300-310
: Avoid unconditionalgh
usage in cross-forge flowInside 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 andhttps://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 whateverforge_init
exports) and rename the field to something neutral (e.g.,tracker:
orissue_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
📒 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)
ccpm/scripts/forge/issue-edit.sh
Outdated
# 處理狀態變更 (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 | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
# 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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
There was a problem hiding this 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 ofccpm/
, 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 ofccpm/
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
📒 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.
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 | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
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 | |
) | |
) |
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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
# 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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
# 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.
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 "" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
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.
There was a problem hiding this 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
task_status=$(grep 'status:' $task_file | cut -d: -f2 | tr -d ' ') | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
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.
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
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.
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.
There was a problem hiding this 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
📒 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
There was a problem hiding this 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
📒 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)
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 (简中)
There was a problem hiding this 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
📒 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)
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
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.
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. |
There was a problem hiding this 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 -n1Consider 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 2ccpm/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
📒 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
.
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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}`.
# Save forge type to config file for future use | ||
echo "$FORGE_TYPE" > .claude/.forge_type | ||
echo " 💾 Saved forge type to .claude/.forge_type" | ||
echo "" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
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:
git clone
ccpm/
→.claude/
.claude
directories (common pain point)Now users have a reliable fallback when the automated script fails.
2. Add Traditional Chinese README (
README-TW.md
) 🌏3. Update Existing READMEs 📚
README.md
(English)zh-docs/README_ZH.md
(Simplified Chinese)Motivation
Problem Statement
Users frequently encounter installation failures (#961, #966, #572):
Current situation:
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
.claude
directoryDocumentation Quality
Related Issues
Breaking Changes
None. This is purely documentation improvement.
Additional Context
The improved installation guide ensures users can get started even when:
.claude
directoryThis should significantly reduce installation friction and improve the new user experience.
Summary by CodeRabbit
New Features
Documentation
Chores
Tests