@arcships/morula-runtime 0.1.0-alpha.2 → 0.1.0-alpha.3

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.
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "morula-cli",
3
+ "version": "0.1.0-alpha.3",
4
+ "description": "Use Morula CLI task management from DimCode.",
5
+ "interface": {
6
+ "displayName": "Morula CLI",
7
+ "shortDescription": "Operate Morula task management from DimCode."
8
+ },
9
+ "skills": "./skills"
10
+ }
@@ -0,0 +1,218 @@
1
+ ---
2
+ name: morula-cli
3
+ description: 使用 Morula CLI 管理任务、空间、成员、评论与自动化报告。当用户要求操作 Morula 任务系统或产出自动化报告时使用。
4
+ ---
5
+
6
+ # Morula CLI
7
+
8
+ ## 能力速查
9
+
10
+ | 操作 | 命令 | 风险 | 审批 |
11
+ |------|------|------|------|
12
+ | 查任务 | `morula task list [flags]`(`--mine` 仅我负责) | `read_only` | 自动 |
13
+ | 任务详情 | `morula task get <id>` | `read_only` | 自动 |
14
+ | 创建任务 | `morula task create --space <id> --title "标题" [flags]` | `write_internal` | **需确认** |
15
+ | 更新任务 | `morula task update <id> [flags]` | `write_internal` | **需确认** |
16
+ | 删除任务 | `morula task delete <id>` | `destructive` | **需预演+确认** (硬删除) |
17
+ | 查空间 | `morula space list [flags]` | `read_only` | 自动 |
18
+ | 空间详情 | `morula space get <id>` | `read_only` | 自动 |
19
+ | 查成员 | `morula space-member list --space <id>` | `read_only` | 自动 |
20
+ | 添加成员 | `morula space-member add --space <id> --principal <id> [--role <admin|member>]` | `identity_access` | **需确认** |
21
+ | 移除成员 | `morula space-member remove <member-id>` | `identity_access` | **需确认** |
22
+ | 查看评论 | `morula comment list --object <id>` | `read_only` | 自动 |
23
+ | 添加评论 | `morula comment add --object <id> --content "内容"` | `write_internal` | **需确认** |
24
+ | 删除评论 | `morula comment delete <id>` | `destructive` | **需预演+确认** (硬删除) |
25
+ | 产出报告 | `morula report create --title "标题" --content-file <path>` | `write_internal` | 自动(见下方「何时产出报告」) |
26
+ | 查看报告 | `morula report list --autopilot <id>` / `morula report get <id>` | `read_only` | 自动 |
27
+ | 归档报告 | `morula report archive <id>` | `write_internal` | **需确认** |
28
+ | 上传文件 | `morula attachment upload <file> --object <id>`(挂任务)/ `--comment <id>`(挂评论) | `write_internal` | **需确认** |
29
+
30
+ 完整参数见 [commands.md](references/commands.md)。
31
+
32
+ ## 何时产出报告(`morula report create`)
33
+
34
+ 报告是**归属于某个自动化**的产出域(正文为 Markdown),人从该自动化的卡片「报告」入口查看——不进任务看板、不占任务编号、也不写进评论。判据:
35
+
36
+ - **该产出**:一次执行得出的**结论型重内容**——扫描/巡检结果、审查结论、分析摘要、对比清单、需要留档的建议。产出后可另用 `morula task create` 建任务跟进。
37
+ - **不该产出**:过程性进度、寒暄、需要人立刻拍板的一句话(短信息走评论/收件箱,只有重内容进报告域);终端输出用户看不到,需要留档的结论必须落到报告或评论。
38
+ - 一次执行可产 0..N 份,份数由 agent 判断;长报告先写进文件再用 `--content-file <path>`(超长正文不要塞进 `--content` 命令行)。
39
+ - `--autopilot` 仅在**没有执行上下文**时才需要显式传:在 agent 任务里省略,服务端按当前任务反查所属自动化并自动绑定 `runId`;若服务端返回「当前执行上下文未关联自动化」,才补 `--autopilot <id>`。
40
+
41
+ ## 审批规则
42
+
43
+ | 风险等级 | Agent 行为 |
44
+ |---------|-----------|
45
+ | `read_only` | 直接在终端执行,结果格式化展示 |
46
+ | `write_internal` | 向用户确认"即将创建/更新 [资源名],确认?",用户同意后执行 |
47
+ | `destructive` | 先 `get <id>` 展示将被删除的资源详情 → 用户确认 → 执行,不可自动重试 |
48
+
49
+ ## 操作前收集
50
+
51
+ | 操作 | 必需信息 | 获取方式 |
52
+ |------|---------|---------|
53
+ | 创建任务 | `spaceId`, `title` | `space list` 获取 spaceId;用户提供 title |
54
+ | 更新任务 | `taskId` | `task list` 获取目标 taskId |
55
+ | 删除任务 | `taskId` | `task list` 获取 → `task get <id>` 确认标题/空间后删除 |
56
+ | 管理成员 | `spaceId`, `principalId` | `space-member list --space <id>` 获取 |
57
+ | 管理评论 | `objectId`, `content` | `task get <id>` 获取 objectId;用户提供内容 |
58
+ | 产出报告 | `title`, 正文 | 标题与正文来自本次执行的结论;长正文先写文件再 `--content-file <path>` |
59
+
60
+ ## 验证操作成功
61
+
62
+ | 操作 | 验证方法 |
63
+ |------|---------|
64
+ | create | 返回 JSON 含 `id` + `code`(如 TASK-042) |
65
+ | update | JSON 返回更新后的字段值,确认与输入一致 |
66
+ | delete | 退出码 0;再次 `get <id>` 应返回退出码 3(404) |
67
+ | login | `auth status` 应返回 `"loggedIn": true` |
68
+
69
+ ## 数据量控制
70
+
71
+ - 列表命令默认 `--page-size 10`(后端 REST 默认值),单次向用户展示不超过 20 条
72
+ - 用户要求"全部"时自动翻页,每页最多 100000 条(后端 REST 上限)
73
+ - 超过 100 条结果 → 摘要展示前 5 条 + "共 X 条,建议缩小筛选范围"
74
+ - 注意:`--page-size` 的"每页最多 50 条"限制仅存在于服务端 Agent 的 `search_objects` 工具(MCP 通道),CLI 走 REST 不受此限
75
+
76
+ ## 幂等性
77
+
78
+ | 命令 | 重试策略 |
79
+ |------|---------|
80
+ | `list` / `get` / `status` | ✅ 安全重试 |
81
+ | `create` | ⚠️ 重试可能重复创建;401/5xx 时先检查是否已创建成功再决定 |
82
+ | `update` | ✅ 安全重试(覆盖更新) |
83
+ | `delete` | ⚠️ 退出码 3(404)= 已删除,非错误 |
84
+
85
+ ## 操作约束
86
+
87
+ ### 必须遵守
88
+ 1. **先 list 再操作** — 不要猜测或编造 UUID,必须从 `list` 结果中获取
89
+ 2. **修改前确认** — `write_internal` 操作必须经用户确认
90
+ 3. **检查返回值** — 退出码非 0 时读 stderr 的 JSON,按退出码语义处理
91
+ 4. **不展示原始 JSON** — 提取关键字段(title/id/priority/state)格式化呈现
92
+
93
+ ### 常见错误
94
+ - ❌ 用 `--priority p0` → 合法值只有 `low medium high urgent`
95
+ - ❌ 同时传 `--mine` 与 `--assignee` → 互斥,二选一
96
+ - ❌ 不检查 auth status 直接 create → 先 `morula auth status`
97
+ - ❌ 对 401 反复重试同一条命令 → 应 `morula auth login` 重新认证
98
+ - ❌ 传无效枚举值 → 先查 [commands.md](references/commands.md) 确认合法值
99
+ - ❌ 在 create 时传 `--sort-order` → 仅 update 支持
100
+
101
+ ## 结果呈现
102
+
103
+ ### 列表结果 → 表格摘要
104
+ 提取 `id`、`title`、`priority`、状态名(嵌套 `state.name`)、负责人名(嵌套 `assignee.displayName`)以表格展示。有分页时提示"第 X 页,共 Y 条"。列表响应中没有顶层 `stateName`/`assigneeName` 字段。
105
+
106
+ ### 单条详情 → 字段列表
107
+ 提取关键字段以 key: value 对展示。不要展示完整 JSON。
108
+
109
+ ### 错误 → 翻译退出码
110
+
111
+ Agent 看到非零退出码时,应从 stderr 提取 JSON 中的 `code` 和 `message` 字段,按以下规则处理:
112
+
113
+ - 退出码 2(`USAGE` / `BAD_REQUEST`)→ 参数格式或值不正确。检查命令语法,对照 [commands.md](references/commands.md) 修正参数后重试。常见原因:传了不支持的枚举值(如 `--priority p0`)、日期格式错误(应 ISO 8601)。
114
+ - 退出码 3(`NOT_FOUND`)→ 请求的资源(空间/任务/成员/评论)不存在。用对应的 `list` 命令重新查询可用 ID,确认 ID 未被删除或拼写错误。
115
+ - 退出码 4(`UNAUTHENTICATED`)→ Token 过期或未登录。执行 `morula auth login --env prod` 重新认证。不要在未认证状态下反复重试业务命令。
116
+ - 退出码 5(`FORBIDDEN`)→ 当前用户对该空间/资源无操作权限。检查用户是否为空间成员、角色权限是否足够(如需要 admin 才能移除成员)。
117
+ - 退出码 6(`CONFLICT`)→ 资源状态冲突(如并发修改、重复创建)。用 `get` 重新查询最新数据,确认当前状态后再决定是否重试。避免盲目重写。
118
+ - 退出码 7(`UPSTREAM` / `NETWORK` / `TIMEOUT` / `RATE_LIMITED`)→ 网络超时、服务端 5xx 错误或频率限制。指数退避重试(1s → 2s → 4s),最多 3 次。如持续失败,告知用户稍后再试。
119
+ - 退出码 137(`CRASH`)→ CLI 进程被操作系统 SIGKILL 强制终止,无 stdout/stderr 输出(包装脚本会尝试注入诊断信息)。详见下方「退出码 137 诊断」章节。
120
+
121
+ ## 退出码 137 诊断
122
+
123
+ 当 morula CLI 返回退出码 137(SIGKILL)时,表明进程被操作系统强制终止,无 stderr 输出。常见于 macOS。
124
+
125
+ **原因**:macOS arm64 对可执行文件有严格的代码签名验证。如果 CLI 二进制(Bun 单文件产物或旧 SEA)签名无效或被破坏(`EXC_CRASH (Code Signature Invalid)`),内核会在启动时直接 SIGKILL。
126
+
127
+ **诊断步骤**:
128
+ 1. 检查二进制签名状态:
129
+ ```bash
130
+ codesign -dvvv "$(dirname $(which morula))/../skills/morula-cli/scripts/morula" 2>&1
131
+ ```
132
+ 2. 检查系统崩溃日志:打开 Console.app → Crash Reports,搜索 `morula`
133
+ 3. 确认 macOS 版本:`sw_vers`
134
+
135
+ **修复方式**(用户侧):
136
+ ```bash
137
+ BIN="$(dirname $(which morula))/../skills/morula-cli/scripts/morula"
138
+ xattr -cr "$BIN"
139
+ codesign --force --deep --sign - "$BIN"
140
+ ```
141
+
142
+ **Agent 回退策略**:如果 CLI 持续返回 137 且无法修复,Agent 应回退到直接调用 Morula REST API(`POST /objects`、`GET /spaces` 等),通过 HTTP 完成操作。注意:API 直调时需显式传递 `descriptionFormat` 字段(通过内容自动检测设置)。
143
+
144
+ ## Step 0: 使用插件命令
145
+
146
+ 插件安装后,宿主会将 `bin/` 加入 `PATH`。始终直接使用:
147
+
148
+ ```bash
149
+ morula --help # 打印所有命令与参数(JSON)
150
+ morula --version # 输出版本号 JSON
151
+ ```
152
+
153
+ 所有成功结果默认以 JSON 输出到 stdout,错误以 JSON 输出到 stderr。不要添加 `--json`。
154
+
155
+ ## Step 1: 检查认证
156
+
157
+ ```bash
158
+ morula auth status
159
+ ```
160
+
161
+ 如未登录或任何命令以退出码 `4` 返回,进入 Step 2。不要要求用户提供、复制或粘贴 Token。
162
+
163
+ ## Step 2: SkyDoor SSO 登录
164
+
165
+ ```bash
166
+ morula auth login --env prod
167
+ ```
168
+
169
+ 该命令会打开浏览器,通过 PKCE + loopback 完成登录。浏览器步骤需要用户操作;等待用户完成后再继续。登录凭据存于 `~/.morula-cli/config.yaml`(0600)。
170
+
171
+ ## Step 3: 执行业务命令
172
+
173
+ 先用列表命令发现稳定 ID,再读取或修改资源。修改前确认用户意图,不要猜测空间、任务、状态或负责人 ID。
174
+
175
+ 常用命令:
176
+
177
+ ```bash
178
+ morula space list
179
+ morula space get <space-id>
180
+ morula task list --space <space-id> --page 1 --page-size 20
181
+ morula task get <task-id>
182
+ morula task create --space <space-id> --title "标题" --priority medium
183
+ morula task update <task-id> --state <state-id> --assignee <principal-id>
184
+ ```
185
+
186
+ 字段读写(自定义字段):
187
+
188
+ ```bash
189
+ # 自定义字段(字段模板里的 select 等字段)
190
+ morula task list --space <space-id> --field plane_module=定制服务 # 按自定义字段值筛选(等值)
191
+ morula task get <task-id> # 详情附带 fieldValues
192
+ morula task create --space <space-id> --title "标题" --field plane_module=定制服务 # 创建后写入自定义字段值
193
+ ```
194
+
195
+ - `--field` 格式为 `key=value`:key 为字段模板里的 fieldKey(也接受字段名),list 筛选需配合 `--space` 解析字段模板。
196
+ - `list` 默认返回字段值(includeFieldValues)。
197
+
198
+ 我的任务(用户问"我有哪些任务"时使用):
199
+
200
+ ```bash
201
+ morula task list --mine # 仅当前用户负责的任务(自动解析,无需传 --assignee)
202
+ ```
203
+
204
+ 完整参数见 [commands.md](references/commands.md),认证和错误处理见 [authentication.md](references/authentication.md)。
205
+
206
+ ## 退出码
207
+
208
+ | 退出码 | stderr `code` | 含义 | Agent 处理 |
209
+ |--------|--------------|------|-----------|
210
+ | `0` | — | 成功,stdout 为 JSON 结果 | 提取字段格式化展示 |
211
+ | `1` | `ERROR` | 未分类的内部错误 | 读取 `message` 告知用户,记录上下文后重新评估 |
212
+ | `2` | `USAGE` / `BAD_REQUEST` | 参数格式或值不正确 | 检查命令语法和参数值,对照 [commands.md](references/commands.md) 修正后重试 |
213
+ | `3` | `NOT_FOUND` | 资源(空间/任务/成员/评论)不存在 | 用 `list` 重新查询可用 ID,确认 ID 未被删除或输入错误 |
214
+ | `4` | `UNAUTHENTICATED` | Token 过期或未登录 | 执行 `morula auth login --env prod` 重新认证 |
215
+ | `5` | `FORBIDDEN` | 无操作权限 | 检查用户角色和空间权限;如需提权,告知用户联系管理员 |
216
+ | `6` | `CONFLICT` | 资源状态冲突(并发修改/重复创建) | 用 `get` 重新查询最新状态后谨慎重试,避免盲目覆盖 |
217
+ | `7` | `UPSTREAM` / `NETWORK` / `TIMEOUT` / `RATE_LIMITED` | 网络超时、服务端 5xx 或限频 | 指数退避重试(1s→2s→4s),最多 3 次;持续失败则告知用户稍后再试 |
218
+ | `137` | `CRASH` | 进程被 SIGKILL 强制终止(macOS 代码签名验证失败) | 见下方「退出码 137 诊断」章节;无法修复时回退到直接调用 REST API |
@@ -0,0 +1,21 @@
1
+ # 认证与配置
2
+
3
+ > CLI-SPLIT-001:业务 CLI(`morula`)与全局运行时 CLI(`morula-runtime`,`@arcships/morula-runtime`)**共享同一认证配置**(`~/.morula-cli/config.yaml`)。设备首次登录推荐用 `morula-runtime auth login`(引导命令以 morula-runtime 开头);业务命令登录也可直接用 `morula auth login`。两者任一登录成功后,两个 CLI 均可使用。
4
+
5
+ `morula auth login` 使用 OAuth2 PKCE S256:CLI 在 `127.0.0.1` 随机端口监听一次性回调,生成 verifier/challenge/state,通过 morula-server 代理 SkyDoor SSO,最后交换 180 天有效的 Morula JWT。
6
+
7
+ 配置路径默认是 `~/.morula-cli/config.yaml`,目录权限 0700、文件权限 0600。支持多个 context:
8
+
9
+ ```yaml
10
+ currentContext: test
11
+ contexts:
12
+ test:
13
+ url: https://morula.basecastle.com/api
14
+ token: <redacted>
15
+ ```
16
+
17
+ 地址优先级:`--url` > `MORULA_API_URL` > 保存 context > 内建环境。Token 优先级:`--token` > `MORULA_TOKEN` > 与目标地址绑定的保存 context。
18
+
19
+ 当前构建 target 为 `production`,默认 context 为 `prod`(https://morula.fazhiplus.com/api)。 若覆盖目标地址,保存的 Token 不会自动发送,必须显式传入 Token。
20
+
21
+ 安全规则:不得显示、记录或提交配置中的 token;不得要求用户在聊天中粘贴 token。401 对应退出码 4,应重新运行浏览器登录。
@@ -0,0 +1,401 @@
1
+ # 命令参考
2
+
3
+ ## 全局参数
4
+
5
+ | Flag | Type | 说明 |
6
+ |------|------|------|
7
+ | `--env` | string | 选择环境 context |
8
+ | `--url` | URL | 覆盖 API 地址 |
9
+ | `--token` | string | 仅本次调用临时覆盖 Token(不持久化,不记录) |
10
+
11
+ ## 退出码速查
12
+
13
+ | 退出码 | 含义 | Agent 行为 |
14
+ |--------|------|-----------|
15
+ | 0 | 成功 | 按"结果呈现"规则格式化输出 |
16
+ | 1 | 未分类错误 | 展示错误信息 |
17
+ | 2 | 参数错误 | 修正参数后重试 |
18
+ | 3 | 资源不存在 | 确认 ID 是否正确 |
19
+ | 4 | 未认证 | 执行 `morula auth login --env {{DEFAULT_CONTEXT}}` |
20
+ | 5 | 无权限 | 告知用户权限不足 |
21
+ | 6 | 冲突 | 重新查询最新数据后谨慎重试 |
22
+ | 7 | 网络/服务端错误 | 稍后重试,不要重复调用 |
23
+
24
+ ---
25
+
26
+ ## `morula auth login`
27
+
28
+ 打开浏览器完成 SkyDoor SSO 登录(OAuth2 PKCE S256 + loopback callback)。Token 存于 `~/.morula-cli/config.yaml`(0600)。
29
+
30
+ **超时**:默认 5 分钟,可通过 `MORULA_LOGIN_TIMEOUT_MS` 环境变量覆盖。
31
+
32
+ **风险**:`read_only`(仅获取凭据)。
33
+
34
+ **幂等性**:可以重复执行,新 Token 覆盖旧 Token。
35
+
36
+ **返回示例**:
37
+ ```json
38
+ {"loggedIn": true, "context": "test", "baseUrl": "https://morula.basecastle.com/api", "expiresIn": 15552000}
39
+ ```
40
+
41
+ ---
42
+
43
+ ## `morula auth logout`
44
+
45
+ 撤销服务端 Token 并清除本地配置。
46
+
47
+ **风险**:`write_internal`。
48
+
49
+ ---
50
+
51
+ ## `morula auth status`
52
+
53
+ 展示当前 context、API 地址、登录状态和用户信息。
54
+
55
+ **风险**:`read_only`。
56
+
57
+ **返回示例**:
58
+ ```json
59
+ {"loggedIn": true, "context": "test", "baseUrl": "https://morula.basecastle.com/api", "user": {"displayName": "张三", "username": "zhangsan"}}
60
+ ```
61
+ 未登录:
62
+ ```json
63
+ {"loggedIn": false, "context": "test", "baseUrl": "https://morula.basecastle.com/api"}
64
+ ```
65
+
66
+ ---
67
+
68
+ ## `morula task list`
69
+
70
+ **风险**:`read_only`。**幂等性**:✅ 安全重试。
71
+
72
+ | Flag | Type | Enum / Format | Default | API Mapping | 说明 |
73
+ |------|------|---------------|---------|-------------|------|
74
+ | `--space` | UUID | - | - | `spaceId` | 空间 ID,从 `space list` 获取 |
75
+ | `--page` | number | ≥ 1 | 1 | `page` | 页码 |
76
+ | `--page-size` | number | 1–50 | 20 | `pageSize` | 每页条数,后端最大 50 |
77
+ | `--search` | string | - | - | `search` | 模糊匹配标题、描述、编码 |
78
+ | `--priority` | enum | `low` `medium` `high` `urgent` | - | `priority` | |
79
+ | `--state` | UUID | - | - | `currentStateId` | 状态 ID |
80
+ | `--assignee` | UUID | - | - | `assigneePrincipalId` | 负责人主体 ID |
81
+ | `--mine` | boolean | - | `false` | 解析为 `assigneePrincipalId` | 仅查询当前登录用户负责的任务(自动经 `auth profile` 解析,与 `--assignee` 互斥) |
82
+ | `--principal` | UUID | - | - | `principalId` | 关联用户主体 ID(同时匹配负责人和报告人) |
83
+ | `--sort` | enum | `createdAt` `updatedAt` `priority` `sortOrder` `title` | - | `sort` | 排序字段 |
84
+ | `--order` | enum | `asc` `desc` | - | `order` | 排序方向 |
85
+ | `--field` | string | `key=value` | - | `fieldFilters` | 字段筛选:自定义字段(等值匹配,多条件逗号分隔 AND,需配合 `--space` 解析字段模板) |
86
+
87
+ **返回结构**:
88
+ ```json
89
+ {
90
+ "data": [
91
+ {
92
+ "id": "550e8400-e29b-41d4-a716-446655440000",
93
+ "title": "UI 设计方案评审",
94
+ "priority": "high",
95
+ "currentStateId": "550e8400-...",
96
+ "assigneePrincipalId": "550e8400-...",
97
+ "spaceId": "550e8400-...",
98
+ "fieldValues": [
99
+ { "schemaFieldId": "…", "valueText": "red" }
100
+ ],
101
+ "schemaFields": [
102
+ { "fieldKey": "field_priority", "fieldName": "自定义字段", "fieldType": "select" }
103
+ ]
104
+ }
105
+ ],
106
+ "total": 42,
107
+ "page": 1,
108
+ "pageSize": 20
109
+ }
110
+ ```
111
+
112
+ **示例**:
113
+ ```bash
114
+ morula task list --space <space-id> --page 1 --page-size 20
115
+ morula task list --priority high --assignee <principal-id>
116
+ morula task list --mine
117
+ morula task list --search "设计方案"
118
+ ```
119
+
120
+ ---
121
+
122
+ ## `morula task get <id>`
123
+
124
+ | Positional | Type | 说明 |
125
+ |-----------|------|------|
126
+ | `<id>` | UUID | 任务 ID,从 `task list` 获取 |
127
+
128
+ **风险**:`read_only`。**幂等性**:✅ 安全重试。
129
+
130
+ **返回结构**:含 `title`、`description`、`priority`、`currentStateId`、`assigneePrincipalId`、`estimateHours`、`visibility`、`schemaId`、`createdAt`、`updatedAt`、`participants`、`comments`。
131
+
132
+ ---
133
+
134
+ ## `morula task create`
135
+
136
+ **风险**:`write_internal` — 执行前须向用户确认 spaceId + title。
137
+
138
+ **幂等性**:⚠️ 重试可能重复创建。401/5xx 时先 `task list` 检查是否已被创建,再决定是否重试。
139
+
140
+ **必填**
141
+
142
+ | Flag | Type | Mapping | 说明 |
143
+ |------|------|---------|------|
144
+ | `--space` | UUID | `spaceId` | 目标空间 ID,从 `space list` 获取 |
145
+ | `--title` | string | `title` | 任务标题 |
146
+
147
+ **可选**
148
+
149
+ | Flag | Type | Enum / Format | Default | Mapping |
150
+ |------|------|---------------|---------|---------|
151
+ | `--description` | string | rich HTML | - | `description` |
152
+ | `--priority` | enum | `low` `medium` `high` `urgent` | `medium` | `priority` |
153
+ | `--state` | UUID | 状态 ID | - | `currentStateId` |
154
+ | `--assignee` | UUID | 负责人主体 ID | - | `assigneePrincipalId` |
155
+ | `--owner` | UUID | 拥有者主体 ID | - | `ownerPrincipalId` |
156
+ | `--visibility` | enum | `private` `space` `restricted` `public` | `space` | `visibility` |
157
+ | `--estimate-hours` | number | 小时数,如 `8` | - | `estimateHours` |
158
+ | `--schema` | UUID | 字段模板 ID | - | `schemaId` |
159
+ | `--field` | string | `key=value` | - | 字段值写入(POST /object-field-values upsert) |
160
+
161
+ **返回**:新任务完整信息,含 `id` + `code`(如 TASK-042)。
162
+
163
+ **示例**:
164
+ ```bash
165
+ morula task create --space <space-id> --title "完成首页开发"
166
+ morula task create --space <space-id> --title "UI评审" --priority high --assignee <principal-id>
167
+ ```
168
+
169
+ ---
170
+
171
+ ## `morula task update <id>`
172
+
173
+ **风险**:`write_internal` — 执行前须向用户确认 taskId + 修改内容。
174
+
175
+ **幂等性**:✅ 覆盖更新,安全重试。至少传一个可选 flag。
176
+
177
+ | Positional | Type | 说明 |
178
+ |-----------|------|------|
179
+ | `<id>` | UUID | 任务 ID,从 `task list` 获取 |
180
+
181
+ **可选**(至少一个)
182
+
183
+ | Flag | Type | Enum / Format | Mapping |
184
+ |------|------|---------------|---------|
185
+ | `--title` | string | - | `title` |
186
+ | `--description` | string | rich HTML | `description` |
187
+ | `--priority` | enum | `low` `medium` `high` `urgent` | `priority` |
188
+ | `--state` | UUID | 状态 ID | `currentStateId` |
189
+ | `--assignee` | UUID | 负责人主体 ID | `assigneePrincipalId` |
190
+ | `--visibility` | enum | `private` `space` `restricted` `public` | `visibility` |
191
+ | `--estimate-hours` | number | 小时数 | `estimateHours` |
192
+ | `--schema` | UUID | 字段模板 ID | `schemaId` |
193
+ | `--sort-order` | number | 排序值 | `sortOrder` |
194
+ | `--field` | string | `key=value`(空 value 清空) | 字段值写入(POST/DELETE /object-field-values) |
195
+
196
+ **示例**:
197
+ ```bash
198
+ morula task update <id> --state <state-id>
199
+ morula task update <id> --assignee <principal-id>
200
+ morula task update <id> --title "更新后的标题" --priority urgent
201
+ morula task update <id> --sort-order 10
202
+ ```
203
+
204
+ ---
205
+
206
+ ## `morula space list`
207
+
208
+ **风险**:`read_only`。**幂等性**:✅ 安全重试。
209
+
210
+ | Flag | Type | Default | Mapping | 说明 |
211
+ |------|------|---------|---------|------|
212
+ | `--page` | number | 1 | `page` | 页码 |
213
+ | `--page-size` | number | 20 | `pageSize` | 每页条数 |
214
+ | `--keyword` | string | - | `keyword` | 模糊匹配空间名称 |
215
+
216
+ **返回结构**:
217
+ ```json
218
+ {
219
+ "data": [
220
+ {
221
+ "id": "550e8400-...",
222
+ "name": "产品研发",
223
+ "description": "产品研发项目空间",
224
+ "objectCount": 42,
225
+ "memberCount": 8
226
+ }
227
+ ],
228
+ "total": 5,
229
+ "page": 1,
230
+ "pageSize": 20
231
+ }
232
+ ```
233
+
234
+ ---
235
+
236
+ ## `morula space get <id>`
237
+
238
+ | Positional | Type | 说明 |
239
+ |-----------|------|------|
240
+ | `<id>` | UUID | 空间 ID,从 `space list` 获取 |
241
+
242
+ **风险**:`read_only`。**幂等性**:✅ 安全重试。
243
+
244
+ **返回结构**:含 `name`、`description`、`visibility`、`ownerPrincipalId`、`members`(成员列表,含 roleCode)、`workflowId`、`schemaId`、`objectCount`、`createdAt`、`updatedAt`。
245
+
246
+ ---
247
+
248
+ ## `morula task delete <id>`
249
+
250
+ | Positional | Type | 说明 |
251
+ |-----------|------|------|
252
+ | `<id>` | UUID | 任务 ID,从 `task list` 获取 |
253
+
254
+ **风险**:`destructive` — 必须先 `task get <id>` 展示任务标题和空间,经用户确认后执行。⚠️ 此为硬删除,数据不可恢复。
255
+
256
+ ---
257
+ ## `morula space-member list`
258
+
259
+ **风险**:`read_only`。**幂等性**:✅。
260
+
261
+ | Flag | Type | Mapping | 说明 |
262
+ |------|------|---------|------|
263
+ | `--space` | UUID | `spaceId` | 空间 ID,必填 |
264
+
265
+ ---
266
+
267
+ ## `morula space-member add`
268
+
269
+ **风险**:`identity_access`。**幂等性**:⚠️ 重复添加可能 409。
270
+
271
+ | Flag | Type | Enum | Mapping |
272
+ |------|------|------|---------|
273
+ | `--space` | UUID | 必填 | `spaceId` |
274
+ | `--principal` | UUID | 必填 | `principalId` |
275
+ | `--role` | enum | `admin` `member`(默认 `member`) | `roleCode` |
276
+
277
+ ---
278
+
279
+ ## `morula space-member update <member-id>`
280
+
281
+ **风险**:`identity_access`。`--role` 必填。**幂等性**:✅。
282
+
283
+ ---
284
+
285
+ ## `morula space-member remove <member-id>`
286
+
287
+ **风险**:`identity_access`。**幂等性**:⚠️ 404 = 已移除。
288
+
289
+ ---
290
+
291
+ ## `morula comment list`
292
+
293
+ **风险**:`read_only`。**幂等性**:✅。
294
+
295
+ | Flag | Type | Mapping | 说明 |
296
+ |------|------|---------|------|
297
+ | `--object` | UUID | `objectId` | 任务 ID,必填 |
298
+
299
+ ---
300
+
301
+ ## `morula comment get <id>`
302
+
303
+ **风险**:`read_only`。**幂等性**:✅。
304
+
305
+ ---
306
+
307
+ ## `morula comment add`
308
+
309
+ **风险**:`write_internal`。**幂等性**:⚠️。
310
+
311
+ | Flag | Type | Mapping |
312
+ |------|------|---------|
313
+ | `--object` | UUID | `objectId` |
314
+ | `--content` | string | `content` |
315
+ | `--parent` | UUID | `parentCommentId` |
316
+
317
+ ---
318
+
319
+ ## `morula comment update <id>`
320
+
321
+ **风险**:`write_internal`。`--content` 必填。**幂等性**:✅。
322
+
323
+ ---
324
+
325
+ ## `morula comment delete <id>`
326
+
327
+ **风险**:`destructive` — 必须先 `comment get <id>` 展示评论内容,经用户确认后执行。⚠️ 此为硬删除,数据不可恢复。
328
+
329
+ ---
330
+
331
+ ## `morula attachment upload <file>`
332
+
333
+ 上传本机文件并挂接为附件(智能体 → 平台回传)。
334
+
335
+ **风险**:`write_internal`。**幂等性**:⚠️ 重试会重复创建附件。
336
+
337
+ **Flag**(`--object`/`--comment`/`--ag-message` 三选一,互斥;全不传则智能归并):
338
+
339
+ | Flag | Type | Mapping | 说明 |
340
+ |------|------|---------|------|
341
+ | `--object` | UUID | `resourceId`(type=object) | 挂到任务对象附件 |
342
+ | `--comment` | UUID | `resourceId`(type=comment) | 挂到评论附件 |
343
+ | `--ag-message` | boolean | `resourceType=ag_message` | 挂到 Chat 会话最新消息附件 |
344
+ | `--task` | UUID | `taskId` | AgentTask 任务 ID(从 task-context.md 读);纯 Chat 任务上传时用于归并到会话消息 |
345
+ | `--inline` | boolean | `isInline` | 仅正文内嵌,不进附件列表 |
346
+
347
+ **Positional**:`<file>` 本机文件路径(必填)。
348
+
349
+ **返回**:`{ id, resourceType, resourceId, fileUrl, fileName, fileType, fileSize, downloadUrl }`。`downloadUrl` 为签名下载链接,可写进交付评论供用户访问。
350
+
351
+ **智能归并**:不传 `--object`/`--comment`/`--ag-message` 时,服务端按任务绑定对象自动决定——有 object 挂 object;**纯对话(无对象)任务必须带 `--task <AgentTaskID>`**,服务端据此挂到该 Chat 会话最新消息(ag_message)。
352
+
353
+ **注意**:文件类型不限(服务端放开到通用类型),单文件上限 20MB;挂 `object`/`comment` 时 agent_task 作用域要求落在任务绑定对象内。
354
+
355
+ ---
356
+
357
+ ## `morula report create`
358
+
359
+ 产出自动化报告(独立产出域 `agent_reports`,挂在所属自动化下)。
360
+
361
+ **风险**:`write_internal`(写平台,但不改动用户已有资源 → 审批为**自动**,不需要用户确认)。**幂等性**:⚠️ 重试会重复产出(先查再决定是否重试)。
362
+
363
+ **何时用**:一次执行得出的**结论型重内容**(扫描/巡检结果、审查结论、分析摘要、对比清单)。过程进度、寒暄、需要人拍板的一句话走评论;正文为 Markdown,人从所属自动化卡片的「报告」入口查看——不进任务看板、不占任务编号。详见 SKILL.md「何时产出报告」。
364
+
365
+ | Flag | Type | Mapping | 说明 |
366
+ |------|------|---------|------|
367
+ | `--title` | string | `title` | 必填,报告标题 |
368
+ | `--content` | markdown | `content` | 正文(与 `--content-file` 二选一) |
369
+ | `--content-file` | path | `content` | 从本机文件读取正文(长报告用;与 `--content` 互斥) |
370
+ | `--space` | UUID | `spaceId` | 可选,归属空间 |
371
+ | `--autopilot` | UUID | `autopilotId` | 可选;缺省由服务端按当前执行上下文反查(taskId → runId → 自动化)并绑定 `runId`;无执行上下文时必填 |
372
+
373
+ **返回**:`{ id, tenantId, autopilotId, runId, spaceId, title, status: "ready", createdBy, createdAt, updatedAt }`。
374
+
375
+ **错误**:退出码 2 — `title/content 不能为空`、`报告必须归属于某个自动化:当前执行上下文未关联自动化,请显式传 --autopilot`;退出码 3 — `Autopilot 不存在`(`--autopilot` 值不对)。
376
+
377
+ ---
378
+
379
+ ## `morula report get <id>`
380
+
381
+ **风险**:`read_only`。**幂等性**:✅。返回含 Markdown 正文 `content`。
382
+
383
+ ---
384
+
385
+ ## `morula report list`
386
+
387
+ **风险**:`read_only`。**幂等性**:✅。
388
+
389
+ | Flag | Type | Mapping | 说明 |
390
+ |------|------|---------|------|
391
+ | `--autopilot` | UUID | 路径 `/agent-autopilots/:id/reports` | 必填,报告的归属自动化 |
392
+ | `--page` / `--page-size` | number | query | 分页 |
393
+ | `--status` | `ready\|archived` | query | 可选;缺省不传(服务端默认过滤已归档),要看归档的报告显式传 `--status archived` |
394
+
395
+ **返回**:`{ data, total, page, pageSize }`。
396
+
397
+ ---
398
+
399
+ ## `morula report archive <id>`
400
+
401
+ **风险**:`write_internal`(审批:**需确认**)。**幂等性**:✅(重复归档结果一致)。归档后报告默认列表不再展示,正文仍在(`report get` 可查)。