@arcships/morula-runtime 0.1.0-alpha.10 → 0.1.0-alpha.12

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/dist/morula.js CHANGED
@@ -704,8 +704,8 @@ function page(ok, message) {
704
704
  }
705
705
 
706
706
  // ../morula-cli-core/dist/build-env.js
707
- var BUILD_VERSION = "0.1.0-alpha.10";
708
- var BUILD_ID = "20260922054915.d5e2cc87";
707
+ var BUILD_VERSION = "0.1.0-alpha.12";
708
+ var BUILD_ID = "20260922142838.0c791f70";
709
709
  var BUILD_CONTEXTS = {
710
710
  "local": "http://localhost:8080/api",
711
711
  "test": "https://morula.basecastle.com/api",
@@ -880,24 +880,6 @@ var CiApi = class {
880
880
  testReport(runId) {
881
881
  return this.client.get(`/vcs/runs/${encodeURIComponent(requiredId2(runId, "run id"))}/test-report`);
882
882
  }
883
- /**
884
- * 重跑整条流水线的失败 job(Phase 3;开放面 = 人 + 管家)。
885
- *
886
- * 只允许 failure / cancelled 的运行,其余状态服务端回 `CI_RETRY_NOT_ALLOWED`(不是 4xx)。
887
- * **非幂等**:每次调用都会在平台上产生一次新的重跑,重复调用不会去重。
888
- */
889
- retryRun(runId) {
890
- return this.client.post(`/vcs/runs/${encodeURIComponent(requiredId2(runId, "run id"))}/retry`);
891
- }
892
- /**
893
- * 重跑单个 job(Phase 3;开放面 = 人 + 管家)。
894
- *
895
- * 服务端按 jobId 反查所属运行(`CI_JOB_NOT_FOUND` 覆盖「job 不存在」与「反查不到运行」两种情况);
896
- * 状态门禁与 `retryRun` 相同。非幂等。
897
- */
898
- retryJob(jobId) {
899
- return this.client.post(`/vcs/jobs/${encodeURIComponent(requiredId2(jobId, "job id"))}/retry`);
900
- }
901
883
  };
902
884
  function requiredId2(id, label) {
903
885
  const normalized = id.trim();
@@ -2227,9 +2209,7 @@ async function ciCommand(context) {
2227
2209
  return ciDeployments(context);
2228
2210
  if (action === "test-report")
2229
2211
  return ciTestReport(context);
2230
- if (action === "retry")
2231
- return ciRetry(context);
2232
- throw usage("usage: morula ci <status|log|deployments|test-report|retry>");
2212
+ throw usage("usage: morula ci <status|log|deployments|test-report>");
2233
2213
  }
2234
2214
  async function ciStatus(context) {
2235
2215
  const { positionals, flags } = context.parsed;
@@ -2309,44 +2289,6 @@ async function ciTestReport(context) {
2309
2289
  throw ciFailure(result);
2310
2290
  return result;
2311
2291
  }
2312
- async function ciRetry(context) {
2313
- const { positionals, flags } = context.parsed;
2314
- rejectUnknownFlags(flags, ["space", "run", "job"]);
2315
- const usageHint = "usage: morula ci retry --space <spaceId> [--run <runId>] [--job <jobId>]";
2316
- if (positionals.length)
2317
- throw usage(`\u91CD\u8DD1\u53EA\u5728\u7A7A\u95F4\u9762\u5F00\u653E\uFF1A\u8BF7\u7528 --space <spaceId>\uFF08\u4EFB\u52A1\u9762\u4E0D\u63D0\u4F9B retry\uFF09\u3002${usageHint}`);
2318
- const runId = flagString(flags, "run");
2319
- const jobId = flagString(flags, "job");
2320
- if (runId && jobId)
2321
- throw usage(`--run \u4E0E --job \u4E92\u65A5\uFF0C\u53EA\u80FD\u7ED9\u4E00\u4E2A\uFF08${usageHint}\uFF09`);
2322
- const spaceId = flagString(flags, "space");
2323
- if (!spaceId)
2324
- throw usage(usageHint);
2325
- if (jobId) {
2326
- const result2 = await context.client.ci.retryJob(jobId);
2327
- if (result2.ok === false)
2328
- throw ciFailure(result2, "\u64CD\u4F5C");
2329
- return result2;
2330
- }
2331
- let targetRunId = runId;
2332
- if (!targetRunId) {
2333
- const view = await context.client.ci.spaceView(spaceId, { failed: true });
2334
- if (view.ok === false)
2335
- throw ciFailure(view);
2336
- targetRunId = view.runs[0]?.id;
2337
- if (!targetRunId) {
2338
- throw new CliError(
2339
- "CI_RUN_NOT_FOUND",
2340
- EXIT.NOT_FOUND,
2341
- `\u7A7A\u95F4 ${spaceId} \u6CA1\u6709\u5931\u8D25\u7684\u6D41\u6C34\u7EBF\u8FD0\u884C\u53EF\u91CD\u8DD1\uFF08\u53EF\u5148\u7528 morula ci status --space ${spaceId} --failed \u786E\u8BA4\uFF09`
2342
- );
2343
- }
2344
- }
2345
- const result = await context.client.ci.retryRun(targetRunId);
2346
- if (result.ok === false)
2347
- throw ciFailure(result, "\u64CD\u4F5C");
2348
- return result;
2349
- }
2350
2292
  function resolveFace(context, usageHint) {
2351
2293
  const taskId = context.parsed.positionals[0]?.trim();
2352
2294
  const spaceId = flagString(context.parsed.flags, "space");
@@ -2356,16 +2298,14 @@ function resolveFace(context, usageHint) {
2356
2298
  throw usage(usageHint);
2357
2299
  return taskId ? { kind: "task", taskId } : { kind: "space", spaceId };
2358
2300
  }
2359
- function ciFailure(failure, verb = "\u67E5\u8BE2") {
2301
+ function ciFailure(failure) {
2360
2302
  return new CliError(
2361
2303
  failure.code,
2362
2304
  exitForCiCode(failure.code),
2363
- `CI ${verb}\u5931\u8D25: ${failure.message || "\u672A\u77E5\u539F\u56E0"}\uFF08${failure.code}\uFF09`
2305
+ `CI \u67E5\u8BE2\u5931\u8D25: ${failure.message || "\u672A\u77E5\u539F\u56E0"}\uFF08${failure.code}\uFF09`
2364
2306
  );
2365
2307
  }
2366
2308
  function exitForCiCode(code) {
2367
- if (code === "CI_RETRY_NOT_ALLOWED" || code === "CI_JOB_NOT_MANUAL")
2368
- return EXIT.CONFLICT;
2369
2309
  if (code === "CI_JOB_NOT_FOUND" || code === "CI_RUN_NOT_FOUND" || code === "TASK_NOT_FOUND" || code === "OBJECT_NOT_FOUND")
2370
2310
  return EXIT.NOT_FOUND;
2371
2311
  return EXIT.OTHER;
@@ -3285,7 +3225,7 @@ var SPEC = {
3285
3225
  { name: "name", type: "string", valueHint: "<branch>", description: "\u5206\u652F\u540D\uFF08\u5FC5\u586B\uFF09", required: true },
3286
3226
  { name: "repo", type: "string", valueHint: "<owner/name>", description: "\u6B21\u4ED3\u5E93\uFF08\u591A\u4ED3\u5E93\u4EFB\u52A1\u7684\u5206\u652F\u9010\u4ED3\u4E0A\u62A5\uFF09" }
3287
3227
  ],
3288
- examples: ["morula task branch <taskId> --name <type>/<code>-<slug>"],
3228
+ examples: ["morula task branch <taskId> --name <type>/<slug>"],
3289
3229
  writes: "remote"
3290
3230
  },
3291
3231
  {
@@ -3847,7 +3787,7 @@ var SPEC = {
3847
3787
  },
3848
3788
  {
3849
3789
  resource: "ci",
3850
- summary: "CI/CD pipeline facts and pipeline operations: pipeline runs / job logs / deployments / failed test cases (read-only) plus retry of a failed pipeline or job (Phase 3 write, space face only). Read faces share one command surface \u2014 task face `<taskId>` (AgentTask credential, self-check your MR pipeline) vs space face `--space <spaceId>` (steward/session credential, space-wide inspection); the two are mutually exclusive. Retry is space-face ONLY (person + steward); trigger-deploy (play a manual job) stays person-only and is intentionally absent from the CLI",
3790
+ summary: "CI/CD pipeline facts (read-only): pipeline runs / job logs / deployments / failed test cases. Read faces share one command surface \u2014 task face `<taskId>` (AgentTask credential, self-check your MR pipeline) vs space face `--space <spaceId>` (steward/session credential, space-wide inspection); the two are mutually exclusive. Write operations (retry / play / trigger) were removed on 2026-09-22 (CI panel is read-only): operate pipelines directly in the VCS platform instead",
3851
3791
  actions: [
3852
3792
  {
3853
3793
  action: "status",
@@ -3903,26 +3843,12 @@ var SPEC = {
3903
3843
  writes: "none",
3904
3844
  idempotent: true,
3905
3845
  emits: ["ok", "runId", "report"]
3906
- },
3907
- {
3908
- action: "retry",
3909
- summary: "re-run a failed pipeline (Phase 3; space face ONLY \u2014 a positional <taskId> is a usage error, retry is not open to the task face; person + steward, and a steward must go through an elicitation confirm card). Omit both --run and --job to retry the newest FAILED run of the space (no failed run at all \u2192 CI_RUN_NOT_FOUND exit 3). Only failure/cancelled runs or jobs can be retried (CI_RETRY_NOT_ALLOWED exit 6). NOT idempotent: every call starts another platform re-run",
3910
- flags: [
3911
- { name: "space", type: "string", valueHint: "<id>", description: "\u7A7A\u95F4 ID\uFF08\u5FC5\u586B\uFF1Bretry \u53EA\u6709\u7A7A\u95F4\u9762\uFF0C\u4EFB\u52A1\u9762\u4E0D\u5F00\u653E\uFF09", required: true },
3912
- { name: "run", type: "string", valueHint: "<runId>", description: "\u8981\u91CD\u8DD1\u7684\u8FD0\u884C ID\uFF08\u4E0E --job \u4E92\u65A5\uFF1B\u7F3A\u7701 = \u8BE5\u7A7A\u95F4\u6700\u65B0\u4E00\u6761\u5931\u8D25\u8FD0\u884C\uFF09" },
3913
- { name: "job", type: "string", valueHint: "<jobId>", description: "\u8981\u91CD\u8DD1\u7684\u5355\u4E2A job ID\uFF08\u4E0E --run \u4E92\u65A5\uFF1B\u6765\u81EA ci status \u7684 jobs[].id\uFF09" }
3914
- ],
3915
- examples: ["morula ci retry --space <id>", "morula ci retry --space <id> --job <jobId>"],
3916
- writes: "remote",
3917
- idempotent: false,
3918
- emits: ["ok", "action", "runId", "jobId", "externalId", "ref", "acceptedAt"]
3919
3846
  }
3920
3847
  ],
3921
3848
  notes: [
3922
3849
  "\u4E24\u4E2A\u9762\uFF08\u4EFB\u52A1\u9762 <taskId> / \u7A7A\u95F4\u9762 --space <spaceId>\uFF09\u4E92\u65A5\uFF1A\u540C\u65F6\u7ED9 \u2192 usage error(2)\uFF0C\u90FD\u4E0D\u7ED9\u540C\u6837 usage error\u3002\u51ED\u8BC1\u4E0E\u4F5C\u7528\u57DF\u4E0D\u540C\uFF0C\u731C\u9519\u4F1A\u53D8\u6210\u9759\u9ED8\u8D8A\u6743\u6216\u9759\u9ED8\u5931\u8D25",
3923
- "\u53EA\u8BFB\u9762\uFF1Astatus / log / deployments / test-report \u53EA\u8BFB\uFF08writes: none\uFF09\uFF1Bretry \u662F Phase 3 \u7684\u552F\u4E00\u5199\u9762\uFF08writes: remote\uFF0C\u975E\u5E42\u7B49\uFF09\uFF0C\u4E14**\u53EA\u6709\u7A7A\u95F4\u9762**\u2014\u2014\u7ED9\u4F4D\u7F6E\u53C2\u6570 <taskId> \u2192 usage error(2)",
3924
- "\u89E6\u53D1\u624B\u52A8 job\uFF08play\uFF0C\u90E8\u7F72\uFF09\u4E0D\u8FDB CLI\uFF1A\u4EC5\u4EBA\u9762\uFF08D5/D6\uFF09\uFF0C\u5165\u53E3\u53EA\u5728 web \u786E\u8BA4\u5F39\u7A97",
3925
- "\u670D\u52A1\u7AEF\u4E1A\u52A1\u5931\u8D25\u662F HTTP 200 + `{ ok:false, code, message }`\uFF1ACI_JOB_NOT_FOUND / CI_RUN_NOT_FOUND / TASK_NOT_FOUND / OBJECT_NOT_FOUND \u2192 exit 3\uFF1BCI_RETRY_NOT_ALLOWED / CI_JOB_NOT_MANUAL \u2192 exit 6\uFF1BCAPABILITY_UNSUPPORTED / NO_CONNECTION / \u5176\u4F59 \u2192 exit 1"
3850
+ "CI \u547D\u4EE4\u9762\u7EAF\u53EA\u8BFB\uFF08\u5199\u64CD\u4F5C\u5DF2\u79FB\u9664\uFF0C2026-09-22 \u5B9A\u6848\uFF09\uFF1Astatus / log / deployments / test-report \u5168\u90E8 writes: none\uFF1B\u91CD\u8DD1 / \u89E6\u53D1\u6D41\u6C34\u7EBF\u8BF7\u5728 VCS \u5E73\u53F0\uFF08GitLab/GitHub\uFF09\u4E0A\u76F4\u63A5\u64CD\u4F5C",
3851
+ "\u670D\u52A1\u7AEF\u4E1A\u52A1\u5931\u8D25\u662F HTTP 200 + `{ ok:false, code, message }`\uFF1ACI_JOB_NOT_FOUND / CI_RUN_NOT_FOUND / TASK_NOT_FOUND / OBJECT_NOT_FOUND \u2192 exit 3\uFF1BCAPABILITY_UNSUPPORTED / NO_CONNECTION / \u5176\u4F59 \u2192 exit 1"
3926
3852
  ]
3927
3853
  },
3928
3854
  {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "morula-cli",
3
- "version": "0.1.0-alpha.10",
3
+ "version": "0.1.0-alpha.12",
4
4
  "description": "Use Morula CLI task management from DimCode.",
5
5
  "interface": {
6
6
  "displayName": "Morula CLI",
@@ -262,7 +262,7 @@ report the final branch name for an agent task (machine protocol; agent naming,
262
262
  **示例**
263
263
 
264
264
  ```bash
265
- morula task branch <taskId> --name <type>/<code>-<slug>
265
+ morula task branch <taskId> --name <type>/<slug>
266
266
  ```
267
267
 
268
268
  > `writes: remote` · `interactive: no` · `idempotent: no`
@@ -1401,12 +1401,11 @@ morula repo mr diff <taskId> --mr <iid>
1401
1401
 
1402
1402
  ## `morula ci`
1403
1403
 
1404
- CI/CD pipeline facts and pipeline operations: pipeline runs / job logs / deployments / failed test cases (read-only) plus retry of a failed pipeline or job (Phase 3 write, space face only). Read faces share one command surface — task face `<taskId>` (AgentTask credential, self-check your MR pipeline) vs space face `--space <spaceId>` (steward/session credential, space-wide inspection); the two are mutually exclusive. Retry is space-face ONLY (person + steward); trigger-deploy (play a manual job) stays person-only and is intentionally absent from the CLI
1404
+ CI/CD pipeline facts (read-only): pipeline runs / job logs / deployments / failed test cases. Read faces share one command surface — task face `<taskId>` (AgentTask credential, self-check your MR pipeline) vs space face `--space <spaceId>` (steward/session credential, space-wide inspection); the two are mutually exclusive. Write operations (retry / play / trigger) were removed on 2026-09-22 (CI panel is read-only): operate pipelines directly in the VCS platform instead
1405
1405
 
1406
1406
  > 两个面(任务面 <taskId> / 空间面 --space <spaceId>)互斥:同时给 → usage error(2),都不给同样 usage error。凭证与作用域不同,猜错会变成静默越权或静默失败
1407
- > 只读面:status / log / deployments / test-report 只读(writes: none);retry 是 Phase 3 的唯一写面(writes: remote,非幂等),且**只有空间面**——给位置参数 <taskId> → usage error(2)
1408
- > 触发手动 job(play,部署)不进 CLI:仅人面(D5/D6),入口只在 web 确认弹窗
1409
- > 服务端业务失败是 HTTP 200 + `{ ok:false, code, message }`:CI_JOB_NOT_FOUND / CI_RUN_NOT_FOUND / TASK_NOT_FOUND / OBJECT_NOT_FOUND → exit 3;CI_RETRY_NOT_ALLOWED / CI_JOB_NOT_MANUAL → exit 6;CAPABILITY_UNSUPPORTED / NO_CONNECTION / 其余 → exit 1
1407
+ > CI 命令面纯只读(写操作已移除,2026-09-22 定案):status / log / deployments / test-report 全部 writes: none;重跑 / 触发流水线请在 VCS 平台(GitLab/GitHub)上直接操作
1408
+ > 服务端业务失败是 HTTP 200 + `{ ok:false, code, message }`:CI_JOB_NOT_FOUND / CI_RUN_NOT_FOUND / TASK_NOT_FOUND / OBJECT_NOT_FOUND → exit 3;CAPABILITY_UNSUPPORTED / NO_CONNECTION / 其余 → exit 1
1410
1409
 
1411
1410
  ### `morula ci status`
1412
1411
 
@@ -1504,27 +1503,6 @@ morula ci test-report <taskId>
1504
1503
 
1505
1504
  > `writes: none` · `interactive: no` · `idempotent: yes` · `emits: ok, runId, report`
1506
1505
 
1507
- ### `morula ci retry`
1508
-
1509
- **用法**:`morula ci retry [--space <id>] [--run <runId>] [--job <jobId>]`
1510
-
1511
- re-run a failed pipeline (Phase 3; space face ONLY — a positional <taskId> is a usage error, retry is not open to the task face; person + steward, and a steward must go through an elicitation confirm card). Omit both --run and --job to retry the newest FAILED run of the space (no failed run at all → CI_RUN_NOT_FOUND exit 3). Only failure/cancelled runs or jobs can be retried (CI_RETRY_NOT_ALLOWED exit 6). NOT idempotent: every call starts another platform re-run
1512
-
1513
- | Flag | 类型 | 必填 | 取值 | 默认 | 说明 |
1514
- |---|---|---|---|---|---|
1515
- | `--space <id>` | string | 是 | - | - | 空间 ID(必填;retry 只有空间面,任务面不开放) |
1516
- | `--run <runId>` | string | - | - | - | 要重跑的运行 ID(与 --job 互斥;缺省 = 该空间最新一条失败运行) |
1517
- | `--job <jobId>` | string | - | - | - | 要重跑的单个 job ID(与 --run 互斥;来自 ci status 的 jobs[].id) |
1518
-
1519
- **示例**
1520
-
1521
- ```bash
1522
- morula ci retry --space <id>
1523
- morula ci retry --space <id> --job <jobId>
1524
- ```
1525
-
1526
- > `writes: remote` · `interactive: no` · `idempotent: no` · `emits: ok, action, runId, jobId, externalId, ref, acceptedAt`
1527
-
1528
1506
  <!-- hand:start ci -->
1529
1507
  <!-- hand:end ci -->
1530
1508
 
@@ -68,33 +68,32 @@ allowed-tools: Bash(morula *), Bash(git *), Bash(gh *)
68
68
  ## 0.3 分支命名:由你(Agent)取名并上报
69
69
 
70
70
  - **任务 ID 获取**:本任务的 AgentTask ID(UUID)在系统提示「基本信息」段(也是 `morula task get`(无参)返回的 `id`,`.agent_context/task-context.md` 开头亦有)。需要调用 `morula task branch` 时用它作为 taskId。
71
- - **重要区分**:`morula task branch <taskId>` 的 taskId 用**本任务 UUID**(机器协议);但 **MR / 分支 / PR 里的任务编号用对外编号 code**(如 `AGENT-958201`,用于服务端关联/关单)——**不要用 UUID 标记 MR**(UUID 关单只认业务对象,AgentTask 不会被识别,会导致 MR 关联失败)。
71
+ - **重要区分**:`morula task branch <taskId>` 的 taskId 用**本任务 UUID**(机器协议);但 **MR / PR 里的任务编号用对外编号 code**(如 `AGENT-958201`,用于服务端关联/关单)——**不要用 UUID 标记 MR**(UUID 关单只认业务对象,AgentTask 不会被识别,会导致 MR 关联失败)。
72
72
  - **只有需要改代码并推分支的任务才取名**;纯问答/只读调研/本地起服务不建分支(见第 3 条决策树)。
73
73
  - **先检查当前分支**:若仓库已有 feature 分支(同任务/同一改动闭环的后续轮次复用),**直接继续用当前分支,不要新建**(在仓库目录内执行):
74
74
  ```bash
75
75
  cd <工作区根>/<仓库目录> && git branch --show-current # 若非空且非 main/master → 用这个分支继续改
76
76
  ```
77
77
  - 若当前为 detached HEAD(首次执行),且任务确实要改代码:
78
- 1. 创建分支。分支名**严格由以下部分依次拼成,不多不少**:`<type>` + `/` + `<本任务对外编号>` + `-` + `<slug>`
78
+ 1. 创建分支。分支名**严格由以下部分依次拼成,不多不少**:`<type>` + `/` + `<slug>`
79
79
  - `<type>`:取下方「命名规范」清单里的一个(按任务性质选,如文档改动用 docs);
80
- - `<本任务对外编号>`:见 0.2,**原样照抄**该编号到分支名里(大小写与内容都不改动,也不省略);
81
80
  - `<slug>`:具体工作事情,小写、用 `-` 连接。
82
81
  ```bash
83
- git switch -c <type>/<本任务对外编号>-<slug>
82
+ git switch -c <type>/<slug>
84
83
  ```
85
- 例:任务编号为 SPW299-30、要做 meta build-info → 分支名 `feature/SPW299-30-meta-build-info`
86
- 分支名**到 `<slug>` 为止就结束** —— 编号与 slug 之后不再接任何内容。
84
+ 例:做 mention 相关的测试补全 → 分支名 `test/mention-tests`;修复登录 401 → `fix/login-401`
85
+ 分支名**到 `<slug>` 为止就结束** —— slug 之后不再接任何内容。
87
86
  2. **通过 CLI 把分支名上报服务端**(必须,服务端据此做 PR 关联/清理):
88
87
  ```bash
89
- morula task branch <taskId> --name <type>/<任务编号>-<slug>
88
+ morula task branch <taskId> --name <type>/<slug>
90
89
  ```
91
90
  - **`morula task branch` 需要 `MORULA_RUNTIME_ID`**(daemon 注入的 env,用于校验你的归属)。若你的 exec 环境没有这个 env,**从主仓库目录内的 `.morula-worktree.json` 读取 `runtimeId` 字段**(完整路径 `<工作区根>/<仓库目录>/.morula-worktree.json`;工作区根下没有这个文件),用 `env MORULA_RUNTIME_ID=<该值> morula task branch ...` 或导出后再调用(不要从别处猜)。
92
91
  - **命名规范**(分支名会出现在 PR、CI、历史里,必须规范):
93
92
  - 前缀 type 选一:`feature`(新功能)、`fix`(缺陷修复)、`hotfix`(紧急/线上)、`docs`(文档)、`refactor`(重构)、`chore`(杂务)、`test`(测试)、`perf`(性能)、`style`(样式)、`build`(构建/依赖)、`ci`(CI)、`revert`(回滚);
94
- - 任务编号 = 本任务的**对外编号**(见 0.2,如 `SPW299-30`),**原样大写**:服务端按 title/branch/body 扫描任务编号关联 MR,**匹配大小写敏感**(`[A-Z][A-Z0-9]{1,9}-数字`),写成小写会关联不到;
95
93
  - slug = 具体工作事情,小写、用 `-` 连接(可用英文;**不要用中文**,中文分支名不被多数 CI/工具链支持);
96
- - **只按本节规则拼,不要参考/模仿仓库里已有分支的命名**:历史分支是过往产物(可能含日期后缀、编号大小写不一、缺编号等),照着它们取名会沿用旧习惯;分支名完全由上面三段决定,与仓库现有分支无关;
97
- - **分支名到 slug 就结束**:编号与 slug 之后**不再追加任何内容**——日期、时间戳、轮次号、随机串都不要;日期不表达语义,且会让「同一件事的后续轮次复用同分支」看起来像要新建分支;
94
+ - **只按本节规则拼,不要参考/模仿仓库里已有分支的命名**:历史分支是过往产物(可能含日期后缀、任务编号等旧形态),照着它们取名会沿用旧习惯;分支名完全由上面两段决定,与仓库现有分支无关;
95
+ - **分支名到 slug 就结束**:slug 之后**不再追加任何内容**——日期、时间戳、轮次号、随机串都不要;日期不表达语义,且会让「同一件事的后续轮次复用同分支」看起来像要新建分支;
96
+ - **分支名是全仓库共享的命名空间,撞名会被拒绝**:若 `morula task branch` / `morula repo mr create` 返回 `BRANCH_OWNED_BY_OTHER_TASK`(分支名已被其他任务占用),换一个更具体的 slug 重新取名、上报后再继续;
98
97
  - **禁止**用 `main`/`master`,禁止以 `-` 开头/结尾,长度 ≤ 255。
99
98
  - 如果你不改代码,**不要**创建分支,也不要调用 `morula task branch`。
100
99
 
@@ -109,6 +108,10 @@ allowed-tools: Bash(morula *), Bash(git *), Bash(gh *)
109
108
  ```
110
109
  - 若 `git status` 显示工作目录有**不属于本任务**的改动(如误入其他任务 worktree),**立即停止并报告**,不要继续编辑。
111
110
  - **不要在工作区根直接跑 git/gh**:工作区根不是 git 仓库(除仓库子目录外还有 `AGENTS.md`/`.agents/`/`.agent_context/`/`.morula/`),在根目录跑 git 只会报 `not a git repository`。`morula` CLI 反之可从工作区根**或其任意子目录**执行(它从 cwd 向上查找 `.morula/checkout.json` 凭据)。
111
+ - **工作区准备(全新检出,先补环境前置再跑构建/验收命令)**:
112
+ - 本工作区是全新检出,`node_modules` 不存在:先按仓库声明的包管理器安装依赖——有 `pnpm-lock.yaml` 用 `pnpm install`、`package-lock.json` 用 `npm ci`、`yarn.lock` 用 `yarn`;
113
+ - 仓库使用 Prisma 时(存在 `prisma/schema.prisma`)先 `npx prisma generate`,否则 `tsc` 会报大量与本次改动无关的错误;
114
+ - 验收/构建命令失败时,先区分「环境前置(依赖、生成物缺失)」与「自身改动」:环境前置先补齐再复跑,不要把环境报错当成本次改动的问题去修。
112
115
 
113
116
  ## 0.5 仓库与工作目录
114
117
 
@@ -249,8 +252,8 @@ morula task inbox --peek # 只看不取(确认有没有新意见,不标
249
252
 
250
253
  ## 2. PR 链接与关单意图是两套不同的契约
251
254
 
252
- - **链接通道**:PR 的 title / branch / body 中出现任务编号 → 服务端自动关联 PR 到任务。
253
- 推荐写法:title 以「STR-101: 描述」开头,或 branch 用 `str-101-xxx`,或 body 写「Closes STR-101」。
255
+ - **链接通道**:PR 的 title / body 中出现任务编号 → 服务端自动关联 PR 到任务。
256
+ 推荐写法:title 以「STR-101: 描述」开头,或 body 写「Closes STR-101」(分支名不含任务编号,见 0.3;平台通道建的 MR 会自动把编号写进 title/body)。
254
257
  - **关单通道**:只有 `Closes` / `Fixes` / `Resolves` 后**紧邻**任务编号(如「Closes STR-101」)→ 该 PR
255
258
  merge 时服务端自动把任务流转到完成状态。title 前缀或 branch 引用只会关联 PR,不会在 merge 时关单。
256
259
  - body 中松散的提及(如「Related to STR-101」)会被标记为纯引用,不展示在任务的 PR 列表中。
@@ -5,7 +5,7 @@
5
5
 
6
6
  | 契约 | 服务端实现 | 位置 |
7
7
  |------|-----------|------|
8
- | 任务 key 匹配(`SPW299-30`) | `VcsLinkService.TASK_KEY_RE`(扫描 title/**branch**/body;正则 `[A-Z][A-Z0-9]{1,9}-数字`,**大小写敏感** → 分支名里的编号必须原样大写) | `src/modules/vcs-integration/link/vcs-link.service.ts:30,435` |
8
+ | 任务 key 匹配(`SPW299-30`) | `VcsLinkService.TASK_KEY_RE`(扫描 title/branch/body;正则 `[A-Z][A-Z0-9]{1,9}-数字`,大小写敏感 → **MR title/body 中的编号须原样大写**;分支名已不含编号(契约 0.3 定案),编号由平台通道自动写入 title/body) | `src/modules/vcs-integration/link/vcs-link.service.ts:30,435` |
9
9
  | Close intent 单独扫描(title/body,`Closes|Fixes|Resolves` 紧跟 key) | `CLOSE_INTENT_RE` | `vcs-link.service.ts:29` |
10
10
  | reference-only 隐藏(松散 body 提及不入 PR 列表) | `resolveTargets` 与 closeIntent 分支 | `vcs-link.service.ts:60-80, 184-186` |
11
11
  | merge 关单幂等 | merged → closeIntent 链接对应任务 | `vcs-link.service.ts:19-20`(文件头注释) |
@@ -27,7 +27,7 @@
27
27
 
28
28
  | 契约 | 实现 | 位置 |
29
29
  |------|------|------|
30
- | 分支名由 Agent 取名并上报(格式 `<type>/<任务编号>-<slug>`,见契约 0.3) | 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` 编码旧规范,已删除) |
30
+ | 分支名由 Agent 取名并上报(格式 `<type>/<slug>`,见契约 0.3) | 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` 编码旧规范,已删除) |
31
31
  | 独立 worktree 创建(detached,不建占位分支) | `prepareWorktree`(`git worktree add --detach`) | `packages/runtime/src/daemon/worktree-manager.ts` |
32
32
  | 复用检测(允许 agent 改名,禁主干) | marker 身份校验不含 branchName;detached 残留自动保全重建(未提交改动 → stash `morula-rescue <tag>`、未推送提交 → `refs/morula-rescue/<tag>`),保全失败/主干 → `WORKTREE_BRANCH_DRIFT` | `worktree-manager.ts`、`workspace-marker.ts` |
33
33
  | 任务编号补齐兜底 | `ensurePullRequestTaskCode` | `packages/runtime/src/daemon/runner.ts` |
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@arcships/morula-runtime",
3
3
  "type": "module",
4
- "version": "0.1.0-alpha.10",
4
+ "version": "0.1.0-alpha.12",
5
5
  "description": "Device-level CLI for the Morula local agent runtime (daemon/portal/models/auth) and the Morula business CLI (morula), distributed via npm",
6
6
  "bin": {
7
7
  "morula-runtime": "./bin/morula-runtime.js",