diff --git a/README.md b/README.md
index 0c59c99..682d6f7 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
[](https://golang.org)
[](https://www.npmjs.com/package/@gitlink-ai/cli)
-The official [GitLink](https://www.gitlink.org.cn) CLI tool — built for humans and AI Agents. Supports **macOS, Linux, and Windows**. Covers repository management, issue tracking, pull requests, webhooks, member collaboration, CI/CD, and AI-powered workflows, with 40+ commands and AI Agent [Skills](./skills/).
+The official [GitLink](https://www.gitlink.org.cn) CLI tool — built for humans and AI Agents. Supports **macOS, Linux, and Windows**. Covers repository management, issue tracking, pull requests, webhooks, member collaboration, CI/CD, and AI-powered workflows, with 40+ commands and AI Agent [Skills](./skills/README.md).
**[中文文档](./README.zh-CN.md)**
@@ -78,11 +78,19 @@ The official [GitLink](https://www.gitlink.org.cn) CLI tool — built for humans
jiangtx
+
+
## Why gitlink-cli?
-- **Agent-Native Design** — Structured [Skills](./skills/) out of the box, compatible with Claude Code, OpenClaw, and other AI platforms — Agents can operate GitLink with zero extra setup
+- **Agent-Native Design** — Structured [Skills](./skills/README.md) out of the box, compatible with Claude Code, OpenClaw, and other AI platforms — Agents can operate GitLink with zero extra setup
- **Wide Coverage** — Repository, Issue, PR, Webhook, Member, Branch, Release, CI, Pipeline, Org, Search, and User workflows are covered by high-level commands
- **AI-Friendly & Optimized** — Every command is tested with real Agents, featuring concise parameters, smart defaults, and structured output
- **Cross-Platform** — Runs on macOS, Linux, and Windows (x64/arm64), install via `npm install -g @gitlink-ai/cli` in one command, binary auto-downloaded
@@ -96,7 +104,7 @@ The official [GitLink](https://www.gitlink.org.cn) CLI tool — built for humans
| Category | Capabilities |
|----------|-------------|
| 📦 Repo | List, create, fork, delete repositories, view repo info, insights, and interactions |
-| 🐛 Issue | Create, update, close, batch close, comment on issues |
+| 🐛 Issue | Create, update, close, batch close/update/delete, comment on issues |
| 🔖 Label | Create, list, update, delete issue labels |
| 🔀 PR | Create, merge, review pull requests, view changed files |
| 👥 Member | List, add, remove repository members, change roles, create and accept invite links |
@@ -106,8 +114,11 @@ The official [GitLink](https://www.gitlink.org.cn) CLI tool — built for humans
| 🔧 CI | View builds, logs, CI/CD operations |
| ⚙️ Pipeline | Run, inspect, enable, disable, delete pipeline workflows and logs |
| 🔔 Webhook | Manage repo webhooks and test deliveries |
+| 📖 Wiki | List, view, create, update, and delete wiki pages |
| 🔍 Search | Search repositories, users |
+| 📊 Dataset | Query research datasets by project |
| 👤 User | View user profiles and info |
+| 📊 Profile | User ability, role, major, activity, and contribution statistics |
| 📋 PM | Sprint management, kanban boards, weekly reports |
| 🤖 Workflow | AI-powered issue triage, PR review, release notes |
@@ -216,11 +227,6 @@ gitlink-cli repo +readme --owner Gitlink --repo forgeplus --ref master
gitlink-cli repo +tree --owner Gitlink --repo forgeplus --ref master
gitlink-cli repo +tree --owner Gitlink --repo forgeplus --path src --ref main
-# Read raw files and common dependency manifests
-gitlink-cli repo +raw --owner Gitlink --repo forgeplus --path LICENSE --ref master
-gitlink-cli repo +file-exists --owner Gitlink --repo forgeplus --path package.json --ref master
-gitlink-cli repo +manifest --owner Gitlink --repo forgeplus --kind go --ref master
-
# Show language breakdown
gitlink-cli repo +languages --owner Gitlink --repo forgeplus
@@ -268,6 +274,28 @@ gitlink-cli webhook +test --owner Gitlink --repo forgeplus --id 68
gitlink-cli webhook +tasks --owner Gitlink --repo forgeplus --id 68
```
+### Wiki Management
+
+```bash
+# List wiki pages (table of contents)
+gitlink-cli wiki +list --owner Gitlink --repo forgeplus --project-id 12345
+
+# View a wiki page by page name
+gitlink-cli wiki +view --owner Gitlink --repo forgeplus --project-id 12345 -n home
+
+# Create a wiki page
+gitlink-cli wiki +create --owner Gitlink --repo forgeplus --project-id 12345 \
+ -n getting-started -t "Getting Started" -c "# Getting Started Guide"
+
+# Update a wiki page title and/or content
+gitlink-cli wiki +update --owner Gitlink --repo forgeplus --project-id 12345 -n home -t "New Title"
+gitlink-cli wiki +update --owner Gitlink --repo forgeplus --project-id 12345 -n home -c "# Updated content"
+gitlink-cli wiki +update --owner Gitlink --repo forgeplus --project-id 12345 -n home -t "New Title" -c "New content"
+
+# Delete a wiki page
+gitlink-cli wiki +delete --owner Gitlink --repo forgeplus --project-id 12345 -n old-page
+```
+
### Member Management
```bash
@@ -290,31 +318,6 @@ gitlink-cli member +role --owner Gitlink --repo forgeplus --user-id 101 --role D
gitlink-cli member +invite-link --owner Gitlink --repo forgeplus --role developer --apply true
```
-### Organization Operations
-
-```bash
-# List organizations
-gitlink-cli org +list --page 1 --limit 20
-
-# Show organization details
-gitlink-cli org +info --id Gitlink
-
-# List organization members with team or keyword filters
-gitlink-cli org +members --id Gitlink --team Platform --format json
-gitlink-cli org +members --id Gitlink --keyword alice --limit 50 --format json
-
-# List organization teams with normalized user details
-gitlink-cli org +teams --id Gitlink --authorize write --include-users --format json
-
-# Preview and create an organization team
-gitlink-cli org +team-create --id Gitlink --name platform --nickname "Platform Team" --dry-run
-gitlink-cli org +team-create --id Gitlink --name platform --nickname "Platform Team"
-
-# Preview and remove an organization member
-gitlink-cli org +member-remove --id Gitlink --login alice --dry-run
-gitlink-cli org +member-remove --id Gitlink --user-id 101
-```
-
### Issue Management
```bash
@@ -324,59 +327,34 @@ gitlink-cli issue +list --owner Gitlink --repo forgeplus
# Create an issue
gitlink-cli issue +create --owner Gitlink --repo forgeplus -t "Bug: Login failed" -b "Steps to reproduce..."
-# Create an issue from a Markdown file
-gitlink-cli issue +create --owner Gitlink --repo forgeplus -t "Bug: Login failed" --body-file issue.md
-
# Create an issue with metadata
gitlink-cli issue +create --owner Gitlink --repo forgeplus -t "Bug: Login failed" --priority-id 3 --tag-ids 4,5 --assigner-ids 7
# View an issue
-gitlink-cli issue +view --owner Gitlink --repo forgeplus --number 123
+gitlink-cli issue +view --owner Gitlink --repo forgeplus -i 123
# Update issue metadata
gitlink-cli issue +update --owner Gitlink --repo forgeplus --number 123 --priority-id 4 --branch bugfix/login --due-date 2026-06-15
-# Update issue description from a file
-gitlink-cli issue +update --owner Gitlink --repo forgeplus --number 123 --body-file update.md
-
# Close an issue
-gitlink-cli issue +close --owner Gitlink --repo forgeplus --number 123
+gitlink-cli issue +close --owner Gitlink --repo forgeplus -i 123
# Preview batch close without changing data
gitlink-cli issue +batch-close --owner Gitlink --repo forgeplus --numbers 123,124 --dry-run
-# Preview a shared batch update
-gitlink-cli issue +batch-update --owner Gitlink --repo forgeplus --numbers 123,124 --state closed --priority-id 4 --dry-run
-
-# Batch update issues from a CSV file
-gitlink-cli issue +batch-update --owner Gitlink --repo forgeplus --from issues.csv --assigner-ids 7 --due-date 2026-06-15
-
# Batch close issues from a CSV file
gitlink-cli issue +batch-close --owner Gitlink --repo forgeplus --from issues.csv
+# Preview batch metadata update by API issue IDs
+# Note: --ids uses API issue IDs, not web URL issue numbers.
+gitlink-cli issue +batch-update --owner Gitlink --repo forgeplus --ids 101,102 --status-id 3 --priority-id 2 --dry-run
+
+# Destructive batch delete requires both dry-run first and --yes for real execution
+gitlink-cli issue +batch-delete --owner Gitlink --repo forgeplus --ids 101,102 --dry-run
+gitlink-cli issue +batch-delete --owner Gitlink --repo forgeplus --ids 101,102 --yes
+
# Add a comment
-gitlink-cli issue +comment --owner Gitlink --repo forgeplus --number 123 -b "Fixed"
-
-# List, update, delete, and inspect issue comments/journals
-gitlink-cli issue +comments --owner Gitlink --repo forgeplus --number 123 --category comment
-gitlink-cli issue +comment-update --owner Gitlink --repo forgeplus --number 123 --comment-id 58 -b "Updated comment" --dry-run
-gitlink-cli issue +comment-delete --owner Gitlink --repo forgeplus --number 123 --comment-id 58 --dry-run
-gitlink-cli issue +comment-children --owner Gitlink --repo forgeplus --number 123 --comment-id 58
-
-# Add a comment from a file
-gitlink-cli issue +comment --owner Gitlink --repo forgeplus -i 123 --body-file comment.md
-
-# Batch comment on issues
-gitlink-cli issue +batch-comment --owner Gitlink --repo forgeplus --numbers 123,124 --body-file comment.md --dry-run
-
-# Reply to a comment and list a comment's replies
-gitlink-cli issue +comment --owner Gitlink --repo forgeplus -i 123 -b "Agreed" --reply-to 456
-gitlink-cli issue +comment-replies --owner Gitlink --repo forgeplus -n 123 -c 456
-
-# List, edit, and delete issue comments
-gitlink-cli issue +comments --owner Gitlink --repo forgeplus -n 123 --category comment
-gitlink-cli issue +comment-edit --owner Gitlink --repo forgeplus -n 123 -c 456 -b "Updated"
-gitlink-cli issue +comment-delete --owner Gitlink --repo forgeplus -n 123 -c 456
+gitlink-cli issue +comment --owner Gitlink --repo forgeplus -i 123 -b "Fixed"
# List issue assigners
gitlink-cli issue +assigners --owner Gitlink --repo forgeplus
@@ -454,12 +432,6 @@ gitlink-cli pr +reviews --owner Gitlink --repo forgeplus -i 42
# Create a PR review (with dry-run preview)
gitlink-cli pr +review --owner Gitlink --repo forgeplus -i 42 --status approved -c "LGTM" --dry-run
gitlink-cli pr +review --owner Gitlink --repo forgeplus -i 42 --status approved -c "LGTM"
-
-# List and manage PR review comments
-gitlink-cli pr +review-comments --owner Gitlink --repo forgeplus -i 42 --state opened
-gitlink-cli pr +review-comment --owner Gitlink --repo forgeplus -i 42 --review-id 10 --commit abc123 --line-code abc123_0_10 --path README.md --note "Please fix" --dry-run
-gitlink-cli pr +review-comment-update --owner Gitlink --repo forgeplus -i 42 --comment-id 200 --state resolved --dry-run
-gitlink-cli pr +review-comment-delete --owner Gitlink --repo forgeplus -i 42 --comment-id 200 --dry-run
```
### Branch Management
@@ -536,6 +508,36 @@ gitlink-cli pipeline +disable --owner Gitlink --repo forgeplus --id 7 --workflow
gitlink-cli pipeline +delete --owner Gitlink --repo forgeplus --id 7 --dry-run
```
+### Project Management
+
+`pm` surfaces GitLink project-management data for dashboards, sprints, weekly
+issues, labels, pipelines, and action runs. PM commands require the numeric
+GitLink project ID.
+
+```bash
+# Query PM dashboards and sprint issues
+gitlink-cli pm +dashboards --project-id 123 --limit 20
+gitlink-cli pm +sprint-issues --project-id 123 --page 1 --limit 20
+
+# Query weekly issues and PM issue tags
+gitlink-cli pm +weekly-issues --project-id 123
+gitlink-cli pm +issue-tags --project-id 123
+
+# Query PM pipelines and action runs
+gitlink-cli pm +pipelines --project-id 123
+gitlink-cli pm +action-runs --project-id 123
+```
+
+### Ignore File Templates
+
+```bash
+# List all available .gitignore templates
+gitlink-cli ignore +list
+
+# Filter templates by name
+gitlink-cli ignore +list --name Go
+```
+
### Search
```bash
@@ -546,6 +548,29 @@ gitlink-cli search +repos -k "machine learning"
gitlink-cli search +users -k "zhangsan"
```
+### User Profile
+
+`profile` surfaces GitLink's native user statistics (ability, role, major, activity,
+contribution). When `--user` is omitted it defaults to the authenticated user.
+
+```bash
+# Development ability scores + language breakdown
+gitlink-cli profile +ability --user zhangsan
+
+# Role positioning / major (discipline) categories
+gitlink-cli profile +role --user zhangsan
+gitlink-cli profile +major --user zhangsan
+
+# Ability within a time window (Unix timestamps)
+gitlink-cli profile +ability --user zhangsan --start-time 1704067200 --end-time 1735689600
+
+# Recent activity (issues / PRs / commits per day) for the current user
+gitlink-cli profile +activity
+
+# Contribution heatmap for a given year
+gitlink-cli profile +contribution --user zhangsan --year 2025
+```
+
### Workflow Agent Commands
`workflow` provides rule-based repository analysis for maintainers and AI Agents. It currently supports:
@@ -645,6 +670,32 @@ Safety:
- `workflow +pr-summary` does not comment, approve, reject, or merge pull requests.
- `workflow +repo-report` aggregates health, issue triage, and PR review summary signals without remote writes.
+### Dataset
+
+`dataset` manages and queries GitLink research datasets (title, description,
+paper content, license, owning project).
+
+```bash
+# List datasets for one or more projects (by numeric project ID)
+gitlink-cli dataset +list --ids 5988
+
+# View a repository's dataset and attachments
+gitlink-cli dataset +view --owner Gitlink --repo forgeplus
+
+# Create / update a repository's dataset (preview first with --dry-run)
+gitlink-cli dataset +create --owner me --repo proj -t "My dataset" -d "..." --license-id 359 --dry-run
+gitlink-cli dataset +update --owner me --repo proj -t "My dataset" -d "updated"
+
+# Delete a dataset attachment (destructive: preview, then confirm with --yes)
+gitlink-cli dataset +delete-attachment --owner me --repo proj --uuid --dry-run
+gitlink-cli dataset +delete-attachment --owner me --repo proj --uuid --yes
+```
+
+> Note: `dataset +list` (platform dataset query) is verified on production
+> gitlink.org.cn. The per-repo `+view`/`+create`/`+update` routes follow the
+> published OpenAPI contract but are not yet deployed on production (they return
+> 404 there); they will work once the platform enables them.
+
### Raw API
For endpoints not covered by shortcuts, use the Raw API directly:
@@ -701,13 +752,13 @@ git push gitlink
The `skills/` directory contains Agent Skill files for AI-automated GitLink operations.
-See [skills/README.md](skills/README.md) for details.
+See [skills/README.md](./skills/README.md) for details.
| Skill | Description |
|-------|-------------|
| `gitlink-shared` | Authentication, global parameters, safety rules, API notes |
| `gitlink-repo` | Repository operations (create, view, delete, fork, insights, etc.) |
-| `gitlink-issue` | Issue operations (create, update, close, comment, etc.) |
+| `gitlink-issue` | Issue operations (create, update, close, batch update/delete, comment, etc.) |
| `gitlink-pr` | Pull request operations (create, merge, review, etc.) |
| `gitlink-member` | Repository member and invite link management |
| `gitlink-branch` | Branch management (create, delete, list, protect, unprotect) |
@@ -748,6 +799,7 @@ gitlink-cli/
│ ├── org/ # Organization shortcuts
│ ├── ci/ # CI shortcuts
│ ├── pipeline/ # Pipeline shortcuts
+│ ├── pm/ # Project management shortcuts
│ ├── search/ # Search shortcuts
│ ├── user/ # User shortcuts
│ └── register.go # Registration entry point
@@ -771,7 +823,7 @@ gitlink-cli/
## Documentation
-- [Skills Guide](skills/README.md) — AI Agent Skills detailed documentation
+- [Skills Guide](./skills/README.md) — AI Agent Skills detailed documentation
- [Design Document](doc/design.md) — Architecture design and development plan
## FAQ
@@ -836,7 +888,7 @@ gitlink-cli uses Windows Credential Manager for secure token storage. If Credent
### Q: Where can I find the full API reference?
-See [skills/gitlink-shared/REFERENCE.md](skills/gitlink-shared/REFERENCE.md).
+See [skills/gitlink-shared/references/api-reference.md](./skills/gitlink-shared/references/api-reference.md).
## License
diff --git a/README.zh-CN.md b/README.zh-CN.md
index 84368c9..a1fc10a 100644
--- a/README.zh-CN.md
+++ b/README.zh-CN.md
@@ -553,6 +553,25 @@ gitlink-cli pipeline +disable --owner Gitlink --repo forgeplus --id 7 --workflow
gitlink-cli pipeline +delete --owner Gitlink --repo forgeplus --id 7 --dry-run
```
+### 项目管理
+
+`pm` 暴露 GitLink 项目管理数据,覆盖看板、Sprint、周报、标签、流水线和 Action 运行记录。
+PM 命令需要传入数字项目 ID。
+
+```bash
+# 查询 PM 看板和 Sprint Issue
+gitlink-cli pm +dashboards --project-id 123 --limit 20
+gitlink-cli pm +sprint-issues --project-id 123 --page 1 --limit 20
+
+# 查询周报 Issue 和 PM Issue 标签
+gitlink-cli pm +weekly-issues --project-id 123
+gitlink-cli pm +issue-tags --project-id 123
+
+# 查询 PM 流水线和 Action 运行记录
+gitlink-cli pm +pipelines --project-id 123
+gitlink-cli pm +action-runs --project-id 123
+```
+
### 忽略文件模板
```bash
@@ -718,6 +737,7 @@ gitlink-cli/
│ ├── org/ # 组织 shortcuts
│ ├── ci/ # CI shortcuts
│ ├── pipeline/ # Pipeline shortcuts
+│ ├── pm/ # 项目管理 shortcuts
│ ├── search/ # 搜索 shortcuts
│ ├── user/ # 用户 shortcuts
│ └── register.go # 注册入口
diff --git a/doc/changes/pm-shortcuts.md b/doc/changes/pm-shortcuts.md
new file mode 100644
index 0000000..aa05e5b
--- /dev/null
+++ b/doc/changes/pm-shortcuts.md
@@ -0,0 +1,60 @@
+# PM shortcuts
+
+## Background
+
+The `gitlink-pm` Skill documented GitLink project-management workflows but had
+to call Raw API paths under `/pm/...` directly. That made Sprint reports, weekly
+issue summaries, board inspection, and PM pipeline checks less discoverable for
+users and agents.
+
+This change adds a first-class `pm` shortcut group for read-only PM data.
+
+## New shortcuts
+
+- `pm +dashboards` lists PM dashboards for a project.
+- `pm +sprint-issues` lists Sprint issues.
+- `pm +weekly-issues` lists weekly issues.
+- `pm +issue-tags` lists PM issue tags.
+- `pm +pipelines` lists PM pipelines.
+- `pm +action-runs` lists PM action run records.
+
+All commands require `--project-id` and accept `--page`/`--limit`.
+
+## Examples
+
+```bash
+gitlink-cli pm +dashboards --project-id 123 --limit 20
+gitlink-cli pm +sprint-issues --project-id 123 --page 1 --limit 20
+gitlink-cli pm +weekly-issues --project-id 123
+gitlink-cli pm +issue-tags --project-id 123
+gitlink-cli pm +pipelines --project-id 123
+gitlink-cli pm +action-runs --project-id 123
+```
+
+## Documentation updates
+
+- README and README.zh-CN include PM usage examples.
+- `skills/gitlink-pm` now prefers `pm +...` shortcuts instead of Raw API calls.
+- The Skills overview lists the new PM commands.
+
+## Tests
+
+Unit tests cover:
+
+- all PM shortcut endpoint mappings;
+- `project_id`, `page`, and `limit` query construction;
+- default pagination;
+- required `--project-id` validation;
+- HTTP error propagation.
+
+Suggested verification:
+
+```bash
+go test ./shortcuts/pm ./shortcuts
+```
+
+Full project verification:
+
+```bash
+go test ./...
+```
diff --git a/internal/i18n/locales/en-US.json b/internal/i18n/locales/en-US.json
index d5af1ca..f86243e 100644
--- a/internal/i18n/locales/en-US.json
+++ b/internal/i18n/locales/en-US.json
@@ -56,6 +56,13 @@
"cmd.org.list.short": "List organizations",
"cmd.org.members.short": "List organization members",
"cmd.org.short": "Organization operations",
+ "cmd.pm.action_runs.short": "List PM action run records",
+ "cmd.pm.dashboards.short": "List PM dashboards",
+ "cmd.pm.issue_tags.short": "List PM issue tags",
+ "cmd.pm.pipelines.short": "List PM pipelines",
+ "cmd.pm.short": "Project management operations",
+ "cmd.pm.sprint_issues.short": "List PM sprint issues",
+ "cmd.pm.weekly_issues.short": "List PM weekly issues",
"cmd.pr.close.short": "Close a pull request",
"cmd.pr.comment.short": "Add a comment to a pull request",
"cmd.pr.create.short": "Create a pull request",
@@ -189,6 +196,7 @@
"flag.org.name": "Organization name",
"flag.owner": "Repository owner (auto-detected from git remote)",
"flag.page": "Page number",
+ "flag.pm.project_id": "GitLink project ID",
"flag.pr.assignee_id": "Assignee user ID",
"flag.pr.base": "Target branch",
"flag.pr.body": "PR description",
diff --git a/internal/i18n/locales/zh-CN.json b/internal/i18n/locales/zh-CN.json
index 4c5d175..cc8b61b 100644
--- a/internal/i18n/locales/zh-CN.json
+++ b/internal/i18n/locales/zh-CN.json
@@ -56,6 +56,13 @@
"cmd.org.list.short": "列出组织",
"cmd.org.members.short": "列出组织成员",
"cmd.org.short": "组织操作",
+ "cmd.pm.action_runs.short": "列出 PM Action 运行记录",
+ "cmd.pm.dashboards.short": "列出 PM 看板",
+ "cmd.pm.issue_tags.short": "列出 PM Issue 标签",
+ "cmd.pm.pipelines.short": "列出 PM 流水线",
+ "cmd.pm.short": "项目管理操作",
+ "cmd.pm.sprint_issues.short": "列出 PM Sprint Issue",
+ "cmd.pm.weekly_issues.short": "列出 PM 周报 Issue",
"cmd.pr.close.short": "关闭拉取请求",
"cmd.pr.comment.short": "给拉取请求添加评论",
"cmd.pr.create.short": "创建拉取请求",
@@ -189,6 +196,7 @@
"flag.org.name": "组织名称",
"flag.owner": "仓库所有者(自动从 git remote 检测)",
"flag.page": "页码",
+ "flag.pm.project_id": "GitLink 项目 ID",
"flag.pr.assignee_id": "指派人用户 ID",
"flag.pr.base": "目标分支",
"flag.pr.body": "PR 描述",
diff --git a/shortcuts/pm/pm.go b/shortcuts/pm/pm.go
index 991a4e4..4ecbdb1 100644
--- a/shortcuts/pm/pm.go
+++ b/shortcuts/pm/pm.go
@@ -1,137 +1,71 @@
+// Package pm implements GitLink project management shortcuts.
package pm
import (
"net/url"
+ "strings"
+ "github.com/gitlink-org/gitlink-cli/internal/i18n"
"github.com/gitlink-org/gitlink-cli/shortcuts/common"
)
-// Shortcuts returns project management shortcuts for GitLink.
-//
-// The pm domain provides commands for viewing dashboards, sprints,
-// weekly issues, tags, pipelines, and action runs associated with
-// a project.
-func Shortcuts() []*common.Shortcut {
+// Shortcuts returns project management read shortcuts.
+func Shortcuts(translators ...*i18n.Translator) []*common.Shortcut {
+ tr := shortcutTranslator(translators...)
return []*common.Shortcut{
- {
- Name: "dashboards",
- Description: "查看项目仪表盘数据",
- Flags: []common.Flag{
- {Name: "project", Usage: "项目 ID", Required: true},
- },
- Run: func(ctx *common.RuntimeContext) error {
- project, err := ctx.RequireArg("project")
- if err != nil {
- return err
- }
- q := url.Values{}
- q.Set("project_id", project)
- env, err := ctx.CallAPIWithQuery("GET", "/pm/dashboards", q)
- if err != nil {
- return err
- }
- return ctx.Output(env)
- },
+ pmListShortcut(tr, "dashboards", tr.T("cmd.pm.dashboards.short"), "/pm/dashboards"),
+ pmListShortcut(tr, "sprint-issues", tr.T("cmd.pm.sprint_issues.short"), "/pm/sprint_issues"),
+ pmListShortcut(tr, "weekly-issues", tr.T("cmd.pm.weekly_issues.short"), "/pm/weekly_issues"),
+ pmListShortcut(tr, "issue-tags", tr.T("cmd.pm.issue_tags.short"), "/pm/issue_tags"),
+ pmListShortcut(tr, "pipelines", tr.T("cmd.pm.pipelines.short"), "/pm/pipelines"),
+ pmListShortcut(tr, "action-runs", tr.T("cmd.pm.action_runs.short"), "/pm/action_runs"),
+ }
+}
+
+func pmListShortcut(tr *i18n.Translator, name, description, path string) *common.Shortcut {
+ return &common.Shortcut{
+ Name: name,
+ Description: description,
+ Flags: []common.Flag{
+ {Name: "project-id", Short: "P", Usage: tr.T("flag.pm.project_id"), Required: true},
+ {Name: "page", Short: "p", Usage: tr.T("flag.page"), Default: "1"},
+ {Name: "limit", Short: "l", Usage: tr.T("flag.limit"), Default: "20"},
},
- {
- Name: "sprints",
- Description: "查看 Sprint 任务列表",
- Flags: []common.Flag{
- {Name: "project", Usage: "项目 ID", Required: true},
- },
- Run: func(ctx *common.RuntimeContext) error {
- project, err := ctx.RequireArg("project")
- if err != nil {
- return err
- }
- q := url.Values{}
- q.Set("project_id", project)
- env, err := ctx.CallAPIWithQuery("GET", "/pm/sprint_issues", q)
- if err != nil {
- return err
- }
- return ctx.Output(env)
- },
- },
- {
- Name: "weekly",
- Description: "查看周报任务",
- Flags: []common.Flag{
- {Name: "project", Usage: "项目 ID", Required: true},
- },
- Run: func(ctx *common.RuntimeContext) error {
- project, err := ctx.RequireArg("project")
- if err != nil {
- return err
- }
- q := url.Values{}
- q.Set("project_id", project)
- env, err := ctx.CallAPIWithQuery("GET", "/pm/weekly_issues", q)
- if err != nil {
- return err
- }
- return ctx.Output(env)
- },
- },
- {
- Name: "tags",
- Description: "查看项目 Issue 标签",
- Flags: []common.Flag{
- {Name: "project", Usage: "项目 ID", Required: true},
- },
- Run: func(ctx *common.RuntimeContext) error {
- project, err := ctx.RequireArg("project")
- if err != nil {
- return err
- }
- q := url.Values{}
- q.Set("project_id", project)
- env, err := ctx.CallAPIWithQuery("GET", "/pm/issue_tags", q)
- if err != nil {
- return err
- }
- return ctx.Output(env)
- },
- },
- {
- Name: "pipelines",
- Description: "查看项目 CI/CD 流水线列表",
- Flags: []common.Flag{
- {Name: "project", Usage: "项目 ID", Required: true},
- },
- Run: func(ctx *common.RuntimeContext) error {
- project, err := ctx.RequireArg("project")
- if err != nil {
- return err
- }
- q := url.Values{}
- q.Set("project_id", project)
- env, err := ctx.CallAPIWithQuery("GET", "/pm/pipelines", q)
- if err != nil {
- return err
- }
- return ctx.Output(env)
- },
- },
- {
- Name: "runs",
- Description: "查看项目 Action 运行记录",
- Flags: []common.Flag{
- {Name: "project", Usage: "项目 ID", Required: true},
- },
- Run: func(ctx *common.RuntimeContext) error {
- project, err := ctx.RequireArg("project")
- if err != nil {
- return err
- }
- q := url.Values{}
- q.Set("project_id", project)
- env, err := ctx.CallAPIWithQuery("GET", "/pm/action_runs", q)
- if err != nil {
- return err
- }
- return ctx.Output(env)
- },
+ Run: func(ctx *common.RuntimeContext) error {
+ projectID, err := ctx.RequireArg("project-id")
+ if err != nil {
+ return err
+ }
+ q := pmQuery(ctx, projectID)
+ env, err := ctx.CallAPIWithQuery("GET", path, q)
+ if err != nil {
+ return err
+ }
+ return ctx.Output(env)
},
}
}
+
+func pmQuery(ctx *common.RuntimeContext, projectID string) url.Values {
+ q := url.Values{}
+ q.Set("project_id", strings.TrimSpace(projectID))
+ q.Set("page", firstNonEmpty(ctx.Arg("page"), "1"))
+ q.Set("limit", firstNonEmpty(ctx.Arg("limit"), "20"))
+ return q
+}
+
+func firstNonEmpty(values ...string) string {
+ for _, value := range values {
+ if strings.TrimSpace(value) != "" {
+ return strings.TrimSpace(value)
+ }
+ }
+ return ""
+}
+
+func shortcutTranslator(translators ...*i18n.Translator) *i18n.Translator {
+ if len(translators) > 0 && translators[0] != nil {
+ return translators[0]
+ }
+ return i18n.Default()
+}
diff --git a/shortcuts/pm/pm_test.go b/shortcuts/pm/pm_test.go
index 781d09f..dc3fd1d 100644
--- a/shortcuts/pm/pm_test.go
+++ b/shortcuts/pm/pm_test.go
@@ -4,192 +4,26 @@ import (
"encoding/json"
"net/http"
"net/http/httptest"
- "strings"
"testing"
"github.com/gitlink-org/gitlink-cli/internal/client"
+ "github.com/gitlink-org/gitlink-cli/internal/i18n"
"github.com/gitlink-org/gitlink-cli/shortcuts/common"
)
-func TestPmDashboards(t *testing.T) {
- tests := []struct {
- name string
- mockStatus int
- mockBody string
- wantErr bool
- errContains string
- }{
- {"正常返回", 200, `{"dashboards": []}`, false, ""},
- {"API 404", 404, `{"error": "not found"}`, true, "404"},
- {"返回 HTML", 200, `Login`, true, "HTML"},
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- if r.Method != "GET" {
- t.Errorf("expected GET, got %s", r.Method)
- }
- if !strings.Contains(r.URL.Path, "/pm/dashboards") {
- t.Errorf("expected path containing /pm/dashboards, got %s", r.URL.Path)
- }
- if got := r.URL.Query().Get("project_id"); got != "123" {
- t.Errorf("expected project_id=123, got %s", got)
- }
- w.WriteHeader(tt.mockStatus)
- w.Write([]byte(tt.mockBody))
- }))
- defer server.Close()
-
- shortcut := findPmShortcut(t, "dashboards")
- ctx := &common.RuntimeContext{
- Client: &client.Client{HTTP: server.Client(), BaseURL: server.URL},
- Owner: "test", Repo: "test", Format: "json",
- Args: map[string]string{"project": "123"},
- }
- err := shortcut.Run(ctx)
-
- if tt.wantErr && err == nil {
- t.Fatal("期望错误但为 nil")
- }
- if !tt.wantErr && err != nil {
- t.Fatalf("不期望错误: %v", err)
- }
- if tt.wantErr && tt.errContains != "" && err != nil {
- if !strings.Contains(err.Error(), tt.errContains) {
- t.Errorf("错误应包含 %q: %s", tt.errContains, err.Error())
- }
- }
- })
- }
-}
-
-func TestPmSprints(t *testing.T) {
- server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- if r.Method != "GET" {
- t.Errorf("expected GET, got %s", r.Method)
- }
- if !strings.Contains(r.URL.Path, "/pm/sprint_issues") {
- t.Errorf("expected path containing /pm/sprint_issues, got %s", r.URL.Path)
- }
- w.WriteHeader(200)
- w.Write([]byte(`{"sprint_issues": []}`))
- }))
- defer server.Close()
-
- shortcut := findPmShortcut(t, "sprints")
+func runShortcut(t *testing.T, server *httptest.Server, name string, args map[string]string) error {
+ t.Helper()
+ shortcut := findShortcut(t, name)
ctx := &common.RuntimeContext{
Client: &client.Client{HTTP: server.Client(), BaseURL: server.URL},
- Owner: "test", Repo: "test", Format: "json",
- Args: map[string]string{"project": "456"},
- }
- if err := shortcut.Run(ctx); err != nil {
- t.Fatalf("sprints shortcut failed: %v", err)
+ Format: "json",
+ Args: args,
+ Tr: i18n.Default(),
}
+ return shortcut.Run(ctx)
}
-func TestPmWeekly(t *testing.T) {
- server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- if !strings.Contains(r.URL.Path, "/pm/weekly_issues") {
- t.Errorf("expected path containing /pm/weekly_issues, got %s", r.URL.Path)
- }
- w.WriteHeader(200)
- w.Write([]byte(`{"weekly_issues": []}`))
- }))
- defer server.Close()
-
- shortcut := findPmShortcut(t, "weekly")
- ctx := &common.RuntimeContext{
- Client: &client.Client{HTTP: server.Client(), BaseURL: server.URL},
- Owner: "test", Repo: "test", Format: "json",
- Args: map[string]string{"project": "789"},
- }
- if err := shortcut.Run(ctx); err != nil {
- t.Fatalf("weekly shortcut failed: %v", err)
- }
-}
-
-func TestPmTags(t *testing.T) {
- server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- if !strings.Contains(r.URL.Path, "/pm/issue_tags") {
- t.Errorf("expected path containing /pm/issue_tags, got %s", r.URL.Path)
- }
- w.WriteHeader(200)
- w.Write([]byte(`{"issue_tags": []}`))
- }))
- defer server.Close()
-
- shortcut := findPmShortcut(t, "tags")
- ctx := &common.RuntimeContext{
- Client: &client.Client{HTTP: server.Client(), BaseURL: server.URL},
- Owner: "test", Repo: "test", Format: "json",
- Args: map[string]string{"project": "100"},
- }
- if err := shortcut.Run(ctx); err != nil {
- t.Fatalf("tags shortcut failed: %v", err)
- }
-}
-
-func TestPmPipelines(t *testing.T) {
- server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- if !strings.Contains(r.URL.Path, "/pm/pipelines") {
- t.Errorf("expected path containing /pm/pipelines, got %s", r.URL.Path)
- }
- w.WriteHeader(200)
- w.Write([]byte(`{"pipelines": []}`))
- }))
- defer server.Close()
-
- shortcut := findPmShortcut(t, "pipelines")
- ctx := &common.RuntimeContext{
- Client: &client.Client{HTTP: server.Client(), BaseURL: server.URL},
- Owner: "test", Repo: "test", Format: "json",
- Args: map[string]string{"project": "200"},
- }
- if err := shortcut.Run(ctx); err != nil {
- t.Fatalf("pipelines shortcut failed: %v", err)
- }
-}
-
-func TestPmRuns(t *testing.T) {
- server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- if !strings.Contains(r.URL.Path, "/pm/action_runs") {
- t.Errorf("expected path containing /pm/action_runs, got %s", r.URL.Path)
- }
- w.WriteHeader(200)
- w.Write([]byte(`{"action_runs": []}`))
- }))
- defer server.Close()
-
- shortcut := findPmShortcut(t, "runs")
- ctx := &common.RuntimeContext{
- Client: &client.Client{HTTP: server.Client(), BaseURL: server.URL},
- Owner: "test", Repo: "test", Format: "json",
- Args: map[string]string{"project": "300"},
- }
- if err := shortcut.Run(ctx); err != nil {
- t.Fatalf("runs shortcut failed: %v", err)
- }
-}
-
-func TestPmMissingProject(t *testing.T) {
- server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- t.Fatal("should not call API when --project is missing")
- }))
- defer server.Close()
-
- shortcut := findPmShortcut(t, "dashboards")
- ctx := &common.RuntimeContext{
- Client: &client.Client{HTTP: server.Client(), BaseURL: server.URL},
- Owner: "test", Repo: "test", Format: "json",
- Args: map[string]string{},
- }
- err := shortcut.Run(ctx)
- if err == nil {
- t.Fatal("expected error when --project is missing")
- }
-}
-
-func findPmShortcut(t *testing.T, name string) *common.Shortcut {
+func findShortcut(t *testing.T, name string) *common.Shortcut {
t.Helper()
for _, shortcut := range Shortcuts() {
if shortcut.Name == name {
@@ -200,21 +34,100 @@ func findPmShortcut(t *testing.T, name string) *common.Shortcut {
return nil
}
-func assertPmRequest(t *testing.T, r *http.Request, method, pathPrefix string) {
+func writeJSON(t *testing.T, w http.ResponseWriter, v interface{}) {
t.Helper()
- if r.Method != method {
- t.Fatalf("got method %s, want %s", r.Method, method)
- }
- if !strings.HasPrefix(r.URL.Path, pathPrefix) {
- t.Fatalf("got path %s, want prefix %s", r.URL.Path, pathPrefix)
+ w.Header().Set("Content-Type", "application/json")
+ if err := json.NewEncoder(w).Encode(v); err != nil {
+ t.Fatalf("write JSON: %v", err)
}
}
-func decodePmJSON(t *testing.T, r *http.Request) map[string]interface{} {
- t.Helper()
- var payload map[string]interface{}
- if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {
- t.Fatalf("failed to decode request body: %v", err)
+func TestPMReadShortcuts(t *testing.T) {
+ tests := []struct {
+ name string
+ path string
+ }{
+ {name: "dashboards", path: "/pm/dashboards.json"},
+ {name: "sprint-issues", path: "/pm/sprint_issues.json"},
+ {name: "weekly-issues", path: "/pm/weekly_issues.json"},
+ {name: "issue-tags", path: "/pm/issue_tags.json"},
+ {name: "pipelines", path: "/pm/pipelines.json"},
+ {name: "action-runs", path: "/pm/action_runs.json"},
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if r.Method != http.MethodGet {
+ t.Fatalf("method = %s, want GET", r.Method)
+ }
+ if r.URL.Path != tt.path {
+ t.Fatalf("path = %s, want %s", r.URL.Path, tt.path)
+ }
+ if got := r.URL.Query().Get("project_id"); got != "123" {
+ t.Fatalf("project_id = %q, want 123", got)
+ }
+ if got := r.URL.Query().Get("page"); got != "2" {
+ t.Fatalf("page = %q, want 2", got)
+ }
+ if got := r.URL.Query().Get("limit"); got != "50" {
+ t.Fatalf("limit = %q, want 50", got)
+ }
+ writeJSON(t, w, map[string]interface{}{"status": 0, "message": "success"})
+ }))
+ defer server.Close()
+
+ err := runShortcut(t, server, tt.name, map[string]string{
+ "project-id": "123",
+ "page": "2",
+ "limit": "50",
+ })
+ if err != nil {
+ t.Fatalf("%s failed: %v", tt.name, err)
+ }
+ })
+ }
+}
+
+func TestPMReadShortcutsDefaultPagination(t *testing.T) {
+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if r.URL.Path != "/pm/dashboards.json" {
+ t.Fatalf("path = %s, want /pm/dashboards.json", r.URL.Path)
+ }
+ if got := r.URL.Query().Get("page"); got != "1" {
+ t.Fatalf("page = %q, want 1", got)
+ }
+ if got := r.URL.Query().Get("limit"); got != "20" {
+ t.Fatalf("limit = %q, want 20", got)
+ }
+ writeJSON(t, w, map[string]interface{}{"status": 0})
+ }))
+ defer server.Close()
+
+ if err := runShortcut(t, server, "dashboards", map[string]string{"project-id": "123"}); err != nil {
+ t.Fatalf("dashboards failed: %v", err)
+ }
+}
+
+func TestPMReadShortcutRequiresProjectID(t *testing.T) {
+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ t.Fatalf("missing project-id should fail before remote API: %s %s", r.Method, r.URL.Path)
+ }))
+ defer server.Close()
+
+ if err := runShortcut(t, server, "dashboards", nil); err == nil {
+ t.Fatal("expected missing project-id error")
+ }
+}
+
+func TestPMReadShortcutHTTPError(t *testing.T) {
+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusInternalServerError)
+ _, _ = w.Write([]byte("server error"))
+ }))
+ defer server.Close()
+
+ if err := runShortcut(t, server, "dashboards", map[string]string{"project-id": "123"}); err == nil {
+ t.Fatal("expected error for HTTP 500")
}
- return payload
}
diff --git a/shortcuts/register.go b/shortcuts/register.go
index ea27013..33e3360 100644
--- a/shortcuts/register.go
+++ b/shortcuts/register.go
@@ -18,6 +18,7 @@ import (
"github.com/gitlink-org/gitlink-cli/shortcuts/milestone"
"github.com/gitlink-org/gitlink-cli/shortcuts/org"
"github.com/gitlink-org/gitlink-cli/shortcuts/pipeline"
+ "github.com/gitlink-org/gitlink-cli/shortcuts/pm"
"github.com/gitlink-org/gitlink-cli/shortcuts/pr"
"github.com/gitlink-org/gitlink-cli/shortcuts/profile"
"github.com/gitlink-org/gitlink-cli/shortcuts/release"
@@ -43,6 +44,7 @@ func RegisterAll(root *cobra.Command, translators ...*i18n.Translator) {
"member": member.Shortcuts(),
"milestone": milestone.Shortcuts(),
"pipeline": pipeline.Shortcuts(),
+ "pm": pm.Shortcuts(tr),
"pr": pr.Shortcuts(tr),
"profile": profile.Shortcuts(tr),
"release": release.Shortcuts(tr),
@@ -68,6 +70,7 @@ func RegisterAll(root *cobra.Command, translators ...*i18n.Translator) {
"member": "Repository member operations",
"milestone": "Milestone operations",
"pipeline": "Pipeline operations",
+ "pm": tr.T("cmd.pm.short"),
"pr": tr.T("cmd.pr.short"),
"profile": tr.T("cmd.profile.short"),
"release": tr.T("cmd.release.short"),
diff --git a/shortcuts/register_test.go b/shortcuts/register_test.go
index c4bc025..4c14316 100644
--- a/shortcuts/register_test.go
+++ b/shortcuts/register_test.go
@@ -13,8 +13,8 @@ func TestRegisterAll(t *testing.T) {
expectedGroups := []string{
"repo", "issue", "label", "license", "pr", "profile", "release", "branch",
"org", "user", "search", "ci", "workflow",
- "compare", "member", "milestone", "pipeline", "webhook",
- "dataset", "health", "ignore", "template",
+ "compare", "member", "milestone", "pipeline", "pm", "webhook",
+ "dataset", "health", "ignore", "wiki",
}
groupSet := map[string]bool{}
diff --git a/skills/README.md b/skills/README.md
index e022aa0..9be10f1 100644
--- a/skills/README.md
+++ b/skills/README.md
@@ -32,7 +32,7 @@ gitlink-cli auth status
gitlink-cli user +me
```
-详见: [gitlink-shared/examples/auth-workflow.md](gitlink-shared/examples/auth-workflow.md)
+详见: [gitlink-shared/SKILL.md](gitlink-shared/SKILL.md)
### 2. 查看可用命令
@@ -64,25 +64,19 @@ skills/
├── README.md # 本文件
├── gitlink-shared/ # 共享基础规则
│ ├── SKILL.md # 认证、全局参数、安全规则、分支约定
-│ ├── REFERENCE.md # API 详细参考、错误处理
-│ ├── TROUBLESHOOTING.md # 常见问题排查
-│ └── examples/
-│ └── auth-workflow.md # 认证工作流示例
+│ └── references/
+│ ├── api-reference.md # API 详细参考、错误处理
+│ ├── raw-api-batch.md # 批量 Raw API 调用参考
+│ └── troubleshooting.md # 常见问题排查
├── gitlink-repo/ # 仓库管理
│ ├── SKILL.md # 仓库操作指南
-│ ├── REFERENCE.md # 仓库 API 参考
-│ └── examples/
-│ └── repo-workflow.md # 仓库管理工作流
+│ └── references/ # 仓库命令参考文档
├── gitlink-issue/ # Issue 管理
│ ├── SKILL.md # Issue 操作指南
-│ ├── REFERENCE.md # Issue API 参考
-│ └── examples/
-│ └── issue-workflow.md # Issue 全流程工作流
+│ └── references/ # Issue 命令参考文档
├── gitlink-pr/ # Pull Request
│ ├── SKILL.md # PR 操作指南
-│ ├── REFERENCE.md # PR API 参考
-│ └── examples/
-│ └── pr-workflow.md # PR 工作流
+│ └── references/ # PR 命令参考文档
├── gitlink-member/ # 仓库成员管理
│ └── SKILL.md # 成员与邀请链接操作指南
├── gitlink-branch/ # 分支管理
@@ -91,25 +85,24 @@ skills/
│ └── branch-workflow.md # 分支工作流
├── gitlink-release/ # 版本发布
│ ├── SKILL.md # Release 操作指南
-│ ├── REFERENCE.md # Release API 参考
-│ └── examples/
-│ └── release-workflow.md # Release 工作流
+│ └── references/ # Release 命令参考文档
+├── gitlink-release-auto/ # 自动化 Release 管理
+│ └── SKILL.md # 自动发版、版本号推荐、Release Notes 生成
├── gitlink-search/ # 搜索功能
│ ├── SKILL.md # 搜索操作指南
-│ └── examples/
-│ └── search-workflow.md # 搜索工作流
+│ └── references/ # 搜索命令参考文档
├── gitlink-user/ # 用户管理
-│ └── SKILL.md # 用户操作指南
+│ ├── SKILL.md # 用户操作指南
+│ └── references/ # 用户命令参考文档
├── gitlink-org/ # 组织管理
│ ├── SKILL.md # 组织操作指南
-│ └── examples/
-│ └── org-workflow.md # 组织工作流
+│ └── references/ # 组织命令参考文档
├── gitlink-ci/ # CI/CD
-│ ├── SKILL.md # CI 操作指南
-│ └── examples/
-│ └── ci-workflow.md # CI 工作流
+│ └── SKILL.md # CI 操作指南
├── gitlink-pipeline/ # 流水线工作流
│ └── SKILL.md # Pipeline 操作指南
+├── gitlink-wiki/ # Wiki 页面管理
+│ └── SKILL.md # Wiki 操作指南
├── gitlink-pm/ # 项目管理
│ └── SKILL.md # PM 操作指南
├── gitlink-health/ # 项目健康度分析
@@ -135,8 +128,8 @@ skills/
|-------|------|----------|
| **gitlink-shared** | 认证、全局参数、API 参考、安全规则、分支约定 | `auth login`, `auth status` |
| **gitlink-repo** | 仓库管理与洞察 | `repo +list`, `repo +info`, `repo +languages`, `repo +contributors`, `repo +code-stats`, `repo +follow`, `repo +like` |
-| **gitlink-issue** | Issue 管理 | `issue +create`, `issue +list`, `issue +view`, `issue +close`, `issue +batch-close`, `issue +comments` |
-| **gitlink-pr** | Pull Request | `pr +list`, `pr +create`, `pr +view`, `pr +merge`, `pr +versions`, `pr +version-diff`, `pr +reviews`, `pr +review`, `pr +review-comments` |
+| **gitlink-issue** | Issue 管理 | `issue +create`, `issue +list`, `issue +view`, `issue +close`, `issue +batch-close`, `issue +batch-update`, `issue +batch-delete` |
+| **gitlink-pr** | Pull Request | `pr +list`, `pr +create`, `pr +view`, `pr +merge`, `pr +versions`, `pr +version-diff`, `pr +reviews`, `pr +review` |
| **gitlink-member** | 仓库成员管理 | `member +list`, `member +add`, `member +batch-add`, `member +role`, `member +invite-link` |
| **gitlink-branch** | 分支管理 | `branch +list`, `branch +create`, `branch +delete`, `branch +protect` |
| **gitlink-release** | 版本发布 | `release +list`, `release +create`, `release +edit`, `release +update`, `release +view` |
@@ -150,7 +143,8 @@ skills/
| **gitlink-org** | 组织管理 | `org +list`, `org +info`, `org +members` |
| **gitlink-ci** | CI/CD | `ci +builds`, `ci +logs` |
| **gitlink-pipeline** | 流水线工作流 | `pipeline +runs`, `pipeline +run`, `pipeline +logs` |
-| **gitlink-pm** | 项目管理 | 通过 Raw API 访问 |
+| **gitlink-wiki** | Wiki 页面管理 | `wiki +list`, `wiki +view`, `wiki +create`, `wiki +update`, `wiki +delete` |
+| **gitlink-pm** | 项目管理 | `pm +dashboards`, `pm +sprint-issues`, `pm +weekly-issues`, `pm +action-runs` |
| **gitlink-workflow** | AI 工作流 | Issue 分类、PR Review、Release Notes |
| **gitlink-health** | 开源项目健康度 | 详情见SKILL.md |
@@ -169,7 +163,7 @@ gitlink-cli repo +info
gitlink-cli repo +info --owner wbtiger --repo gitlink-cli
```
-详见: [gitlink-repo/examples/repo-workflow.md](gitlink-repo/examples/repo-workflow.md)
+详见: [gitlink-repo/SKILL.md](gitlink-repo/SKILL.md)
### 场景 2:创建和管理 Issue
@@ -190,7 +184,7 @@ gitlink-cli issue +close -i 123
gitlink-cli issue +batch-close --numbers 123,124 --dry-run
```
-详见: [gitlink-issue/examples/issue-workflow.md](gitlink-issue/examples/issue-workflow.md)
+详见: [gitlink-issue/SKILL.md](gitlink-issue/SKILL.md)
### 场景 3:管理分支和发布
@@ -208,7 +202,7 @@ gitlink-cli release +create -t v1.0.0 -n "v1.0.0 正式版" -b "更新内容..."
gitlink-cli release +view -i
```
-详见: [gitlink-release/examples/release-workflow.md](gitlink-release/examples/release-workflow.md)
+详见: [gitlink-release/SKILL.md](gitlink-release/SKILL.md)
### 场景 4:搜索和发现
@@ -224,7 +218,7 @@ gitlink-cli org +list
gitlink-cli org +info -i Gitlink
```
-详见: [gitlink-search/examples/search-workflow.md](gitlink-search/examples/search-workflow.md)
+详见: [gitlink-search/SKILL.md](gitlink-search/SKILL.md)
---
@@ -233,8 +227,8 @@ gitlink-cli org +info -i Gitlink
### 快速查找
- **我想了解认证**: [gitlink-shared/SKILL.md](gitlink-shared/SKILL.md)
-- **我想查看 API 细节**: [gitlink-shared/REFERENCE.md](gitlink-shared/REFERENCE.md)
-- **我遇到了错误**: [gitlink-shared/TROUBLESHOOTING.md](gitlink-shared/TROUBLESHOOTING.md)
+- **我想查看 API 细节**: [gitlink-shared/references/api-reference.md](gitlink-shared/references/api-reference.md)
+- **我遇到了错误**: [gitlink-shared/references/troubleshooting.md](gitlink-shared/references/troubleshooting.md)
- **我想看工作流示例**: 查看各 Skill 下的 `examples/` 目录
### 按功能分类
@@ -242,12 +236,12 @@ gitlink-cli org +info -i Gitlink
**仓库操作**:
- [gitlink-repo/SKILL.md](gitlink-repo/SKILL.md) - 仓库命令
- [gitlink-branch/SKILL.md](gitlink-branch/SKILL.md) - 分支命令
-- [gitlink-repo/examples/repo-workflow.md](gitlink-repo/examples/repo-workflow.md) - 完整工作流
+- [gitlink-repo/SKILL.md](gitlink-repo/SKILL.md) - 完整工作流
**Issue 和 PR**:
- [gitlink-issue/SKILL.md](gitlink-issue/SKILL.md) - Issue 命令
- [gitlink-pr/SKILL.md](gitlink-pr/SKILL.md) - PR 命令
-- [gitlink-issue/examples/issue-workflow.md](gitlink-issue/examples/issue-workflow.md) - Issue 工作流
+- [gitlink-issue/SKILL.md](gitlink-issue/SKILL.md) - Issue 工作流
**发布和搜索**:
- [gitlink-release/SKILL.md](gitlink-release/SKILL.md) - Release 命令
@@ -289,11 +283,11 @@ gitlink-cli auth login
### Q: 如何查看完整的 API 参考?
-A: 查看 [gitlink-shared/REFERENCE.md](gitlink-shared/REFERENCE.md)
+A: 查看 [gitlink-shared/references/api-reference.md](gitlink-shared/references/api-reference.md)
### Q: 遇到错误怎么办?
-A: 查看 [gitlink-shared/TROUBLESHOOTING.md](gitlink-shared/TROUBLESHOOTING.md)
+A: 查看 [gitlink-shared/references/troubleshooting.md](gitlink-shared/references/troubleshooting.md)
---
@@ -329,7 +323,7 @@ AI 代理可以:
- 所有边界情况处理正确
- 完整的文档和示例
-详见: [../doc/SKILLS_TEST_REPORT_2026-04-02.md](../doc/SKILLS_TEST_REPORT_2026-04-02.md)
+详见: [../doc/design.md](../doc/design.md)
---
@@ -337,8 +331,7 @@ AI 代理可以:
- [主项目 README](../README.md) - gitlink-cli 项目说明
- [设计文档](../doc/design.md) - 架构设计和开发计划
-- [测试报告](../doc/SKILLS_TEST_REPORT_2026-04-02.md) - 功能测试报告
-- [代码同步方案](../doc/CODE_SYNC_STRATEGY_FINAL.md) - GitHub ↔ GitLink 同步设计
+- [API 参考文档](../doc/gitlink_api_reference.md) - GitLink API 参考文档
- [gitlink-bisync](https://www.gitlink.org.cn/wbtiger/gitlink-bisync) - 代码双向同步系统
---
@@ -346,8 +339,8 @@ AI 代理可以:
## 📞 获取帮助
- **命令帮助**: `gitlink-cli --help`
-- **故障排查**: [gitlink-shared/TROUBLESHOOTING.md](gitlink-shared/TROUBLESHOOTING.md)
-- **API 参考**: [gitlink-shared/REFERENCE.md](gitlink-shared/REFERENCE.md)
+- **故障排查**: [gitlink-shared/references/troubleshooting.md](gitlink-shared/references/troubleshooting.md)
+- **API 参考**: [gitlink-shared/references/api-reference.md](gitlink-shared/references/api-reference.md)
- **工作流示例**: 查看各 Skill 下的 `examples/` 目录
---
@@ -355,7 +348,7 @@ AI 代理可以:
## 🎓 下一步
1. 阅读 [gitlink-shared/SKILL.md](gitlink-shared/SKILL.md) 了解基础
-2. 查看 [gitlink-shared/examples/auth-workflow.md](gitlink-shared/examples/auth-workflow.md) 完成认证
+2. 查看 [gitlink-shared/SKILL.md](gitlink-shared/SKILL.md) 完成认证
3. 根据需求选择相应的 Skill 文档
4. 参考 `examples/` 目录中的工作流示例
5. 使用 AI 代理自动化你的工作流
diff --git a/skills/gitlink-pm/SKILL.md b/skills/gitlink-pm/SKILL.md
index f5333ed..d8707bc 100644
--- a/skills/gitlink-pm/SKILL.md
+++ b/skills/gitlink-pm/SKILL.md
@@ -1,6 +1,6 @@
---
name: gitlink-pm
-version: 1.0.0
+version: 2.0.0
description: "项目管理(PM):Sprint、看板、周报等项目管理功能。当用户需要使用 GitLink PM 功能时触发。"
metadata:
requires:
@@ -10,37 +10,56 @@ metadata:
# gitlink-pm(项目管理)
-> **前置条件:** 先阅读 [`../gitlink-shared/SKILL.md`](../gitlink-shared/SKILL.md)
+> **前置条件:** 先阅读 [`../gitlink-shared/SKILL.md`](../gitlink-shared/SKILL.md)。
-**CRITICAL — GitLink 操作只能用 `gitlink-cli`。禁止用 `gh`(GitHub CLI)操作 GitLink 资源。`gh` 仅适用于 GitHub 平台。**
+**CRITICAL — GitLink 操作只能用 `gitlink-cli`。禁止用 `gh`(GitHub CLI)操作 GitLink 资源。**
-GitLink PM 模块提供敏捷项目管理能力,目前通过 Raw API 访问。
+GitLink PM 模块提供敏捷项目管理能力。优先使用 `pm` shortcut,不再直接拼接 `/pm/...` Raw API。
-## API 端点
-
-> 前缀:`/api/pm`
+## 命令
```bash
# 看板
-gitlink-cli api GET /pm/dashboards --query 'project_id=123'
+gitlink-cli pm +dashboards --project-id 123 --format json
# Sprint Issue 列表
-gitlink-cli api GET /pm/sprint_issues --query 'project_id=123'
+gitlink-cli pm +sprint-issues --project-id 123 --page 1 --limit 20 --format json
-# 周报
-gitlink-cli api GET /pm/weekly_issues --query 'project_id=123'
+# 周报 Issue
+gitlink-cli pm +weekly-issues --project-id 123 --format json
-# Issue 标签
-gitlink-cli api GET /pm/issue_tags --query 'project_id=123'
+# PM Issue 标签
+gitlink-cli pm +issue-tags --project-id 123 --format json
-# 流水线
-gitlink-cli api GET /pm/pipelines --query 'project_id=123'
+# PM 流水线
+gitlink-cli pm +pipelines --project-id 123 --format json
# Action 运行记录
-gitlink-cli api GET /pm/action_runs --query 'project_id=123'
+gitlink-cli pm +action-runs --project-id 123 --format json
```
+## 参数
+
+| 参数 | 必填 | 说明 |
+|------|------|------|
+| `--project-id, -P` | 是 | GitLink 数字项目 ID |
+| `--page, -p` | 否 | 页码,默认 `1` |
+| `--limit, -l` | 否 | 每页数量,默认 `20` |
+
+## API 映射
+
+| Shortcut | API |
+|----------|-----|
+| `pm +dashboards` | `GET /pm/dashboards` |
+| `pm +sprint-issues` | `GET /pm/sprint_issues` |
+| `pm +weekly-issues` | `GET /pm/weekly_issues` |
+| `pm +issue-tags` | `GET /pm/issue_tags` |
+| `pm +pipelines` | `GET /pm/pipelines` |
+| `pm +action-runs` | `GET /pm/action_runs` |
+
## 注意事项
-- PM 接口需要项目 ID(`project_id`),可通过 `repo +info` 获取
-- PM 功能需要项目开启 PM 模块
+- PM 接口需要项目 ID(`project_id`),可通过 `repo +info` 获取。
+- PM 功能需要项目开启 PM 模块。
+- 这些命令均为只读查询,适合 Agent 生成 Sprint 报告、看板摘要和项目管理周报。
+- 建议在 Agent 场景始终使用 `--format json`。