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

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,42 @@
1
+ # SKILL 评估用例
2
+
3
+ > 用于验证 morula-cli SKILL 的激活准确性和输出质量。
4
+
5
+ ## 激活测试(should-trigger)
6
+
7
+ 以下输入应触发 morula-cli 加载:
8
+
9
+ | # | 用户输入 | 预期行为 |
10
+ |---|---------|---------|
11
+ | 1 | "查一下我的任务" | 加载 morula-cli → `task list` |
12
+ | 2 | "帮我创建一个高优先级任务" | 加载 morula-cli → 收集 spaceId + title → 确认 → `task create` |
13
+ | 3 | "把 TASK-042 改成已完成" | 加载 morula-cli → `task list` 获取 id → 确认 → `task update` |
14
+ | 4 | "我的空间有哪些" | 加载 morula-cli → `space list` |
15
+ | 5 | "看看产品研发空间" | 加载 morula-cli → `space list` 获取 id → `space get` |
16
+ | 6 | "登录 morula" | 加载 morula-cli → `auth login` |
17
+
18
+ ## 不激活测试(should-not-trigger)
19
+
20
+ 以下输入不应触发 morula-cli 加载:
21
+
22
+ | # | 用户输入 | 预期行为 |
23
+ |---|---------|---------|
24
+ | 1 | "任务管理系统怎么设计" | 不加载(架构讨论,非操作请求) |
25
+ | 2 | "帮我写个 Python 脚本" | 不加载(非 Morula 操作) |
26
+ | 3 | "morula 是什么" | 不加载(产品介绍,非操作请求) |
27
+
28
+ ## 输出测试(output eval)
29
+
30
+ 验证 Agent 在具体场景下的行为是否符合最佳实践:
31
+
32
+ | # | 场景 | 预期 Agent 行为 | 验证点 |
33
+ |---|------|----------------|--------|
34
+ | 1 | 用户说"创建任务 priority 为 p0" | Agent 拒绝:`--priority` 合法值为 `low medium high urgent` | 枚举校验 |
35
+ | 2 | `task update` 不传 id | Agent 提示需要 taskId | 必填检查 |
36
+ | 3 | `task create` 不传 spaceId | Agent 提示先 `space list` 获取 spaceId | 前置依赖 |
37
+ | 4 | 命令返回退出码 4(401) | Agent 执行 `morula auth login`,不向用户报错 | 自动恢复 |
38
+ | 5 | `task list` 返回 200 条 | Agent 展示前 20 条 + "第 1 页,共 200 条" | 数据量控制 |
39
+ | 7 | 创建任务成功 | Agent 展示 `code`(如 TASK-042)+ `title`,不展示完整 JSON | 输出格式化 |
40
+ | 8 | 命令返回退出码 7(5xx) | Agent 提示"服务暂时不可用,稍后重试",不重复调用 | 错误处理 |
41
+ | 9 | 用户未登录就要求创建任务 | Agent 先执行 `auth status` → 发现未登录 → 执行 `auth login` → 再 create | 认证前置 |
42
+ | 10 | `task create` 传 `--sort-order 5` | Agent 拒绝:`--sort-order` 仅 `task update` 支持 | 操作边界 |
@@ -0,0 +1,42 @@
1
+ ---
2
+ name: morula-platform
3
+ description: "Use when a Morula task needs platform interaction beyond the runtime brief — branch naming and PR/MR channel rules, checkout and multi-repo workspace, status and verdict protocols, in-run feedback, delivery and final-comment discipline, or live incident queries. Open only the reference your task needs (routing table inside); never read them all."
4
+ user-invocable: false
5
+ allowed-tools: Bash(morula *), Bash(git *), Bash(gh *)
6
+ ---
7
+
8
+ > 本文件是随 CLI 插件分发的**文档副本**。daemon 执行任务时会按平台在任务工作区
9
+ > `.agents/skills/morula-platform/` 注入**权威版本**(GitLab 任务会在 git-workflow.md 附带平台说明段,
10
+ > 并按执行 CLI 写入原生发现路径),两者正文同源。命令细节以工作区内注入的那份与 `morula <resource> --help` 为准。
11
+
12
+ # Morula 平台契约(morula-platform)
13
+
14
+ 本 SKILL 是 Morula 平台对本地智能体(daemon 执行的 AgentTask)的**操作手册入口**。
15
+ 分工:系统提示(runtime brief)管你的身份、目标与钥匙;工作区根 `AGENTS.md` 的
16
+ 「Morula 平台协作契约」段是**不变量与命令索引**(恒常生效,先读它);本 SKILL 只做按域手册的路由。
17
+
18
+ 每份手册自包含、互不依赖。按任务需要打开对应的一份或几份(通常一两份),
19
+ **不要**因为不确定就把全部手册读一遍。
20
+
21
+ ## Routing
22
+
23
+ | 手册 | 任务涉及 |
24
+ |---|---|
25
+ | `.agents/skills/morula-platform/references/workspace.md` | 开工确认现场(git status / 分支现场)、工作区布局与主仓库物化、任务详情与评论获取、环境前置(依赖 / prisma generate)、本地服务端口隔离 |
26
+ | `.agents/skills/morula-platform/references/git-workflow.md` | 分支命名与上报、`repo checkout` / `prepare` 语义、多仓库、推分支、建 PR/MR(含 GitLab 平台说明)、PR 关联与关单 |
27
+ | `.agents/skills/morula-platform/references/task-protocols.md` | 状态流转(task state / assign)、分析任务 verdict、评审任务 submit、运行中反馈(inbox / 打断)、MR 巡检评论 |
28
+ | `.agents/skills/morula-platform/references/delivery.md` | 最终总结评论纪律、`---FINAL---` 分隔符、attachment 文件回传、report 报告、交付物表述 |
29
+ | `.agents/skills/morula-platform/references/observability.md` | 排查线上行为 / 故障:gcx 引擎、数据源选择、只读边界、结果纪律 |
30
+
31
+ 跨任务类型的通用约束(CLI-only、不碰凭据、结论先行、纯问答不建分支等)在 `AGENTS.md` 契约核心段,
32
+ 不在本表内重复。
33
+
34
+ ## 降级说明
35
+
36
+ 若 `skill` 工具按名加载本 SKILL 报 `Unknown skill`(发现范围不含项目级目录),直接读本文件与
37
+ references 文件即可,**不要因为加载失败就跳过契约**。
38
+
39
+ ## References
40
+
41
+ `.agents/skills/morula-platform/references/working-on-issues-source-map.md` —— 每条契约对应的服务端/CLI 实现位置(`file:line`),
42
+ 用于校准契约与实现一致。
@@ -0,0 +1,60 @@
1
+ # 交付纪律(评论 / 文件 / 报告)
2
+
3
+ > 评论/附件/报告命令索引见 `AGENTS.md` 契约核心段。
4
+
5
+ ## 生成文件必须回传平台(智能体 → 平台)
6
+
7
+ 若你的交付物是**文件**(报告、文档、图表格、xlsx、图片、压缩包等),且用户需要在线查看/下载,**必须**用 `morula attachment upload` 把本机文件回传到平台,而不是在消息里给一个本地相对路径/文件名(用户打不开):
8
+
9
+ - **纯 Chat 会话任务(推荐)**:本任务不关联业务对象(task-context.md 无 objectId),**必须带 `--task <AgentTaskID>`**(AgentTask ID = `morula task get`(无参)返回的 `id`(或 task-context.md 开头的 UUID)),服务端据此把文件挂到本 Chat 会话消息:
10
+ ```bash
11
+ morula attachment upload <file> --task <AgentTaskID>
12
+ ```
13
+ - **默认智能归并**(有绑定对象时):不传目标参数,服务端自动决定——有任务绑定对象挂对象:
14
+ ```bash
15
+ morula attachment upload <file>
16
+ ```
17
+ - **显式挂任务对象**(用户从任务/评论发起、任务有 objectId):
18
+ ```bash
19
+ morula attachment upload <file> --object <objectId>
20
+ ```
21
+ - **显式挂指定评论**:`morula attachment upload <file> --comment <commentId>`
22
+ - **显式挂 Chat 会话消息**:`morula attachment upload <file> --ag-message --task <AgentTaskID>`
23
+
24
+ **回传后**:命令输出 JSON,含 `downloadUrl` 与附件 `id`。在最终总结里**引用下载链接**(`http...` 或附件的可下载地址),并说明文件名即可——不要把本地绝对路径/相对文件名当交付物。<br>
25
+ **文件类型不限**,单文件上限 20MB;超限需拆分或说明,不要硬传失败。
26
+
27
+ ## 自动化的信息类产出:用 `morula report create`
28
+
29
+ 当本任务是**自动化(定时/触发)派发**的,且你的产出是给人看的**信息类结果**(巡检/扫描结论、摘要、分析),用报告承载:
30
+
31
+ ```bash
32
+ morula report create --title "<一句话标题>" --content "<Markdown 正文>" # 正文长时用 --content-file <path>
33
+ ```
34
+
35
+ - 报告落在**本次执行所属自动化的「报告」入口**(不在任务看板、不占任务编号),归属由平台自动绑定,不用传;
36
+ - 一次执行可产出多份(一份报告一个主题);**要建工单请用任务,不要把待办事项写进报告正文**;
37
+ - 报告落库后创建者与订阅者会收到轻通知(只含标题与跳转);
38
+ - 不产出也没关系:任务终态时平台会用你的最终输出兜底落一份报告(但兜底不如你主动组织的内容清晰,信息类产出**优先主动产出**)。
39
+
40
+ ## 评论交付纪律(最终总结由你自己发布)
41
+
42
+ - **最终总结评论由你自己发布**:任务收尾时执行
43
+ ```bash
44
+ morula comment add --object <objectId> --final --content <结论>
45
+ ```
46
+ 作者=你(智能体身份);评论触发任务时服务端会**自动把它挂到触发评论下**作为回复(无需自己查评论 ID)。
47
+ **完成后必须在任务评论区留下一条你自己的总结性评论(做了什么、结果、后续),再上报任务结果**——这是交付的一部分,一条评论都没发不算完成。服务端只在你一条评论都没发时才兜底代发。
48
+ `--final` 是防重标记(同一任务重复执行只保留一条总结,重试/重跑不会发第二条;重复发送被服务端拒绝是预期内的幂等保护),不是交付判据——收尾总结推荐带上。
49
+ - **例外:评审任务不需要(也不应)发 final**——你的结论已经通过 `morula review submit` 机器协议上报,平台会据此写权威结论评论(✅ 通过 / 💬 非阻塞 / 🔁 未通过);再发一条 final 总结会让同一结论在评论区**说两遍**(服务端也会拒绝评审任务的 final)。需要发 final 的是开发 / 修复 / 分析 / 问答 / 评论触发类任务——内容**用你自己的话写**,不要套模板。
50
+ - **普通评论**(说明进展、@ 其他人或运行时)随时可发:
51
+ ```bash
52
+ morula comment add --object <objectId> --content <文本>
53
+ morula comment add --object <objectId> --content <文本> --mention-agent <stageExecutorId> # @ 阶段运行时(触发该执行器在本任务上干活)
54
+ ```
55
+ chat 会话无 objectId 的任务(纯对话派发)不发评论——最终交付由 daemon 回填 assistant 消息。
56
+ - **评论纪律:只写结论与事实**——做了什么、结果如何、用户需要知道的后续;**不写**思考过程、探索步骤、工具日志、终端输出、命令回显。用户只关心「做了什么、结果怎样」,不关心「怎么做的」。内容较多时用小标题/列表组织,结论先置顶。
57
+ - **PR 汇报仅当「任务涉及代码改动」或「用户明确问到 PR/合并」时给出**;纯问答/调研类任务不要出现 PR/分支章节。
58
+ - **任务结果文本同样只写结论**:上报的任务结果会被服务端用于缺失兜底与通知摘要——若结果里混入了中间过程(英文探索叙述、工具尝试记录、思考片段),**必须**在真正的总结之前插入独占一行的 `---FINAL---` 分隔符,服务端兜底时只保留它之后的内容(`---SUMMARY---` 同样兼容;不写时服务端退回「按总结类标题 / 水平线猜测」,猜不中会把过程文本一起兜底出去)。
59
+ - **不要把本地绝对路径当交付物**:工作目录路径只属于执行它的机器,读者打不开;生成的文件**必须先回传平台**(见上「生成文件必须回传平台」),交付物用平台下载链接或仓库内相对路径。
60
+ - 不要包含工具调试过程、内部日志、任何凭据或 token 信息。
@@ -0,0 +1,98 @@
1
+ # Git 工作流(分支 / PR / MR)
2
+
3
+ > 通用不变量(CLI-only、不推 main 等)见 `AGENTS.md` 契约核心段;工作区布局 / checkout 现场检查见 `.agents/skills/morula-platform/references/workspace.md`。
4
+
5
+ ## 本任务编号与 PR 关联
6
+
7
+ > **适用前提(PR/分支类契约)**:本节及后文 PR/分支/关单约定**仅当任务涉及代码改动时适用**。
8
+ > 纯问答、调研、分析、本地起服务类任务:**不建分支、不提 PR、最终评论不出现 PR 章节**,直接回答用户问题。
9
+
10
+ - 本任务的对外编号(在任务看板 URL / 列表可见)可能形如 `STR-101` 或 `AGENT-463963`。
11
+ - **PR 关联只由平台通道产生**(2026-09-24 定案):**只有经平台通道建出来的 PR 会自动关联到任务**——
12
+ `morula repo mr create`(推荐)或 `gh pr create` 后调 `report_pr` 工具上报。平台按自己的事实(哪个任务、
13
+ 哪条分支、哪个 workContext)认领,**不读 PR 文本**。
14
+ - **不要在 PR 标题/正文里靠任务编号「标记归属」**:服务端**不再扫描** title/branch/body 找任务编号。
15
+ 人工在 GitLab/GitHub 上手工建的 PR 平台**不关联**(不进关联区、不触发自动评审、不驱动任务状态)。
16
+ - **关单**:关联上的 PR 合并后,服务端按既有流程自动推进任务状态(全部 MR 合并 → 已合并;这些提交进入生产分支 → 已发布)。
17
+ 不需要 `Closes` 之类关键字——**关联本身就是授权**。
18
+ - 仍然建议 PR 标题以「`<任务编号>: 描述`」开头、正文写一句 `Closes <任务编号>`:**这是给人看的可读性**(平台不再依赖它),
19
+ 且是任务与 PR 之间最省事的对照线索。
20
+
21
+ ## 分支命名:由你(Agent)取名并上报
22
+
23
+ - **任务 ID 获取**:本任务的 AgentTask ID(UUID)在系统提示「基本信息」段(也是 `morula task get`(无参)返回的 `id`,`.agent_context/task-context.md` 开头亦有)。需要调用 `morula task branch` 时用它作为 taskId。
24
+ - **重要区分**:`morula task branch <taskId>` 的 taskId 用**本任务 UUID**(机器协议);MR 标题里的任务编号用**对外编号 code**(如 `AGENT-958201`)——但注意**编号只影响可读性,不再影响关联**(服务端不读 PR 文本)。
25
+ - **只有需要改代码并推分支的任务才取名**;纯问答/只读调研/本地起服务不建分支(见「决策树」)。
26
+ - **先检查当前分支**:若仓库已有 feature 分支(同任务/同一改动闭环的后续轮次复用),**直接继续用当前分支,不要新建**(在仓库目录内执行):
27
+ ```bash
28
+ cd <工作区根>/<仓库目录> && git branch --show-current # 若非空且非 main/master → 用这个分支继续改
29
+ ```
30
+ - 若当前为 detached HEAD(首次执行),且任务确实要改代码:
31
+ 1. 创建分支。分支名**严格由以下部分依次拼成,不多不少**:`<type>` + `/` + `<slug>`
32
+ - `<type>`:取下方「命名规范」清单里的一个(按任务性质选,如文档改动用 docs);
33
+ - `<slug>`:具体工作事情,小写、用 `-` 连接。
34
+ ```bash
35
+ git switch -c <type>/<slug>
36
+ ```
37
+ 例:做 mention 相关的测试补全 → 分支名 `test/mention-tests`;修复登录 401 → `fix/login-401`
38
+ 分支名**到 `<slug>` 为止就结束** —— slug 之后不再接任何内容。
39
+ 2. **通过 CLI 把分支名上报服务端**(必须,服务端据此做 PR 关联/清理):
40
+ ```bash
41
+ morula task branch <taskId> --name <type>/<slug>
42
+ ```
43
+ - **`morula task branch` 需要 `MORULA_RUNTIME_ID`**(daemon 注入的 env,用于校验你的归属)。若你的 exec 环境没有这个 env,**从主仓库目录内的 `.morula-worktree.json` 读取 `runtimeId` 字段**(完整路径 `<工作区根>/<仓库目录>/.morula-worktree.json`;工作区根下没有这个文件),用 `env MORULA_RUNTIME_ID=<该值> morula task branch ...` 或导出后再调用(不要从别处猜)。
44
+ - **命名规范**(分支名会出现在 PR、CI、历史里,必须规范):
45
+ - 前缀 type 选一:`feature`(新功能)、`fix`(缺陷修复)、`hotfix`(紧急/线上)、`docs`(文档)、`refactor`(重构)、`chore`(杂务)、`test`(测试)、`perf`(性能)、`style`(样式)、`build`(构建/依赖)、`ci`(CI)、`revert`(回滚);
46
+ - slug = 具体工作事情,小写、用 `-` 连接(可用英文;**不要用中文**,中文分支名不被多数 CI/工具链支持);
47
+ - **只按本节规则拼,不要参考/模仿仓库里已有分支的命名**:历史分支是过往产物(可能含日期后缀、任务编号等旧形态),照着它们取名会沿用旧习惯;分支名完全由上面两段决定,与仓库现有分支无关;
48
+ - **分支名到 slug 就结束**:slug 之后**不再追加任何内容**——日期、时间戳、轮次号、随机串都不要;日期不表达语义,且会让「同一件事的后续轮次复用同分支」看起来像要新建分支;
49
+ - **分支名是全仓库共享的命名空间,撞名会被拒绝**:若 `morula task branch` / `morula repo mr create` 返回 `BRANCH_OWNED_BY_OTHER_TASK`(分支名已被其他任务占用),换一个更具体的 slug 重新取名、上报后再继续;
50
+ - **禁止**用 `main`/`master`,禁止以 `-` 开头/结尾,长度 ≤ 255。
51
+ - 如果你不改代码,**不要**创建分支,也不要调用 `morula task branch`。
52
+
53
+ ## PR 关联:只走平台通道
54
+
55
+ - **关联的唯一来源是平台通道**(2026-09-24 定案):`morula repo mr create`(推荐)建 PR 时服务端当场落关联;
56
+ 或 `gh pr create` 之后调 `report_pr` 工具上报。**服务端不读 PR 文本**——title/branch/body 里写什么任务编号都不会关联。
57
+ - **人工在 GitLab/GitHub 上手工建的 PR,平台不关联**:不进任务关联区、不触发自动评审、不驱动任务状态。
58
+ 如果你希望一条 PR 关联到本任务,就必须走上面两条平台通道之一。
59
+ - **关单不需要关键字**:关联上的 PR 合并后,服务端按既有流程推进任务状态
60
+ (全部 MR 合并 → 已合并;这些提交进入生产分支 → 已发布)。**关联本身就是授权**。
61
+ - 推荐(可读性,不是关联手段):title 以「STR-101: 描述」开头、body 写一句 `Closes STR-101`——便于人和平台日志对照。
62
+
63
+ ## 什么时候推分支、提 PR(决策树)
64
+
65
+ 先判断**这次任务是否改了仓库里的代码**,再决定要不要分支/PR:
66
+
67
+ | 任务类型 | 是否建分支/上报分支名 | 是否推分支 + 建 PR |
68
+ |---|---|---|
69
+ | **改了代码**(改文件、修 bug、加功能、重构) | ✅ 取名 + `morula task branch`(见「分支命名」节) | ✅ 推 feature 分支 + 建 PR/MR(命令见下方「执行要点」,按平台选) |
70
+ | **改了代码但被环境阻断无法建 PR**(权限/远端异常/无凭据等) | ✅ 已取名 | ⚠️ 最终总结里用文字报告阻塞原因,并带上约定关键词 **`PR_BLOCKED`**(**这不是 CLI 错误码**,只是给平台/人看的标记;daemon 也会回报交付告警) |
71
+ | **只回答问题 / 调研分析**(不改仓库文件) | ❌ 不建分支 | ❌ 不推、不建 PR,直接回答用户问题(不要声明「无需 PR」等无关补充) |
72
+ | **本地起服务 / 运行命令**(不落代码到仓库) | ❌ 不建分支 | ❌ 不推、不建 PR |
73
+ | **改了代码但用户明确只要本地** | ✅ 可建分支 | ❌ 不推 PR,总结说明 |
74
+
75
+ 执行要点:
76
+
77
+ - **以下命令都在对应仓库目录内执行**(`cd <工作区根>/<仓库目录>`;工作区根不是仓库);
78
+ - 修改了代码 → **推送到 feature 分支(禁止推 main/master)并确保有 PR**;
79
+ - 分支用你在「分支命名」节取的名(或复用的已有分支)。**创建/更新 PR(MR) 的命令按平台选择**(本文件末尾的「GitLab 平台说明」段会覆盖此处的 GitHub 写法):
80
+ - **GitHub 仓库**:先查该分支是否已有 PR:
81
+ ```bash
82
+ gh pr list --head <branch> --state open # 已有 → 直接 push 更新,不要重复创建
83
+ ```
84
+ - **已有 PR**(同一改动闭环的后续轮次)→ 只 `git push -u origin <branch>` 更新,**不要**再 `gh pr create`;
85
+ - **无 PR** → 创建:
86
+ ```bash
87
+ git push -u origin <branch>
88
+ gh pr create --base <默认分支> --head <branch> --title "<任务编号>: 描述" --body "Closes <任务编号>"
89
+ ```
90
+ - **GitLab 仓库**:推分支 + 建 MR 用一条平台命令(**不要**用 `gh`、不要手写 `git push -o merge_request.create`):
91
+ ```bash
92
+ morula repo mr create <repoFullName> --branch <branch> --base <默认分支> --task-code <任务编号>
93
+ ```
94
+ 该命令等价于「推分支 + 服务端建 MR」,MR 一定建在平台绑定的仓库上,详见末尾「GitLab 平台说明」段。
95
+ - **不确定用哪条**:本任务的工作区来自哪个平台由「GitLab 平台说明」段是否存在决定——**存在即 GitLab**,按 GitLab 走。
96
+ - 没有改代码(纯调研/问答/起服务)→ **直接回答用户问题**,不要声明「无需 PR」或「未改动任何代码」这类无关补充,也不要为了形式而建 PR;
97
+ - PR 创建被阻塞(权限/测试失败/远端状态异常)→ 在最终总结中**报告阻塞原因**,不要假装任务已完成;
98
+ - **不要**切回 `main` 或 `master` 直接提交。
@@ -0,0 +1,33 @@
1
+ # 排查线上行为/故障:直接用引擎查线上事实(gcx)
2
+
3
+ **什么时候用**:任务本身是排查线上行为或故障时才用——报障、告警、错误率/延迟异常、线上数据与代码预期对不上。判断依据是**任务要回答的问题是关于线上实际发生了什么**。
4
+
5
+ **什么时候不用**:不要把它当默认动作。改代码、写功能、调研代码库、答设计问题,都不需要查线上;不要为了「多收集点信息」先查一遍。
6
+
7
+ **环境怎么来(不用自己找凭据)**:任务启动时环境里已经注入了 `GRAFANA_SERVER` / `GRAFANA_TOKEN` / `GRAFANA_ORG_ID`——直接用;本机永远没有真实凭据,不要去找上游凭据。**换源**或令牌(30 分钟)**过期**时,调运行环境接口拿一份新的:
8
+
9
+ ```bash
10
+ morula obs env # 打印当前默认源的环境(可直接 eval 的 shell export)
11
+ morula obs env --source <name|id> # 换一个数据源
12
+ ```
13
+
14
+ `morula obs env` 只**打印环境**(把 server / token / org 交给人和脚本),**不是查询命令**——查询永远用引擎。
15
+
16
+ **用哪个工具**:**直接用引擎**(`gcx`);先看它有什么、支持哪些命令,再决定怎么调(命令与语法是引擎自己的资产,不要凭记忆猜):
17
+
18
+ ```bash
19
+ gcx --help
20
+ gcx commands
21
+ ```
22
+
23
+ **只读边界**:写命令(删面板、改告警、动数据源配置之类)不是「被禁止」,而是**会被网关 403**——网关只转发只读路径。不要试图绕过(换条命令、直接打上游都过不去)。
24
+
25
+ **结果纪律**:先开小窗(`--since 1h` / `--limit` / 只取需要的字段),确认方向对了再放大;大结果让引擎 spill 或写到文件,**不要**把全量灌进上下文。
26
+
27
+ **数据源选择**:运行环境里的 `context` 给了默认 UID 就用它;没给时引擎会**按类型自动发现**——**同类型恰好一条**才用,**0 条或 ≥2 条会报错并列出候选**,按报错换一条。随时可以用下面这条看全量数据源:
28
+
29
+ ```bash
30
+ gcx datasources list
31
+ ```
32
+
33
+ **引擎自带 skill**:引擎自己带 skill(`gcx agent skills list` / `gcx agent skills get <name>`),与任务工作区的 skill 目录一并可用。
@@ -0,0 +1,110 @@
1
+ # 任务协议(状态 / 结论上报 / 运行中反馈)
2
+
3
+ > 命令索引见 `AGENTS.md` 契约核心段;最终总结与交付纪律见 `.agents/skills/morula-platform/references/delivery.md`。
4
+ > **`<taskId>` = `morula task get`(无参)返回的 `id`**(本任务 AgentTask UUID)——下文所有机器协议命令的 id 位都用它,不要用任务编号或别的 id 替代。
5
+
6
+ ## 运行中反馈:检查点与打断(本回合内生效)
7
+
8
+ 用户可以在**你正在运行的这一个回合内**发来意见——不必等本轮结束、也不必重开任务。你要在两处配合:
9
+
10
+ **① 主动查检查点(`morula task inbox`)——只在这四个时机查,不要更频繁**
11
+
12
+ ```bash
13
+ morula task inbox # 取走本线程未消费的消息(服务端标记「本回合已消费」)
14
+ morula task inbox --peek # 只看不取(确认有没有新意见,不标记消费)
15
+ ```
16
+
17
+ 四个时机(闭环枚举,**不要**每一步都查):
18
+
19
+ 1. 一批文件改动**完成之后**(准备进入下一批之前);
20
+ 2. `git commit` **之前**;
21
+ 3. `git push` / 建 PR **之前**;
22
+ 4. 收到「运行中被打断」提示时(见 ②)。
23
+
24
+ 拿到消息后:
25
+
26
+ - **有消息** → 逐条纳入本回合,按用户的意见调整,并在最终总结里**回执式说明**(「已按要求改为 X」);
27
+ - **没有消息** → **立即继续手上的事,不要展开讨论、不要复述检查过程、不要在总结里提「检查过没有新意见」**;
28
+ - 用户的意见**不得推翻它没涉及的部分**:已完成的、与意见无关的改动保留;意见与原始需求冲突时**以意见为准**并在总结里说明差异;
29
+ - 不要反复轮询(一次检查就是一次工具调用,有开销)。
30
+
31
+ **② 被打断时(用户按了「立即打断」)你会在同一会话收到新的指令**
32
+
33
+ - 上一回合在**安全点**被中断:其中的工具进度已丢弃,**被中断的工具调用没有结果**(时间线标为已中断)——需要时重新执行,不要假定它已成功;
34
+ - 新消息就是用户的最新意见:先按它调整方向,再继续完成本任务;工作区文件与 git 状态仍在,不用重做已完成的部分。
35
+
36
+ **③ 用户意见与「要不要返工」由你自己判断,平台不代做**
37
+
38
+ - 平台**不会**因为用户说了句话就回退阶段、改任务状态或派返工任务——**那是你的判断**:评估后认为必须推倒重做,就按你自己的协议表达(评审阶段用 `morula review submit` 给出结论;分析阶段用 `morula task analysis-verdict`),状态流转由服务端按既有规则驱动;
39
+ - 你只跟**当前阶段**对话:消息就是发给当前阶段负责智能体的。**不要**因为收到意见就去操作别的阶段或别的对象的资源;
40
+ - **评审阶段你只做评审**(看 diff、核对目标、出结论),**不要改代码、不要建分支/提 PR**。
41
+
42
+ > 为什么是这四个时机:检查是**工具调用**,有 token 与延迟开销;「无消息立即继续」是为了不让检查点把主线带偏。
43
+
44
+ ## 状态与任务操作:结论优先,动作为辅
45
+
46
+ - **状态推进由结论协议与事实事件驱动**:分析任务上报 `analysis-verdict`、评审任务用 `morula review submit`、合并/发布由 PR 事件驱动——**不要**用状态动作替代结论协议。
47
+ - **你可以在任务上做基础操作**(像人一样,作用域仅限本任务):
48
+ - `morula task state <taskId> --state <in_progress|review> [--reason <文本>]`:在「开发中 / 待评审」范围内自推状态;**待评审 → 开发中 = 退回开发**——平台会自动回退状态、记评审轮次并派发修复任务(同一 PR 迭代),**不需要、也不应该**再自己 @ 开发执行器;`--reason` 写明退回原因(会进修复任务 prompt)。
49
+ - `morula comment add`:见 `.agents/skills/morula-platform/references/delivery.md` 评论纪律。
50
+ - `morula task assign <taskId> --to <principalId>`:指派本任务负责人(本空间成员或阶段执行器;目标不存在会显式报错)。
51
+ - **终态(已合并/已发布/已关闭)与需求池状态不由你声明**;同态重复推送是幂等的(无害)。
52
+
53
+ ## 分析任务:必须上报分析结论(verdict)
54
+
55
+ > **仅当本任务是「待分析」任务时适用**(任务停在「待分析」阶段、要求做需求分析与方案拆解、不写代码)。
56
+ > 其余任务(开发 / 评审 / 调研 / 问答)跳过本节,不要调用该命令。
57
+
58
+ - 分析结论分两部分,**都要给**(顺序:先发评论,再上报 verdict):
59
+ 1. **人看的**:用**你自己的话**把分析结论发成最终总结评论——需求是否清晰、怎么做、范围与风险、验收点:
60
+ ```bash
61
+ morula comment add --object <objectId> --final --content <你的分析结论>
62
+ ```
63
+ 这是用户看到的分析交付:用自己的话写,不要套固定格式,更不要复述任务描述;结论先说、理由跟上。
64
+ 2. **机器判定的**:执行 `morula task analysis-verdict <taskId> --verdict ready|blocked [--reason "…"]` 上报结论(`--reason` 只需一句话,详细内容在评论里)。
65
+ - `<taskId>` = `morula task get`(无参)返回的 `id`(本任务 AgentTask UUID)。
66
+ - **`ready`** = 需求清晰、可直接开发(`--reason` 可写一句话范围摘要);
67
+ **`blocked`** = 不可做 / 需澄清(**必须**在 `--reason` 或最终输出里写清阻塞点与需要澄清的问题)。
68
+ - **服务端据此自动推进,不需要任何人点确认**:`ready` → 任务自动进入「开发中」并派发开发任务;
69
+ `blocked` / 未上报 → 任务**停在「待分析」**,由用户补充需求后重派分析。
70
+ - **必须上报**:漏报会让任务静默停在「待分析」;同一任务只需上报一次(重复上报以首次为准,不会改写)。
71
+ - 分析任务的推进由服务端按 verdict 决定——**不要用状态动作替代分析结论**(不要调 `morula task state`)。
72
+
73
+ ## 评审任务:只读评审 + 必须回传结论(verdict)
74
+
75
+ > **仅当本任务是「Code Review 评审任务」时适用**(系统提示出现「本任务是 **Code Review 评审任务**」;要求对开发提交的改动做评审、不写代码)。
76
+ > 其余任务(开发 / 分析 / 调研 / 问答)跳过本节,不要调用该命令。
77
+
78
+ - 评审是**只读**的:物化仓库后查看 PR 分支相对目标分支的**实际改动**(`git diff`),**禁止修改代码、建分支、推分支、合并 MR**。
79
+ - 评审维度:正确性 / 安全性 / 代码风格 / 测试覆盖 / 是否符合原始需求;**必须读取真实 diff 后再下结论**,禁止凭空评审、编造结论。
80
+ - **评审所需信息全部用工具获取**(系统提示不注入):
81
+ - 评审对象:`morula task get`(无参)返回的 `objectId`(关联业务任务);
82
+ - 业务任务目标(标题/描述):`morula task get <objectId>`;关键评论:`morula comment list --object <objectId>`;
83
+ - PR 编号/链接:**GitLab** 用 `morula repo mr list <taskId> --state opened`(见 `.agents/skills/morula-platform/references/git-workflow.md` GitLab 平台说明段);**GitHub** 用 `gh pr list --head <branch>`;两者都可用业务对象详情里的 PR 关联兜底。
84
+ - **先答「目标达成度」**:对照业务任务目标逐条给出「达成 / 部分达成 / 未达成」;**未达成目标不得判 approved**;若开发改动与业务目标不匹配(做的是另一件事),verdict 必须为 `changes_requested`,不得以「描述残留、不影响验收」为由判通过。
85
+ - **必须回传结论**(机器协议),执行:
86
+ ```bash
87
+ morula review submit <objectId> --verdict approved|changes_requested|commented [--details <文本>] [--pr-number <PR编号>]
88
+ ```
89
+ - `<objectId>` = `morula task get`(无参)返回的 `objectId`;
90
+ - `--verdict`:`approved`(通过)/ `changes_requested`(不通过,**必须**在 `--details` 写明具体意见:文件/行/问题/建议,否则开发无法修复)/ `commented`(有意见但不阻塞);
91
+ - `--pr-number`:评审对象的 PR 编号(有则填)。
92
+ - **评审任务的交付就是这份结论**:平台会按结论写权威评论(✅/💬/🔁)——**不要**再发最终总结评论(`--final` 会被服务端拒绝),也不要在评论区复述结论。
93
+ - **结论新鲜度(无新提交不重复投 `approved`)**:提交结论前先核对被评审 MR 的 head commit 与上一轮结论时是否相同(`morula repo mr list` / `mr-detail`;评论区也有上一轮结论)。**相同且无新提交时不要重复投 `approved`**:本轮任务上下文里有人的新要求(如要求修复上一轮意见)→ 按人的要求处理(意见未修复就投 `changes_requested`);确实无可评审内容 → 投 `commented` 说明「无新提交」即可。复述上一轮结论对任务没有任何推进。
94
+ - **禁止评审自己开发的任务**:若待评审改动由你自己提交(同一智能体既开发又评审),不下结论,直接报告该配置问题。
95
+ - **必须上报**:漏报会让任务停在「待评审」,开发无法进入下一轮。
96
+ - 退回开发**首选结论协议**:`--verdict changes_requested`(带具体意见)与服务端结论链路完全等价;`morula task state --state in_progress` 是等价的替代入口(见「状态与任务操作」节),不是绕过。
97
+
98
+ ## 在 MR/PR 上留评审意见(巡检/审查类任务,非评审任务时)
99
+
100
+ > **仅当本任务是巡检/审查类(如自动化定时 PR Review),且确实发现值得提出的问题时适用**;开发/分析/问答任务跳过本节。
101
+
102
+ - **正确姿势**:用 `morula repo mr comment`(服务端机器协议,只写评论:不 approve、不 merge、不 close),**一条 MR 最多一条评论**:
103
+ ```bash
104
+ morula repo mr get <taskId> --mr <iid> --notes # 写之前先读已有讨论(平台不做去重,重复由你避免)
105
+ morula repo mr comment <taskId> --mr <iid> --content-file <path>
106
+ ```
107
+ - 内容为**结论 + 关键问题**(文件:行 + 问题 + 建议),不要贴大段日志或复述 diff;长内容写成报告(`morula report create`,见 `.agents/skills/morula-platform/references/delivery.md`)后用摘要引用;
108
+ - 末尾带署名行 `> 由自动化「<自动化名称>」于 <日期> 生成`——供人与 agent 下一轮识别这是本自动化的历史评论;
109
+ - 若本自动化已就同一问题留过评论、结论与这次一致 → **不要重复评论**;
110
+ - ⛔ **不要用 `morula review submit`**(那是评审任务的机器协议,会驱动业务任务状态回退)。
@@ -0,0 +1,103 @@
1
+ # morula-platform — 契约到实现溯源(source map)
2
+ 每条契约都对应以下实现位置。合并/重构后行号可能漂移,先核对再依赖精确行号。
3
+ 契约分布:不变量与命令索引在 AGENTS.md「Morula 平台协作契约」核心段(buildContractCoreSection);
4
+ 操作手册在 morula-platform references/{workspace, git-workflow, task-protocols, delivery, observability}.md。
5
+
6
+ ## 1. PR 链接 vs 关单双通道(git-workflow.md)
7
+
8
+ | 契约 | 服务端实现 | 位置 |
9
+ |------|-----------|------|
10
+ | PR 关联**只由平台通道产生**(服务端不读 PR 文本) | 平台通道建链(`reportPrLinkByAgent`)+ webhook 按 `(租户, 仓库, PR 号)` 定位**已存在**的链接 → 只更新状态 | `src/modules/vcs-integration/link/vcs-link.service.ts`(`findLinkedRows` / `handlePullRequest`) |
11
+ | 未关联的 PR(人工手工建)→ 不建链、不流转、留痕 | 同上(定位不到即返回,写「未关联任何任务」日志) | 同上 |
12
+ | merge 关单:**链接存在即授权**(无需 `Closes` 关键字) | merged/closed → 多仓库汇总 → `closeObject` | `vcs-link.service.ts`(`closeObject`) |
13
+ | 终态不可被降级(`released` 不被 `closed`/`merged` 覆盖;`merged → released` 放行) | `isTerminalDowngrade`(领域层唯一定义)+ `ObjectService.update` 不变量 | `domain/lifecycle-state.ts`、`object.service.ts` |
14
+
15
+ ## 2. 与平台交互只能走 morula CLI(AGENTS.md 核心段不变量 + workspace.md)
16
+
17
+ | 契约 | 实现 | 位置 |
18
+ |------|------|------|
19
+ | CLI 读评论 | `morula comment list --object <objectId>` | `packages/morula-cli/src/commands/comment.ts` |
20
+ | CLI 写评论(**由 agent 自己发**,含 `--final` 最终总结与 `--mention-agent` @ 运行时;见 delivery.md) | `morula comment add` → `POST /comments`(agent_task 凭证;`kind='final'` 按 `(taskId, kind)` 唯一防重) | `packages/morula-cli/src/commands/comment.ts`、`src/modules/task-management/comment/comment.service.ts` |
21
+ | CLI 任务详情(**无参**取本任务;带参取业务对象) | `morula task get` → `GET /agent-tasks/:id`;`morula task get <objectId>` → `GET /objects/:id` | `packages/morula-cli/src/commands/task.ts` |
22
+ | daemon 注入凭据(agent 无需自行登录) | runner 注入 `env` 给 Provider 子进程 | `packages/runtime/src/daemon/runner.ts` |
23
+ | 调 CLI 用 `$MORULA_CLI`(绝对路径,与当前 daemon 同源;PATH 上的裸 `morula` 可能是宿主自带的旧版) | `resolveAgentCliPath`(优先本包 `dist/morula.js`,产物缺失回退插件启动器);注入点:任务链路 `env`、会话链路 `env` | `packages/runtime/src/daemon/plugin-register.ts`、`runner.ts`、`session-host.ts` |
24
+ | 系统提示注入(身份与边界 = 阶段职责 / 目标 / 钥匙 taskId+spaceId / 工具入口指引);任务详情与仓库清单由 `morula task get`(无参)、`morula repo list --space` 获取 | `buildTaskPromptWithContract`(`runner.ts`,唯一进 dim 的 messages[0]);CLI `packages/morula-cli/src/commands/task.ts`(resolveTaskId → `GET /agent-tasks/:id`) | `packages/runtime/src/daemon/runner.ts` |
25
+ | 运行中检查点(本回合内取用户意见) | CLI `morula task inbox [--peek]` → `GET /agent-tasks/:id/thread/inbox`(机器协议;默认取走即消费,落 `consumed` + 当回合号);契约时机见 task-protocols.md「运行中反馈」 | `packages/morula-cli/src/commands/task.ts`、`src/modules/agent-task/chat/object-agent-chat.controller.ts`、`object-agent-message.service.ts`(`getThreadInbox`) |
26
+ | 运行中打断(同一会话重开一轮) | daemon 在安全点(`inFlightTools === 0`)`session/cancel` → `session/resume` → 用新意见重开 prompt;回合号与中断点上报为 `turn_started` / `turn_interrupted` 事件 | `packages/runtime/src/daemon/acp/acp-executor.ts`(回合循环)、`runner.ts`(`buildSteerPort`)、`src/modules/agent-task/chat/object-agent-message.service.ts`(`steerDeliveryStrategy`) |
27
+
28
+ ## 3.1 排查线上行为/故障:直接用受管引擎查线上事实(gcx)(observability.md)
29
+
30
+ | 契约 | 实现 | 位置 |
31
+ |------|------|------|
32
+ | 平台没有查询命令面:查询由 agent 直接用引擎(`gcx`)发起,命令与语法是引擎的运行期资产(`gcx --help` / `gcx commands`) | CLI 只剩 `morula obs env`(打印运行环境,无查询语义);受管引擎目录前置到任务 PATH | `packages/morula-cli/src/commands/obs.ts`、`packages/runtime/src/daemon/engine-provision.ts` |
33
+ | 真实凭据永不出平台;本机只有 30 分钟、绑空间、只读的网关令牌(绑 sourceId,换源必须换令牌) | `ObsTokenService`(`tokenType=obs_gateway`,claims 含 sourceId)+ 网关校验「URL sourceId == claim sourceId 且属于令牌空间」 | `src/modules/observability-query/obs-token.service.ts`、`observability-gateway.service.ts` |
34
+ | 只读强制:网关按上游路径白名单放行(GET / 确认为查询的 POST),写方法与未命中路径一律 403 且留审计 | `adapter.readonlyPaths()` 按域实测的 `'<METHOD> <上游路径>'` 条目放行;未命中 403 + 记日志 | `src/modules/observability-query/adapters/grafana.adapter.ts`、`observability-gateway.service.ts` |
35
+ | 运行环境由运行时注入:任务 env 注入 `GCX_CONFIG`(工作区受控骨架,隔离用户自己的 gcx context)+ `GRAFANA_SERVER` / `GRAFANA_TOKEN` / `GRAFANA_ORG_ID`(按默认源签发),并把受管引擎目录前置到任务 PATH | `ensureManagedEngine` / `managedEngineEnv` / `managedEngineDir`(不碰用户自己装的同名二进制);凭据只进 env、不进 argv | `packages/runtime/src/daemon/runner.ts`、`engine-provision.ts` |
36
+ | 审计按上游事实:每次转发一条(method / upstreamPath / 字节 / 耗时 / 结果码 / 引擎版本),不再有平台侧「能力」概念 | 网关转发时写 `observability_query_audits` | `src/modules/observability-query/observability-gateway.service.ts` |
37
+ | 不再有参数模板 / 统一裁剪与落盘:查询语法、结果形态与 spill 由引擎自理 | ——(引擎自带 `--help` / `commands` / skill) | 引擎侧 |
38
+
39
+ ## 3. 改代码默认产 PR(分支纪律,Agent 取名)(git-workflow.md)
40
+
41
+ | 契约 | 实现 | 位置 |
42
+ |------|------|------|
43
+ | 分支名由 Agent 取名并上报(格式 `<type>/<slug>`,见 git-workflow.md「分支命名」) | workContext 初始占位符 `morula/tmp-<random6>`;`morula task branch <id> --name <name> [--repo <owner/name>]` 更新(多仓库任务的次仓库带 `--repo`) | `buildPlaceholderBranchName`(`collaboration-logic.ts`)、`POST /agent-tasks/:id/branch`(`agent-task.controller.ts`)、`commands/task.ts`。**服务端不生成分支名**(曾有的 `buildBranchName` 编码旧规范,已删除) |
44
+ | 独立 worktree 创建(detached,不建占位分支) | `prepareWorktree`(`git worktree add --detach`) | `packages/runtime/src/daemon/worktree-manager.ts` |
45
+ | 复用检测(允许 agent 改名,禁主干) | marker 身份校验不含 branchName;detached 残留自动保全重建(未提交改动 → stash `morula-rescue <tag>`、未推送提交 → `refs/morula-rescue/<tag>`),保全失败/主干 → `WORKTREE_BRANCH_DRIFT` | `worktree-manager.ts`、`workspace-marker.ts` |
46
+ | 任务编号补齐兜底 | `ensurePullRequestTaskCode` | `packages/runtime/src/daemon/runner.ts` |
47
+ | delivery 以本地实际分支为准 | `reportPrDelivery` 读 `git branch --show-current`,跳过占位/主干 | `packages/runtime/src/daemon/runner.ts` |
48
+ | 交付上报遍历本任务全部仓库 | 主仓库目录(工作区根下的仓库子目录)+ 其余同级仓库子目录(prepare 产物,磁盘事实;按 repoFullName 归属排除主仓库),逐仓上报 branch/pushState、逐仓独立成败;次仓库 `workContextId` 省略时服务端按 `(lastAgentTaskId, repoFullName)` 反查 | `reportPrDelivery`/`reportRepoTargets`(`runner.ts`)、`collectMaterializedRepoDeliveryTargets`(`repo-checkout-service.ts`) |
49
+
50
+ ## 4. 状态与任务操作(结论优先、动作为辅;proposal stage-runtime-as-task-actor)(task-protocols.md)
51
+
52
+ | 契约 | 实现 | 位置 |
53
+ |------|------|------|
54
+ | merge 自动关单(事实事件驱动状态) | webhook merged → 按平台事实定位已关联链接 → 汇总 → Object 完成 | `src/modules/vcs-integration/webhook/vcs-event.service.ts`、`link/vcs-link.service.ts` |
55
+ | 运行时可声明状态集合 = `in_progress` / `review`(D8 落地口径;终态与 backlog/todo 不可声明,D5) | `resolveRuntimeStateTransition`(唯一定义:控制器端点与 change_object_status 工具共用);正向走事件级规则 + ObjectService.update | `src/modules/agent-task/domain/runtime-state-actions.ts`、`agent-task.controller.ts`(`POST :id/state`) |
56
+ | **待评审 → 开发中 = 退回开发,单一效应入口**(记账 + 回退 + 派修复 + 双触发去重;不做裸状态写) | `ReviewLoopService.runtimeRevertToDev`(与 verdict 路径 `handleRejected` 共用 `dispatchDevRework`;事实去重 = 对象已有未完成 dev 任务则只记账不派单) | `src/modules/agent-task/review-loop.service.ts` |
57
+ | 任务活跃门禁(终态任务的 token 不得再推状态/指派) | `ACTIVE_TASK_STATUSES`(queued/dispatched/running/awaiting_approval) | `src/modules/agent-task/domain/runtime-state-actions.ts` |
58
+ | 指派负责人(目标 = 本空间成员或阶段执行器 principal;失败显式报错) | `POST /agent-tasks/:id/assignee`(ObjectService.update 落库,agent_task 字段白名单含 assigneePrincipalId) | `agent-task.controller.ts`、`object.service.ts` |
59
+
60
+ ## 4.1 评审任务结论回传(morula review submit)(task-protocols.md)
61
+
62
+ | 契约 | 实现 | 位置 |
63
+ |------|------|------|
64
+ | 评审结论机器协议(approved / changes_requested / commented,changes_requested 必须带 details) | `morula review submit <objectId> --verdict ... [--details] [--pr-number]` → `POST /agent-collaborations/review/submit`(服务端校验调用者 = 评审任务后落库并驱动回环) | `packages/morula-cli/src/commands/review.ts`、`src/modules/agent-task/review-loop.service.ts` |
65
+ | 评审对象(objectId)经 AgentTask 本体下发(`morula task get` 无参返回) | AgentTask 记录 `objectId` 字段(enqueue 时写入) | `src/modules/agent-task/review-loop.service.ts` |
66
+
67
+ ## 5. 评论交付纪律(最终总结由运行时自发,服务端防重兜底)(delivery.md)
68
+
69
+ | 契约 | 实现 | 位置 |
70
+ |------|------|------|
71
+ | 评论是用户可见的产出通道;**最终总结由 agent 自己发**(`morula comment add --final`,作者=智能体) | `POST /comments`(agent_task 凭证;`kind='final'` 服务端回填 `taskId`,`(tenantId, taskId, kind)` 唯一约束 → 同一任务一条) | `packages/morula-cli/src/commands/comment.ts`、`src/modules/task-management/comment/comment.service.ts`(FINAL-COMMENT-001) |
72
+ | **服务端缺失兜底**(DP-1):任务完成时若运行时在任务上**一条评论都没发**(既无 final 也无普通评论)才代发一条(占住唯一键;交付判据=总结性评论本身,`--final` 仅防重,2026-09-30 用户定案) | `task-lifecycle.service.ts` onTaskCompleted:`runtimeFinalExists` + `hasAgentRepliedToTrigger` 双检查 → 都没有才兜底 create 带 `taskId/kind`(并发由 P2002 捕获) | `src/modules/agent-task/task-lifecycle.service.ts` |
73
+ | 兜底路径截取「总结段」(`---FINAL---` 分隔符 → 总结标题 → 水平线 → 原文兜底) | `cleanFinalOutput`(仅兜底代发路径使用;运行时自发路径内容纪律靠契约) | `src/modules/agent-task/task-lifecycle.service.ts` |
74
+ | **评论 @触发任务 → agent 的 final 自动挂到触发评论下**(agent 无需评论 ID) | 结构性挂靠:`CommentService.create`(resolveCommentAuthor 返回 triggerCommentId → parentCommentId 默认值);生命周期兜底:hasAgentRepliedToTrigger / isMentionReply | LOCAL-AGENT-COMMENT-REPLY-001 |
75
+ | **@ 阶段运行时**(`--mention-agent <stageExecutorId>`)→ 触发该执行器在任务上干活 | mentions 数组 agent 类型项 → `comment.mentioned` 事件 → AgentCollaborationService 派发 | `comment.service.ts`、`agent-collaboration.service.ts` |
76
+ | 禁止本地绝对路径作为交付物 | delivery.md;`reportPrDelivery` 只回报仓库相对信息 | `packages/runtime/src/daemon/runner.ts` |
77
+ | 单条最终评论(不刷进度;评论只写结论与事实,D10) | delivery.md + 唯一约束 | morula-platform |
78
+
79
+ ## 6. 禁止事项(AGENTS.md 核心段不变量)+ 机器化执行认领
80
+
81
+ `allowed-tools` frontmatter 是**免审批放行(pre-approve)**,不是围栏(skill 未被调用时零约束力);
82
+ 真正的围栏是下列机器化执行(prompt 文本只是提示,不是执行依据):
83
+
84
+ | 禁止 | 契约依据 | 机器化执行 |
85
+ |------|------|------|
86
+ | 直连平台 REST API / curl / wget | 核心段不变量 1 | agent_task 凭据端点 scope(token 仅对 CLI 端点有效,非 CLI 调用被服务端拒绝) |
87
+ | 读取 `~/.morula-cli` / token / 环境变量密钥 | 核心段不变量 2 | daemon 凭据注入隔离;残余风险由沙箱化兜底(issues/local-backend-watch-instability.md) |
88
+ | 探索工作目录外文件系统 | 核心段不变量 3;workspace.md 安全边界 | worktree 防护部分覆盖;沙箱化后由沙箱文件系统策略兜底 |
89
+ | 推 main/master | git-workflow.md;worktree-manager 分支漂移防护 | `morula task branch` 拒绝主干 + `WORKTREE_BRANCH_DRIFT` 保全重建 |
90
+ | 在工作区根直接跑 git/gh(工作区根不是仓库) | workspace.md | 工作区根无 `.git`,命令自然失败 |
91
+ | 评审任务发 final(结论已由 review submit 上报) | task-protocols.md / delivery.md | 服务端按任务类型拒绝评审任务的 final 评论 |
92
+
93
+ ## 7. 任务工作区布局与 AGENTS.md(task-workspace-layout)
94
+
95
+ | 契约 | 实现 | 位置 |
96
+ |------|------|------|
97
+ | 工作区根 = `<workdir>/worktrees/<tenant>/<runtimeId8>/<dirName>`,仓库为其下的 `<safeDirName(repoFullName)>` 子目录 | `buildTaskRootPath` / `buildWorktreePath` / `prepareWorktree` | `packages/runtime/src/daemon/worktree-manager.ts` |
98
+ | cwd = 工作区根(ACP session cwd / `acpWorkDir` / `registerTask`) | `prepareTaskWorkspace` 返回 `taskRoot`,git 操作仍用 `repoDir` | `packages/runtime/src/daemon/runner.ts` |
99
+ | `.agents/`、`.agent_context/`、`AGENTS.md` 写在工作区根(不在仓库内,故不再写用户仓库 .gitignore);`AGENTS.md` = 空间项目说明(用户内容)+ 契约核心段(marker 包裹,幂等替换) | `writeCustomSkills` / `writeCollaborationSkill` / `writeTaskContextBrief` / `writeProjectAgentsMd`(含核心段合并);`.gitignore` 只注入 worktree marker | `packages/runtime/src/daemon/runner.ts`、`worktree-manager.ts` |
100
+ | 空间 AGENTS.md 自动生效(dim 从 cwd 向上查找为 `project.instructions`);契约核心段随之恒定在场 | 服务端下发 `projectAgentsMd` → daemon 写工作区根 `AGENTS.md`(用户内容 + 核心段) | `runner.ts` `writeProjectAgentsMd`、`api.ts` `TaskDetail.projectAgentsMd` |
101
+ | skills/契约按 provider 投影注入(dim → `.agents/skills`;claude → `.claude/skills` + `CLAUDE.md` 双记忆;codex → `$CODEX_HOME/prompts`;自定义 ACP → `.morula/prompts`) | `resolveInstructionProjection` / `contractPathsFor`(providers/acp/instruction-projection.ts),writeCollaborationSkill / writeCustomSkills / writeProjectAgentsMd 消费 | `packages/runtime/src/daemon/runner.ts`、`packages/runtime/src/daemon/providers/acp/instruction-projection.ts` |
102
+ | 次仓库/只读检出物化到工作区根下同级子目录(`<repo>` / `<repo>-readonly`) | `resolveRepoTargetDir` / `materializeAdditionalRepo` / `materializeReadWorktree` | `packages/runtime/src/daemon/repo-checkout-service.ts` |
103
+ | cleanup 删整个工作区(含注入物与全部仓库目录),有未推送改动则拒绝;旧布局仍可安全清理 | `validateRemovable` / `findAdditionalRepoActivity` / `removeTaskWorkspace` | `packages/runtime/src/daemon/worktree-manager.ts` |
@@ -0,0 +1,79 @@
1
+ # 工作区与现场(workspace)
2
+
3
+ > CLI 入口约定(`$MORULA_CLI`、子目录执行、`--help` 优先)与不变量见工作区根 `AGENTS.md`
4
+ > 「Morula 平台协作契约」段;分支 / PR / MR 操作见 `.agents/skills/morula-platform/references/git-workflow.md`。
5
+
6
+ ## 任务详情与上下文获取
7
+
8
+ 任务系统提示(发给你的首条消息)只承载:**你的身份与边界**(阶段职责)、**你的目标**(「你的目标」段)、
9
+ **钥匙**(「基本信息」段的任务 ID / 空间 ID——只是命令入参,不是任务信息)、**工作区与工具入口**。
10
+ **其余上下文与任务详情一律不进提示词**,用 CLI 获取:
11
+
12
+ - **当前任务详情**:`morula task get`(无参)——taskId 由执行环境提供(`MORULA_TASK_ID` env / `.morula/checkout.json`),无需也不应从别处猜。返回:`id`(本任务 AgentTask ID,UUID)、`code`(任务编号,如 `SPW299-59`)、`objectId`(关联业务任务对象)、`taskPrompt`(本次目标原文)、`contextSnapshot`、`status`。
13
+ - **业务任务详情**(标题/描述):`morula task get <objectId>`;**关键评论**(用户原始诉求/分析结论):`morula comment list --object <objectId>`。
14
+ - **空间仓库清单**(多仓库任务判断依据):`morula repo list --space <spaceId>`——提示词不列仓库,需要时自己查。
15
+ - **「你的目标」**:系统提示「你的目标」段 = 本次任务的原始诉求,据此判断要做什么。
16
+
17
+ > **任务上下文文件**:同一套上下文也写在工作目录 `.agent_context/task-context.md`(与首条系统提示同源)。
18
+ > 需要再次确认任务边界时**读取该文件**(`cat .agent_context/task-context.md`),不要凭记忆推断。
19
+
20
+ ## 开工前先确认工作现场
21
+
22
+ - **先确认自己站在哪个目录**:工作目录是**任务工作区根**,仓库在其下的子目录(见下文布局)。`git/gh` 命令必须在**仓库目录内**执行。
23
+ - **改代码前先看现场**(防止在错误的分支/目录上动手)——进入对应仓库目录后:
24
+ ```bash
25
+ cd <工作区根>/<仓库目录> # 主仓库目录 = 仓库全名把 / 换成 -(如 human-resources-xxx)
26
+ git status # 是否有未提交改动(复用前一轮成果时正常,但要知道有什么)
27
+ git branch --show-current # 当前分支;detached HEAD 表示本轮尚未取名
28
+ ```
29
+ - 若 `git status` 显示工作目录有**不属于本任务**的改动(如误入其他任务 worktree),**立即停止并报告**,不要继续编辑。
30
+ - **不要在工作区根直接跑 git/gh**:工作区根不是 git 仓库(除仓库子目录外还有 `AGENTS.md`/`.agents/`/`.agent_context/`/`.morula/`),在根目录跑 git 只会报 `not a git repository`。`morula` CLI 反之可从工作区根**或其任意子目录**执行。
31
+
32
+ ## 工作区准备(全新检出,先补环境前置再跑构建/验收命令)
33
+
34
+ - 本工作区是全新检出,`node_modules` 不存在:先按仓库声明的包管理器安装依赖——有 `pnpm-lock.yaml` 用 `pnpm install`、`package-lock.json` 用 `npm ci`、`yarn.lock` 用 `yarn`;
35
+ - 仓库使用 Prisma 时(存在 `prisma/schema.prisma`)先 `npx prisma generate`,否则 `tsc` 会报大量与本次改动无关的错误;
36
+ - 验收/构建命令失败时,先区分「环境前置(依赖、生成物缺失)」与「自身改动」:环境前置先补齐再复跑,不要把环境报错当成本次改动的问题去修。
37
+
38
+ ## 仓库与工作目录
39
+
40
+ - **工作目录 = 任务工作区根**;仓库是它下面的**子目录**(清单里没有的仓库不在本地):
41
+
42
+ ```
43
+ <工作区根>/ ← 你的 cwd(pwd 就在这里)
44
+ ├── AGENTS.md ← 空间项目说明 + 平台协作契约核心段(已自动加载)
45
+ ├── .agents/skills/ ← morula-platform(本 skill)+ 本任务自定义 skill
46
+ ├── .agent_context/task-context.md ← 任务上下文(见上)
47
+ ├── .morula/checkout.json ← daemon 凭据(CLI 内部使用,不要手动读)
48
+ ├── <owner>-<repo>/ ← 主仓库(已按平台解析结果物化;本地没有的仓库按需 checkout)
49
+ └── <owner>-<repo2>/ ← 次仓库 / 只读检出(按需物化,与主仓库同级)
50
+ ```
51
+
52
+ - **git / gh 命令一律在对应仓库目录内执行**(`cd <工作区根>/<仓库目录>`,或 `git -C <仓库目录> ...`):
53
+ 工作区根不是 git 仓库,在根目录跑 git 命令必然失败。`morula` CLI 可在工作区根或其任意子目录执行。
54
+ - **主仓库**:平台已解析出的仓库在**工作区根下就绪**(目录名 = 仓库全名把 `/` 换成 `-`,如 `human-resources/xxx` → `human-resources-xxx`);`ls` 工作区根即可看到,直接在该目录内建分支/提交/推分支/提 PR。**需要空间绑定了哪些仓库时自己查**:`morula repo list --space <spaceId>`(spaceId 见系统提示「基本信息」段)。
55
+ - **⚠️ `morula repo checkout` 的语义 = 「声明/切换本任务的主仓库」**(服务端 generation+1 + daemon 物化工作区):
56
+ 声明只作用于当前任务(当前阶段的执行者);**开发阶段任务不继承分析阶段的声明**——需要改代码时由你自己
57
+ 按任务描述/分析结论 checkout。因此只在**判定出主仓库之后**调用,**一次任务只声明一次**(判错要纠正时才再调一次)。
58
+ 不要用它「把空间里的仓库逐个逛一遍」——每调一次主仓库就跟着换一次(真机踩到:分析阶段为查证 checkout 了 3 个仓库,
59
+ 主仓库最终停在最后那个「只看了一眼」的仓库上)。
60
+ - **若任务需要了解仓库内容/代码/提交状态(读场景,含纯问答)**:
61
+ - **首选服务端只读**(不切主仓库、不建工作上下文):`morula repo files --space <spaceId> [--repo <owner/name>] [--path <p>]` 列目录、
62
+ `morula repo read --space <spaceId> --repo <owner/name> --path <p>` 读文件;
63
+ - 需要 git 历史 / 分支 / 全仓检索时:只对**候选主仓库**用 `morula repo checkout <taskId> <repoFullName>`
64
+ (本轮立即物化,路径通常是工作区根下的 `<仓库目录>-readonly`),然后在该路径内只读查证:
65
+ `git -C <路径> log --oneline -20`、`git -C <路径> branch -a`、`rg "关键词" <路径>` 等(**只读**,不建分支、不改代码、不提 PR);
66
+ 刷新远端最新:`git -C <路径> fetch origin --prune`(remote 已配置 SSH,免密)。
67
+ **若为查证物化过「非结论」仓库,结论产出前必须再 `repo checkout` 一次结论仓库**,把主仓库摆正。
68
+ - **本地没有 ≠ 仓库不存在**:仓库内容用 `morula repo read` / `repo files` 查(服务端读,不受本地物化状态影响);
69
+ **不要**因为在 `repos/`、`worktrees/` 或常见目录搜索不到就断言「本地没有该仓库」。
70
+ - **若任务需要改代码**:用 `morula repo checkout <taskId> <repoFullName>` 拉取/切换仓库(认证已由执行环境注入),
71
+ 拿到返回的仓库路径后**chdir 进该仓库目录**,再按 `.agents/skills/morula-platform/references/git-workflow.md` 建分支、提 PR。可选 `--ref <branch|sha>` 指定检出分支。
72
+ - **若任务纯问答、或空间无可用仓库**:直接回答用户问题,不构建分支/PR(见 git-workflow.md「决策树」)。
73
+ - **若任务涉及多个仓库(多仓库任务)**:涉及哪些仓库由**你**结合任务描述判断(任务描述里的「涉及仓库」是管家的初始判断;空间绑定了哪些仓库用 `morula repo list --space <spaceId>` 查;执行中发现还需改动其他仓库时,自行 prepare 拉取),**不需要向用户逐个确认**:
74
+ 1. 主仓库:在它的子目录内直接 git 操作(工作区根不是仓库);
75
+ 2. 其他仓库用 `morula repo prepare <taskId> <repoFullName>` 物化到任务工作区根下(**与主仓库同级的子目录**,本地 daemon 端点,本轮立即物化并返回路径;git 协议拉取,不走平台 API);
76
+ 3. 在哪个仓库改动,就在哪个仓库内建分支(命名规范见 git-workflow.md)、推分支并**经平台通道建 PR/MR**(`morula repo mr create` 优先;标题带任务编号仅为可读性)。**只有经平台通道建的 PR 才会关联到本任务**(服务端不读 PR 文本)。**分支名逐仓上报**:主仓库(其子目录)用 `morula task branch <taskId> --name <分支名>`;次仓库(同级子目录)用 `morula task branch <taskId> --name <分支名> --repo <owner/name>` —— 服务端据此把分支名写到该仓库的工作上下文(平台侧逐仓建 MR 兜底、交付清单都依赖它;不报则一直停在占位分支名 `morula/tmp-*`,平台找不到你的分支);
77
+ 4. prepare 目录二次调用会 fetch 更新但**不动工作区**——跨轮复用时先 `git status` 确认现场。
78
+ - **安全边界**:只在本任务的任务工作区根(及其仓库子目录)内操作;禁止探索/修改工作区根之外的路径(尤其 daemon 根目录下其他任务的 `repos/`、`worktrees/`、`scratch/`)。
79
+ - **本地验证服务端口隔离**(issues/local-backend-watch-instability.md):若任务需要启动本地服务验证(如 `npm run dev` / `nest start` 等),**必须使用非平台占用端口**——绑定 `127.0.0.1` 的高位随机端口(如 127.0.0.1:18080+),**禁止**使用 `8080`(平台后端)及 `15173`(平台前端)等平台占用端口,也不要依赖终端会话存活(后台进程方式启动,用 `nohup`/`disown` 或 `&!` 脱离);启动后自测可用即可,不需要(也不应)让平台侧访问。云端沙箱化后由沙箱网络策略兜底。