@mu-cabin/coding-cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +78 -0
- package/dist/cli.js +1181 -0
- package/generated/index.json +1 -0
- package/package.json +30 -0
- package/skills/coding/SKILL.md +188 -0
- package/skills/coding/references/admin.md +65 -0
- package/skills/coding/references/artifacts.md +138 -0
- package/skills/coding/references/cd.md +103 -0
- package/skills/coding/references/ci.md +99 -0
- package/skills/coding/references/code.md +145 -0
- package/skills/coding/references/export.md +42 -0
- package/skills/coding/references/files.md +66 -0
- package/skills/coding/references/issues.md +175 -0
- package/skills/coding/references/org.md +115 -0
- package/skills/coding/references/permissions.md +164 -0
- package/skills/coding/references/program.md +79 -0
- package/skills/coding/references/project.md +150 -0
- package/skills/coding/references/servicehook.md +112 -0
- package/skills/coding/references/test.md +143 -0
- package/skills/coding/references/wiki.md +118 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# coding-code
|
|
2
|
+
|
|
3
|
+
A curated playbook for the **代码托管 (09)** category — the 152 Git/MR actions.
|
|
4
|
+
|
|
5
|
+
## 1. Identifiers — get the DepotId first
|
|
6
|
+
|
|
7
|
+
Almost every action keys off **`DepotId`** (a numeric repo id), *not* the repo name. `DepotPath` is an
|
|
8
|
+
optional companion on most calls. So the universal first step is "resolve repo name → DepotId" (§2).
|
|
9
|
+
|
|
10
|
+
- **`DepotId`** — numeric repository id, required by nearly all git/MR actions.
|
|
11
|
+
- **`MergeId`** — the merge-request id; the key for every per-MR action (detail, diff, reviewers,
|
|
12
|
+
merge, close). MR list items carry both `Id` and `MergeId` — use **`MergeId`** for subsequent calls.
|
|
13
|
+
- **`ReviewerGlobalKey`** — reviewers/mergers are addressed by **GlobalKey** (a string), not numeric id.
|
|
14
|
+
- **Branches** are addressed by name; create needs a `StartPoint` (a branch name or commit sha).
|
|
15
|
+
- **Files/commits** need a `Ref` (branch/tag/sha) and a `Path`.
|
|
16
|
+
|
|
17
|
+
## 2. Resolve the repo → DepotId
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# repos the current user can read (simplest, no ids needed)
|
|
21
|
+
coding call DescribeMyDepots --param PageNumber=1 --param PageSize=50 \
|
|
22
|
+
--select 'Payload.Depots[].Id,Payload.Depots[].Name,Payload.Depots[].ProjectName,Payload.Depots[].DefaultBranch' --json
|
|
23
|
+
|
|
24
|
+
# all repos in a project (needs the numeric ProjectId)
|
|
25
|
+
coding call DescribeProjectDepotInfoList --param ProjectId=341 \
|
|
26
|
+
--select 'DepotData.Depots[].Id,DepotData.Depots[].Name,DepotData.Depots[].DefaultBranch' --json
|
|
27
|
+
|
|
28
|
+
# by exact name (needs team GlobalKey + project + depot name)
|
|
29
|
+
coding call DescribeDepotByNameInfo --param TeamGk=<team> --param ProjectName=demo --param DepotName=backend \
|
|
30
|
+
--select 'Depot.Id,Depot.DefaultBranch,Depot.HttpsUrl,Depot.SshUrl' --json
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Cache the `DepotId` (and default branch) for the session.
|
|
34
|
+
|
|
35
|
+
## 3. Browse code
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# branches
|
|
39
|
+
coding call DescribeGitBranches --param DepotId=123 --param PageSize=50 \
|
|
40
|
+
--select 'Branches[].BranchName,Branches[].IsDefaultBranch,Branches[].IsProtected,Branches[].Sha' --json
|
|
41
|
+
|
|
42
|
+
# directory listing at a ref (Path defaults to repo root)
|
|
43
|
+
coding call DescribeGitFiles --param DepotId=123 --param Ref=master --param Path=src \
|
|
44
|
+
--select 'Items[].Name,Items[].Path,Items[].Mode' --json
|
|
45
|
+
|
|
46
|
+
# a file's content at a specific commit
|
|
47
|
+
coding call DescribeGitFileContent --param DepotId=123 --param CommitSha=<sha> --param Path=src/app.ts --json
|
|
48
|
+
|
|
49
|
+
# commit history on a ref (KeyWord / Path / date range filter the list)
|
|
50
|
+
coding call DescribeGitCommitInfos --param DepotId=123 --param Ref=master --param PageSize=20 \
|
|
51
|
+
--select 'Commits[].Sha,Commits[].ShortMessage,Commits[].AuthorName,Commits[].CommitDate' --json
|
|
52
|
+
coding call DescribeGitCommitDiff --param DepotId=123 --param Sha=<sha> --json # one commit's diff (param is Sha)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## 4. Branches & tags
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
coding call CreateGitBranch --param DepotId=123 --param BranchName=feature/login --param StartPoint=master --json
|
|
59
|
+
coding call DescribeGitTags --param DepotId=123 --json
|
|
60
|
+
coding call CreateGitTag --data '{"DepotId":123,"TagName":"v1.2.0","StartPoint":"master","Message":"release"}' --json
|
|
61
|
+
# DeleteGitBranch / DeleteGitTag / DeleteGitMergedBranches are gated — see §7
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## 5. Merge requests — the lifecycle
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
# 5a. CREATE — two near-identical actions exist:
|
|
68
|
+
# CreateGitMergeReq → also accepts inline `Reviewers` (comma-separated GlobalKeys) ← prefer this
|
|
69
|
+
# CreateGitMergeRequest→ same minus Reviewers
|
|
70
|
+
coding call CreateGitMergeReq --data '{
|
|
71
|
+
"DepotId":123, "SrcBranch":"feature/login", "DestBranch":"master",
|
|
72
|
+
"Title":"Add SMS login", "Content":"…", "Reviewers":"userA,userB"}' --json
|
|
73
|
+
|
|
74
|
+
# 5b. LIST (Status filter ∈ OPEN|CLOSE|ALL|ACCEPTED; plus KeyWord, Source/TargetBranches, Reviewer/Creator/Merger…)
|
|
75
|
+
coding call DescribeDepotMergeRequests --param DepotId=123 --param Status=OPEN --param PageSize=20 \
|
|
76
|
+
--select 'Data.List[].MergeId,Data.List[].Title,Data.List[].Status,Data.List[].SourceBranch,Data.List[].TargetBranch' --json
|
|
77
|
+
# also: DescribeSelfMergeRequests (mine), DescribeProjectMergeRequests (whole project)
|
|
78
|
+
|
|
79
|
+
# 5c. DETAIL + diff + discussion
|
|
80
|
+
coding call DescribeMergeReqInfo --param DepotId=123 --param MergeId=45 --json
|
|
81
|
+
coding call DescribeGitMergeRequestDiffs --param DepotId=123 --param MergeId=45 --json # changed-file list
|
|
82
|
+
coding call DescribeGitMergeRequestDiffDetail --param DepotId=123 --param MergeId=45 --param Path=src/app.ts --json
|
|
83
|
+
coding call DescribeSingeMergeRequestNotes --param DepotPath=team/demo/backend --param MergeId=45 --json # comments (keys off DepotPath)
|
|
84
|
+
|
|
85
|
+
# 5d. REVIEWERS
|
|
86
|
+
coding call CreateMergeRequestReviewer --param DepotId=123 --param MergeId=45 --param ReviewerGlobalKey=userC --json
|
|
87
|
+
coding call DescribeMergeRequestReviewers --param DepotId=123 --param MergeId=45 --json
|
|
88
|
+
|
|
89
|
+
# 5e. COMMENT (NOTE: this action keys off DepotPath, not DepotId; ParentId 0 = root.
|
|
90
|
+
# Omit `Form` for an MR-level comment; supply it for a diff-line comment.)
|
|
91
|
+
coding call CreateMergeRequestNote --param DepotPath=team/demo/backend --param MergeId=45 \
|
|
92
|
+
--param ParentId=0 --param Content="LGTM" --json
|
|
93
|
+
|
|
94
|
+
# 5f. CAN-MERGE check (uses branch names, not MergeId)
|
|
95
|
+
coding call DescribeCanMerge --param DepotId=123 --param Source=feature/login --param Target=master --json
|
|
96
|
+
|
|
97
|
+
# 5g. MERGE — all flags required. Squash/IsFastForward/IsDelSourceBranch are booleans; Message is the commit msg.
|
|
98
|
+
coding call ModifyMergeMR --data '{"DepotId":123,"MergeId":45,"Message":"Merge !45",
|
|
99
|
+
"Squash":false,"IsFastForward":false,"IsDelSourceBranch":true}' --json
|
|
100
|
+
|
|
101
|
+
# title/description edits, rebase, or close instead of merge:
|
|
102
|
+
coding call ModifyGitMergeRequest --param DepotId=123 --param MergeId=45 --param Title="…" --json
|
|
103
|
+
coding call ModifyGitMergeRequestRebase --param DepotId=123 --param MergeId=45 --json
|
|
104
|
+
coding call ModifyCloseMR --param DepotId=123 --param MergeId=45 --json # close without merging (not destructive-gated)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## 6. Writing files / commits, releases (less common)
|
|
108
|
+
|
|
109
|
+
`CreateGitFiles` / `ModifyGitFiles` commit content directly — **both** require `Ref`, `Message`, and
|
|
110
|
+
`LastCommitSha` (the current head sha, for optimistic-lock conflict detection). `CreateGitCommit` makes
|
|
111
|
+
a multi-file commit (keys off `DepotPath`, not `DepotId`; also needs `LastCommitSha`).
|
|
112
|
+
`CreateGitRelease` / `DescribeGitReleases` manage releases. Prefer normal git over the API for bulk
|
|
113
|
+
content work; use these only when you must operate purely through the OpenAPI.
|
|
114
|
+
|
|
115
|
+
## 7. Destructive actions (exit-10 gated)
|
|
116
|
+
|
|
117
|
+
`DeleteGitDepot`, `DeleteGitBranch`, `DeleteGitMergedBranches`, `DeleteGitFiles`, `DeleteGitTag`,
|
|
118
|
+
`DeleteGitRelease`, `DeleteGitDeployKey`, `DeleteMergeRequestReviewer`, `DeleteMergeRequestNote`,
|
|
119
|
+
`DeleteBranchProtection`(+`Member`), `DeleteGitProtectedTagRule`, `DeleteSshKey`/`DeleteMemberSshKey`.
|
|
120
|
+
(`ModifyGitDepotArchive` is **not** gated — indexed `write` — but archiving hides the repo; confirm
|
|
121
|
+
anyway.) Follow SKILL.md's protocol: preview with `--dry-run`, get explicit
|
|
122
|
+
user approval, then re-run the **same argv with `--yes`**. `DeleteGitMergedBranches` is bulk — it skips
|
|
123
|
+
protected branches but still deletes every merged branch; confirm scope before approving.
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
coding call DeleteGitBranch --param DepotId=123 --param BranchName=feature/login --dry-run --json # show user
|
|
127
|
+
coding call DeleteGitBranch --param DepotId=123 --param BranchName=feature/login --yes --json # after approval
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
> **Merging is not exit-10 gated** (`ModifyMergeMR` is classified `write`). Treat it as consequential
|
|
131
|
+
> anyway: confirm the MR id, source/target, and the squash/delete-branch flags with the user before merging.
|
|
132
|
+
|
|
133
|
+
## 8. Gotchas
|
|
134
|
+
|
|
135
|
+
- **`DepotId` is the key, not the repo name** — always resolve it via §2 first. `DepotPath` is optional
|
|
136
|
+
on most calls, but a few use it **instead of** `DepotId`: `CreateMergeRequestNote`,
|
|
137
|
+
`DescribeSingeMergeRequestNotes`, and `CreateGitCommit` have **no `DepotId` param** (key off
|
|
138
|
+
`DepotPath`), and `DeleteGitMergedBranches` requires **both**. Check `coding schema` when unsure.
|
|
139
|
+
- **Reviewers/mergers use `GlobalKey` (string), not numeric user id.**
|
|
140
|
+
- **Two MR-create actions**: `CreateGitMergeReq` (supports inline `Reviewers`) and `CreateGitMergeRequest`.
|
|
141
|
+
Pick one; don't call both. The MR key for everything after is **`MergeId`** (not the list item's `Id`).
|
|
142
|
+
- **`ModifyMergeMR` requires all four control fields** (`Message`, `Squash`, `IsFastForward`,
|
|
143
|
+
`IsDelSourceBranch`) — a missing required field is a validation error (exit 11).
|
|
144
|
+
- Diffs and trees are large — `--select`/`--limit` aggressively, and prefer `DescribeGitMergeRequestDiffDetail`
|
|
145
|
+
for a single file over pulling the whole MR diff.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# coding-export
|
|
2
|
+
|
|
3
|
+
A curated playbook for the **导出任务 / Export jobs (17)** category — 3 actions implementing an async
|
|
4
|
+
"export pages → ZIP of Markdown" pipeline. **No action here is destructive** (all are `write` risk; none
|
|
5
|
+
trips the exit-10 gate) — but note these actions break the usual naming convention (verb is a *suffix*:
|
|
6
|
+
`DocumentJob{Create,Start,Status}`).
|
|
7
|
+
|
|
8
|
+
## 1. The export pipeline (create → start → poll)
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
# 1. create the job. Event is fixed; EventBody is an escaped-JSON STRING naming the subject.
|
|
12
|
+
# belongType ∈ project|team|program ; belongId is that subject's numeric id.
|
|
13
|
+
coding call DocumentJobCreate --data '{"Event":"PAGE_EXPORT_TO_ZIP_MD",
|
|
14
|
+
"EventBody":"{\"belongType\":\"project\",\"belongId\":341}"}' --select 'JobId' --json
|
|
15
|
+
# → top-level JobId (a string) — carry it through the next two calls
|
|
16
|
+
|
|
17
|
+
# 2. start the job (it does not run on create)
|
|
18
|
+
coding call DocumentJobStart --param JobId=<JobId> --json # → only RequestId
|
|
19
|
+
|
|
20
|
+
# 3. poll status until done; Result is a signed COS download URL (⚠️ valid ~30 min, then expires)
|
|
21
|
+
coding call DocumentJobStatus --param JobId=<JobId> --select 'Status,ProcessRate,Result' --json
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
The three values that thread through: `DocumentJobCreate` yields the **`JobId`** (top-level); `…Start`
|
|
25
|
+
kicks it off; `…Status` returns **`Status`** (string), **`ProcessRate`** (a progress object), and once
|
|
26
|
+
finished **`Result`** — the signed download URL.
|
|
27
|
+
|
|
28
|
+
> ⚠️ **`Result` is a time-limited COS link (~30 min per the spec).** Download promptly. The CLI does not
|
|
29
|
+
> download the bytes — hand the `Result` URL to the user (or `curl` it out of band) before it expires.
|
|
30
|
+
|
|
31
|
+
## 2. Notes
|
|
32
|
+
|
|
33
|
+
- **Two separate steps to run a job**: `DocumentJobCreate` only *registers* the job; it does not run
|
|
34
|
+
until `DocumentJobStart`. Poll `DocumentJobStatus` after starting.
|
|
35
|
+
- **`EventBody` is an escaped-JSON string**, not a nested object: `{"belongType":"…","belongId":…}`.
|
|
36
|
+
`belongType` is `project` | `team` | `program`; `belongId` is the matching numeric id (resolve a
|
|
37
|
+
project id via the `references/project.md` playbook, a program id via `references/program.md`).
|
|
38
|
+
- **Responses are top-level**, not under `Data`: `JobId` (create), `Status`/`ProcessRate`/`Result`
|
|
39
|
+
(status). Match `--select` accordingly.
|
|
40
|
+
- **`Event` is fixed** to `PAGE_EXPORT_TO_ZIP_MD` (the only documented export type).
|
|
41
|
+
- **Export requires team/project admin scope** — that's what an exit-8 `UnauthorizedOperation` means
|
|
42
|
+
here (a scope gap, not a wrong token).
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# coding-files
|
|
2
|
+
|
|
3
|
+
A curated playbook for the **文件网盘 / File disk (14)** category — 3 actions implementing an upload
|
|
4
|
+
pipeline. **No action in this category is destructive** — there's no exit-10 gate here (and no
|
|
5
|
+
delete/list/download action either).
|
|
6
|
+
|
|
7
|
+
## 1. The upload pipeline (3 steps, like the Wiki ZIP flow)
|
|
8
|
+
|
|
9
|
+
Uploading a file is **presign → upload bytes out-of-band → register**. The CLI does steps 1 and 3; the
|
|
10
|
+
actual byte transfer (step 2) is a direct PUT to Tencent COS / MinIO that the CLI does **not** perform.
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
# 1. presign — get the upload URL + the keys you carry forward
|
|
14
|
+
coding call DescribePreSignUploadUrl --data '{"ProjectName":"demo","FileName":"report.csv",
|
|
15
|
+
"ContentType":"text/csv","FolderType":0,"FolderId":0}' \
|
|
16
|
+
--select 'Data.UploadLink,Data.StorageKey,Data.AuthToken,Data.Headers' --json
|
|
17
|
+
|
|
18
|
+
# 2. PUT the bytes to Data.UploadLink — OUT OF BAND (curl/SDK). Use Data.Headers (a JSON string of
|
|
19
|
+
# x-cos-security-token etc.) and the signed Authorization embedded in UploadLink. The CLI does not
|
|
20
|
+
# move bytes; this step happens in the user's shell.
|
|
21
|
+
|
|
22
|
+
# 3. register the uploaded object as a CODING file — carries StorageKey + AuthToken from step 1
|
|
23
|
+
coding call CreateFile --data '{"StorageKey":"<from step 1>","AuthToken":"<from step 1>"}' \
|
|
24
|
+
--select 'Data.Id,Data.Name' --json # → Data.Id is the file id
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The values that thread through: step 1 yields **`StorageKey`** (the stored object path), **`AuthToken`**
|
|
28
|
+
(identity proof for step 3), **`UploadLink`** (the signed PUT URL), and **`Headers`** (a JSON *string*
|
|
29
|
+
of upload headers). Step 3 (`CreateFile`) needs only `StorageKey` + `AuthToken` and returns the new
|
|
30
|
+
file's `Data.Id`.
|
|
31
|
+
|
|
32
|
+
## 2. ⚠️ `FolderType` picks the destination — get it right
|
|
33
|
+
|
|
34
|
+
`DescribePreSignUploadUrl` has two distinct use cases controlled by **`FolderType`**:
|
|
35
|
+
|
|
36
|
+
| Goal | `FolderType` | `FolderId` |
|
|
37
|
+
|---|---|---|
|
|
38
|
+
| Upload to the **file disk (网盘)** | `0` (常规文件夹) | a real folder id from `CreateFolder` (or `0` for root) |
|
|
39
|
+
| Upload an **issue/项目协同 attachment** | `1` (隐藏文件夹) | `0` (not needed) |
|
|
40
|
+
|
|
41
|
+
For the attachment case: get the `Data.Id` from `CreateFile`, then pass it into an issue create/modify
|
|
42
|
+
as `FileIds:[<id>]` (that lives in the `references/issues.md` playbook, action `CreateIssue`/`ModifyIssue`).
|
|
43
|
+
|
|
44
|
+
## 3. Folders (file disk only)
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# create a folder in the file disk. ParentId 0 = root. Returns Data.Id (use as FolderId in step 1).
|
|
48
|
+
coding call CreateFolder --data '{"ProjectName":"demo","FoldName":"个人资料","ParentId":0}' \
|
|
49
|
+
--select 'Data.Id,Data.Name' --json
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Note the param is **`FoldName`** (not `FolderName`) and **`ParentId`** (not `ParentFolderId`).
|
|
53
|
+
|
|
54
|
+
## 4. Gotchas
|
|
55
|
+
|
|
56
|
+
- **The byte upload (step 2) is out of band** — the CLI presigns and registers but does not PUT the
|
|
57
|
+
file. Hand the user the `UploadLink` + `Headers` to upload (COS/MinIO PUT), then run `CreateFile`.
|
|
58
|
+
- **`FolderType`: `0` = file disk, `1` = issue attachment** (hidden folder). Picking the wrong one puts
|
|
59
|
+
the file in the wrong place. The `ContentType` should match what a browser would send (e.g.
|
|
60
|
+
`image/png`, `text/csv`).
|
|
61
|
+
- **`CreateFile` keys off `StorageKey` + `AuthToken`** from the presign step — no `ProjectName` on this
|
|
62
|
+
call. It returns `Data.Id` (int) — the handle you feed into `FileIds[]` when attaching to an issue.
|
|
63
|
+
- **Param spelling**: `CreateFolder` uses **`FoldName`** and **`ParentId`**; presign uses **`FolderId`**
|
|
64
|
+
(singular) + **`FolderType`**. Everything in this category wraps under **`Data`**.
|
|
65
|
+
- **No delete / list / download** here — this category only presigns, registers files, and creates
|
|
66
|
+
folders. For attachment-to-issue wiring, see the `references/issues.md` playbook.
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# coding-issues
|
|
2
|
+
|
|
3
|
+
A curated playbook for the **项目协同 (08)** category — the 65 issue/iteration actions.
|
|
4
|
+
|
|
5
|
+
## 1. Concepts & identifiers (resolve these before mutating)
|
|
6
|
+
|
|
7
|
+
- **ProjectName** — the project's name/identifier (the slug used in URLs, e.g. `demo-project`), **not**
|
|
8
|
+
its display label. Required by almost every action. If you only know the team or the display name,
|
|
9
|
+
list/resolve projects first (SKILL.md / `DescribeUserProjects` / `DescribeProjectByName`).
|
|
10
|
+
- **IssueCode** — the per-project issue number the user sees (e.g. `#42` → `42`). The key for
|
|
11
|
+
read/modify/delete of a single issue. **Not** the same as the global issue id.
|
|
12
|
+
- **Type** (the enum) vs **IssueTypeId** (a number):
|
|
13
|
+
- `Type` ∈ `REQUIREMENT` 需求 · `DEFECT` 缺陷 · `MISSION` 任务 · `EPIC` 史诗 · `SUB_TASK` 子任务 (for
|
|
14
|
+
`CreateIssue`). **List queries** (`DescribeIssueList`/`DescribeIssueListWithPage`) take an `IssueType`
|
|
15
|
+
of only `ALL`/`DEFECT`/`REQUIREMENT`/`MISSION`/`EPIC` — **no `SUB_TASK`**; reach sub-tasks via
|
|
16
|
+
`DescribeSubIssueList` on the parent.
|
|
17
|
+
- `IssueTypeId` is the numeric id of a *configured* type in this project (a project may have
|
|
18
|
+
several custom requirement/defect types). Get it from `DescribeProjectIssueTypeList`. `CreateIssue`
|
|
19
|
+
needs `Type`; `IssueTypeId` is only needed when the project has multiple types for that `Type`.
|
|
20
|
+
- **Priority** is a **string code**, not a label: `"0"`低 · `"1"`中 · `"2"`高 · `"3"`紧急.
|
|
21
|
+
- **StatusId** — status is an id, resolved per (project, IssueType) via `DescribeProjectIssueStatusList`.
|
|
22
|
+
You **transition** an issue by setting `StatusId` on `ModifyIssue`; there is no separate transition action.
|
|
23
|
+
- **Dates** are `"YYYY-MM-DD"` strings (`StartDate`/`DueDate`).
|
|
24
|
+
|
|
25
|
+
## 2. Orient — the one-time lookups
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# what issue types exist in this project (gives Type + IssueTypeId + names)
|
|
29
|
+
coding call DescribeProjectIssueTypeList --param ProjectName=demo \
|
|
30
|
+
--select 'IssueTypes[].IssueType,IssueTypes[].Id,IssueTypes[].Name' --json
|
|
31
|
+
|
|
32
|
+
# the status pipeline for a given type (gives IssueStatusId you'll set on ModifyIssue)
|
|
33
|
+
coding call DescribeProjectIssueStatusList --param ProjectName=demo --param IssueType=REQUIREMENT \
|
|
34
|
+
--select 'ProjectIssueStatusList[].IssueStatusId,ProjectIssueStatusList[].IssueStatus.Name' --json
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Cache these for the session so you don't re-fetch them per issue.
|
|
38
|
+
|
|
39
|
+
## 3. Find issues
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
# the user's own to-dos across the team (no ProjectName needed)
|
|
43
|
+
coding call DescribeWorkbenchIssueList --param Type=REQUIREMENT --param PageSize=20 \
|
|
44
|
+
--select 'Data.IssueList[].Code,Data.IssueList[].Name,Data.IssueList[].Priority' --limit 20 --json
|
|
45
|
+
|
|
46
|
+
# filtered list within a project — IssueType required; filter with Conditions
|
|
47
|
+
coding call DescribeIssueList --data '{
|
|
48
|
+
"ProjectName":"demo", "IssueType":"ALL", "Offset":0, "Limit":20,
|
|
49
|
+
"SortKey":"UPDATED_AT", "SortValue":"DESC",
|
|
50
|
+
"Conditions":[
|
|
51
|
+
{"Key":"STATUS_TYPE","Value":"TODO,PROCESSING"},
|
|
52
|
+
{"Key":"ASSIGNEE","Value":"254"},
|
|
53
|
+
{"Key":"KEYWORD","Value":"login"}
|
|
54
|
+
]
|
|
55
|
+
}' --select 'IssueList[].Code,IssueList[].Name,IssueList[].Priority,IssueList[].IssueStatusName' --json
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
**Condition keys** (`Key`, with comma-separated `Value` for multi-select): `STATUS`, `STATUS_TYPE`
|
|
59
|
+
(`TODO`/`PROCESSING`/`COMPLETED`), `ASSIGNEE`/`CREATOR`/`WATCHER` (user ids), `PRIORITY` (`0`–`3`),
|
|
60
|
+
`LABEL`, `MODULE`, `ITERATION`, `KEYWORD` (name/code fuzzy), `ISSUE_TYPE`, `CREATED_AT`/`UPDATED_AT`/
|
|
61
|
+
`DUE_DATE`/`START_DATE` (range `"2020-08-01_2020-08-31"`), `WORKING_HOURS` (range `"0.1_5.0"`),
|
|
62
|
+
`CUSTOM` (also set `CustomFieldId`). Use `ConstValue:"UNSPECIFIC"` to match "unassigned/unset".
|
|
63
|
+
For paged results with totals use `DescribeIssueListWithPage`.
|
|
64
|
+
|
|
65
|
+
## 4. Create an issue
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
coding call CreateIssue --data '{
|
|
69
|
+
"ProjectName":"demo", "Type":"REQUIREMENT", "Name":"用户登录支持短信验证码",
|
|
70
|
+
"Priority":"2", "Description":"...", "AssigneeId":254,
|
|
71
|
+
"IterationCode":1001, "DueDate":"2026-06-01"
|
|
72
|
+
}' --json
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
- `Name`, `Type`, `Priority`, `ProjectName` are the only required fields.
|
|
76
|
+
- `SUB_TASK` **requires** `ParentCode`; `EPIC`/`SUB_TASK` ignore `IterationCode`/`EpicCode`.
|
|
77
|
+
- Set `IssueTypeId` only if the project has multiple configured types for that `Type` (from §2).
|
|
78
|
+
- Defaults to the type's initial status; pass an optional `StatusId` (resolved in §2) to create it
|
|
79
|
+
in a specific status, or transition afterward via `ModifyIssue` (§6).
|
|
80
|
+
|
|
81
|
+
## 5. Read one issue
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
coding call DescribeIssue --param ProjectName=demo --param IssueCode=42 --json
|
|
85
|
+
coding call DescribeIssueCommentList --param ProjectName=demo --param IssueCode=42 \
|
|
86
|
+
--select 'CommentList[].CommentId,CommentList[].Content,CommentList[].CreatorId' --json
|
|
87
|
+
# activity log — ActionType + Target are BOTH required and combine (e.g. UPDATE+STATUS = status changes,
|
|
88
|
+
# UPDATE+ASSIGNEE = reassignments, CREATE+SELF = creation). Or use DescribeIssueStatusChangeLogList.
|
|
89
|
+
coding call DescribeIssueLogList --param ProjectName=demo --param IssueCode=42 \
|
|
90
|
+
--param ActionType=UPDATE --param Target=STATUS --json
|
|
91
|
+
coding call DescribeSubIssueList --param ProjectName=demo --param IssueCode=42 --json # children
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## 6. Update — fields, assignee, status, iteration
|
|
95
|
+
|
|
96
|
+
`ModifyIssue` is the single write path; pass `ProjectName` + `IssueCode` plus only the fields you change.
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
# transition status: resolve StatusId from §2, then set it
|
|
100
|
+
coding call ModifyIssue --param ProjectName=demo --param IssueCode=42 --param StatusId=44318126 --json
|
|
101
|
+
|
|
102
|
+
# reassign + bump priority
|
|
103
|
+
coding call ModifyIssue --param ProjectName=demo --param IssueCode=42 \
|
|
104
|
+
--param AssigneeId=254 --param Priority=3 --json
|
|
105
|
+
|
|
106
|
+
# move into / out of an iteration
|
|
107
|
+
coding call ModifyIssue --param ProjectName=demo --param IssueCode=42 --param IterationCode=1001 --json
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
- Description has its own action: `ModifyIssueDescription` (long rich text).
|
|
111
|
+
- Labels/watchers/releases use add+`Del…`/`Update…` list params (e.g. `LabelIds` to add, `DelLabelIds`
|
|
112
|
+
to remove) — check `coding schema ModifyIssue` for the exact field.
|
|
113
|
+
- Use `--dry-run` first when the user wants to see the change before it lands.
|
|
114
|
+
|
|
115
|
+
## 7. Comment & log work hours
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
# top-level comment: ParentId is required — use 0 for a root comment, or a comment Id to reply
|
|
119
|
+
coding call CreateIssueComment --param ProjectName=demo --param IssueCode=42 \
|
|
120
|
+
--param ParentId=0 --param Content="Reviewed, looks good." --json
|
|
121
|
+
|
|
122
|
+
# log work hours (StartAt is an epoch-ms timestamp; hours are floats)
|
|
123
|
+
coding call CreateIssueWorkHours --data '{
|
|
124
|
+
"ProjectName":"demo","IssueCode":42,"SpendHour":3.5,"RemainingHour":1.0,
|
|
125
|
+
"StartAt":1716249600000,"WorkingDesc":"实现短信发送"}' --json
|
|
126
|
+
coding call DescribeIssueWorkLogList --param ProjectName=demo --param IssueCode=42 --json
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## 8. Iterations (sprints) & releases
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
coding call DescribeIterationList --param ProjectName=demo \
|
|
133
|
+
--select 'Data.List[].Code,Data.List[].Name,Data.List[].Status' --json
|
|
134
|
+
coding call CreateIteration --data '{"ProjectName":"demo","Name":"Sprint 12",
|
|
135
|
+
"StartAt":"2026-05-25","EndAt":"2026-06-07","Goal":"登录改版"}' --json
|
|
136
|
+
|
|
137
|
+
# batch-plan issues into an iteration
|
|
138
|
+
coding call PlanIterationIssue --data '{"ProjectName":"demo","IterationCode":1001,
|
|
139
|
+
"IssueCode":[42,43,44]}' --json
|
|
140
|
+
|
|
141
|
+
# start / complete / reopen a sprint — Operator ∈ start|complete|restart
|
|
142
|
+
coding call ModifyIterationStatus --param ProjectName=demo --param IterationCode=1001 \
|
|
143
|
+
--param Operator=start --param StartAt=2026-05-25 --json
|
|
144
|
+
# completing requires EndAt; JoinIterationCode optionally carries unfinished issues into another sprint
|
|
145
|
+
coding call ModifyIterationStatus --param ProjectName=demo --param IterationCode=1001 \
|
|
146
|
+
--param Operator=complete --param EndAt=2026-06-07 --json
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Releases (版本) mirror this: `DescribeReleaseList` / `CreateRelease` / `ModifyRelease`, and
|
|
150
|
+
`DescribeReleaseIssueList` for a release's scope.
|
|
151
|
+
|
|
152
|
+
## 9. Destructive actions
|
|
153
|
+
|
|
154
|
+
`DeleteIssue`, `DeleteIteration`, `DeleteRelease`, `DeleteIssueWorkHours`, `DeleteIssueModule`,
|
|
155
|
+
`DeleteIssueBlock`, `DeleteRequirementDefectRelation` are **gated (exit 10)**. (Comments have no
|
|
156
|
+
delete action — only `CreateIssueComment`/`ModifyIssueComment`.)
|
|
157
|
+
Follow SKILL.md's confirmation protocol: preview with `--dry-run`, get explicit user approval,
|
|
158
|
+
then re-run the same argv with `--yes`. Resolve the exact `IssueCode`/`IterationCode` first — deletes
|
|
159
|
+
are not reversible.
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
coding call DeleteIssue --param ProjectName=demo --param IssueCode=42 --dry-run --json # show the user
|
|
163
|
+
coding call DeleteIssue --param ProjectName=demo --param IssueCode=42 --yes --json # after approval
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## 10. Gotchas
|
|
167
|
+
|
|
168
|
+
- **IssueCode is project-scoped**, not global — always pair it with `ProjectName`.
|
|
169
|
+
- **Priority is `"0"`–`"3"`**, never the Chinese label. **Status is an id**, resolved per type (§2).
|
|
170
|
+
- **Type vs IssueType vs IssueTypeId**: `CreateIssue` takes `Type` (the enum); **list queries take
|
|
171
|
+
`IssueType`** (same enum, different param name — there is no `Type` param on `DescribeIssueList`/
|
|
172
|
+
`DescribeIssueListWithPage`). Add the numeric `IssueTypeId` only when a project defines multiple
|
|
173
|
+
configured types for that enum.
|
|
174
|
+
- `CreateIssueComment.ParentId` is **required** (`0` = root). `CreateIssueWorkHours.StartAt` is **epoch ms**.
|
|
175
|
+
- Large boards: always `--select` the few fields you need and `--limit` arrays — issue payloads are huge.
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# coding-org
|
|
2
|
+
|
|
3
|
+
A curated playbook for the **组织和成员 (02)** category — the 16 actions covering **team members** and
|
|
4
|
+
the **department tree**.
|
|
5
|
+
|
|
6
|
+
## 1. Two id systems — don't cross them
|
|
7
|
+
|
|
8
|
+
| Context | Input id | Notes |
|
|
9
|
+
|---|---|---|
|
|
10
|
+
| **Team member** (team-level ops) | **`UserId`** (uint64) | what Delete/Lock/Unlock/DescribeTeamMember take. In *responses* the same value is the member's `Id`. `Name`/`GlobalKey`/`Email` are **not** input ids (except `DescribeTeamMemberByEmail`). |
|
|
11
|
+
| **Department member** (membership/assignee ops) | **`RefId`** / **`RefIds[]`** | a *different* integer (部门用户 refId), obtained from `DescribeDepartmentMembers.Data.DepartmentMembers[].RefId`. **Not** the UserId. |
|
|
12
|
+
|
|
13
|
+
**Member `Status` enum** (everywhere): `0` 不活跃 · `1` 活跃 · `-1` 被锁定 · `-2` 锁定登录 · `-3` 退出团队.
|
|
14
|
+
|
|
15
|
+
## 2. Team members
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# list team members (paginated). ShowDepartment=true attaches each member's department membership.
|
|
19
|
+
coding call DescribeTeamMembers --param PageNumber=1 --param PageSize=50 \
|
|
20
|
+
--select 'Data.TeamMembers[].Id,Data.TeamMembers[].Name,Data.TeamMembers[].Email,Data.TeamMembers[].GlobalKey,Data.TeamMembers[].Status' --json
|
|
21
|
+
|
|
22
|
+
# admins only (leaner shape — Id/Name/GlobalKey, NO Email/Status/Roles)
|
|
23
|
+
coding call DescribeTeamAdminMembers --param PageNumber=1 --param PageSize=50 --select 'Data.Members[].Id,Data.Members[].Name,Data.Members[].GlobalKey' --json
|
|
24
|
+
|
|
25
|
+
# look up one member — by UserId, or by email. Both return a single object at `TeamMember` (not under Data).
|
|
26
|
+
coding call DescribeTeamMember --param UserId=254 --param ShowDepartment=true --select 'TeamMember.Id,TeamMember.Name,TeamMember.Email,TeamMember.Status,TeamMember.Roles' --json
|
|
27
|
+
coding call DescribeTeamMemberByEmail --param Email=alice@example.com --select 'TeamMember.Id,TeamMember.Name,TeamMember.GlobalKey' --json
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Lock / unlock are **two separate actions** (there is no lock flag), both keyed by `UserId`:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
coding call ModifyTeamMemberLocked --param UserId=254 --json # returns only RequestId; re-read via DescribeTeamMember to confirm Status -1
|
|
34
|
+
coding call ModifyTeamMemberUnlocked --param UserId=254 --json
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## 3. Departments — the org tree
|
|
38
|
+
|
|
39
|
+
The tree is expressed via `ParentId` (a parent department's id; **`0` = top level**). Mind that the
|
|
40
|
+
department-id param name **changes per action** (see the table in §5).
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# read the tree from a node down. GetTree=true returns the recursive subtree. Result at `DepartmentTree`.
|
|
44
|
+
coding call DescribeDepartment --param DepartmentId=4001 --param GetTree=true \
|
|
45
|
+
--select 'DepartmentTree.Id,DepartmentTree.Name,DepartmentTree.Children' --json
|
|
46
|
+
|
|
47
|
+
# create a department (ParentId=0 for a top-level one). → Department.Id
|
|
48
|
+
coding call CreateDepartment --data '{"Name":"Platform","ParentId":0}' --json
|
|
49
|
+
|
|
50
|
+
# modify — ⚠️ the dept's own id is `Id` here (not DepartmentId); Name + ParentId are also required.
|
|
51
|
+
# Changing ParentId MOVES the department under a new parent.
|
|
52
|
+
coding call ModifyDepartment --data '{"Id":4002,"Name":"Platform Eng","ParentId":4001}' --json
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## 4. Department members & assignees (负责人)
|
|
56
|
+
|
|
57
|
+
Both consume **`RefIds` (an array)** — refIds, not UserIds. Get refIds from `DescribeDepartmentMembers`.
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
# list a department's members (paginated). Pointer=true → only DIRECT members (exclude sub-departments).
|
|
61
|
+
coding call DescribeDepartmentMembers --param DepartmentId=4001 --param PageNumber=1 --param PageSize=50 \
|
|
62
|
+
--select 'Data.DepartmentMembers[].RefId,Data.DepartmentMembers[].UserId,Data.DepartmentMembers[].Name,Data.DepartmentMembers[].UserStatus' --json
|
|
63
|
+
|
|
64
|
+
# add members to departments — DepartmentIds AND RefIds are BOTH arrays (members ↔ departments)
|
|
65
|
+
coding call ModifyDepartmentMember --data '{"DepartmentIds":[4001],"RefIds":[5501,5502]}' --json
|
|
66
|
+
|
|
67
|
+
# set a department's head(s) — DepartmentId is a SINGLE id here; RefIds is still an array
|
|
68
|
+
coding call ModifyDepartmentAssignee --data '{"DepartmentId":4001,"RefIds":[5501]}' --json
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
`ModifyDepartmentMember` (which **departments a member belongs to**, plural `DepartmentIds`) vs
|
|
72
|
+
`ModifyDepartmentAssignee` (who **leads one department**, single `DepartmentId`; surfaces as
|
|
73
|
+
`Assignee:true` in a member's `Refs[]`). Different shapes — don't swap them.
|
|
74
|
+
|
|
75
|
+
## 5. Third-party (LDAP) sync
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
# fire-and-forget sync of third-party department members (currently LDAP). No params. Rate-limited to
|
|
79
|
+
# at most once per 2 minutes — don't loop on it.
|
|
80
|
+
coding call TriggerDepartmentSync --json
|
|
81
|
+
# poll status separately (no params; returns an opaque `Result`)
|
|
82
|
+
coding call DescribeDepartmentSyncStatus --select 'Result' --json
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## 6. Destructive actions (exit-10 gated)
|
|
86
|
+
|
|
87
|
+
Two actions need `--yes` (preview with `--dry-run`, get explicit approval, re-run the **same argv with
|
|
88
|
+
`--yes`** — see SKILL.md's exit-10 protocol):
|
|
89
|
+
|
|
90
|
+
- **`DeleteTeamMember`** (`UserId`) — removes the member from the team.
|
|
91
|
+
- **`DeleteDepartment`** (`DepartmentId`) — deletes a department node.
|
|
92
|
+
|
|
93
|
+
## 7. Department-id param name cheat-sheet (the #1 trap)
|
|
94
|
+
|
|
95
|
+
| Action | Dept id param | Shape |
|
|
96
|
+
|---|---|---|
|
|
97
|
+
| `CreateDepartment` | `ParentId` (parent) | scalar |
|
|
98
|
+
| `ModifyDepartment` | **`Id`** (self) + `ParentId` (parent) | scalar |
|
|
99
|
+
| `DeleteDepartment` / `DescribeDepartment` / `DescribeDepartmentMembers` / `ModifyDepartmentAssignee` | `DepartmentId` | scalar |
|
|
100
|
+
| `ModifyDepartmentMember` | **`DepartmentIds`** | **array** |
|
|
101
|
+
|
|
102
|
+
## 8. Gotchas
|
|
103
|
+
|
|
104
|
+
- **`UserId` (team ops) vs `RefId` (department member/assignee ops)** are different integers — never
|
|
105
|
+
interchange them. Read a member's `RefId` from `DescribeDepartmentMembers`.
|
|
106
|
+
- **Dept-id param name varies** (§7); **`RefIds` and (for ModifyDepartmentMember) `DepartmentIds` are
|
|
107
|
+
arrays** even for a single value.
|
|
108
|
+
- **Lock/unlock are distinct actions**, no flag.
|
|
109
|
+
- **Result wrapping**: paginated lists → `Data.<X>[]` (`Data.TeamMembers`, `Data.Members`,
|
|
110
|
+
`Data.DepartmentMembers`); single member reads → `TeamMember`; the tree → `DepartmentTree`; sync status
|
|
111
|
+
→ `Result`. Match `--select` accordingly.
|
|
112
|
+
- **`TriggerDepartmentSync` is rate-limited (≤1 / 2 min)** and returns nothing useful beyond `RequestId`
|
|
113
|
+
— poll `DescribeDepartmentSyncStatus`, don't re-trigger in a loop.
|
|
114
|
+
- **Team/department administration needs an org-admin-scoped token** — that's what an exit-8
|
|
115
|
+
`UnauthorizedOperation` is telling you here (a scope gap, not a wrong token).
|