@siming-org/cli 0.8.4 → 0.8.6

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/index.js CHANGED
@@ -1089,7 +1089,18 @@ ${ctx.reposScanDetail}`
1089
1089
  const leakByRepo = [];
1090
1090
  const errRepos = [];
1091
1091
  for (const repo of hitRepos) {
1092
- const r = await ctx.runGit(["diff", "--name-only", `${sha}..${base}`], repo);
1092
+ const cnt = await ctx.runGit(["rev-list", "--count", `${base}..${sha}`], repo);
1093
+ if (!cnt.ok) {
1094
+ errRepos.push(repo);
1095
+ continue;
1096
+ }
1097
+ const n = Number.parseInt(cnt.stdout.trim(), 10);
1098
+ if (!Number.isSafeInteger(n) || n < 0) {
1099
+ errRepos.push(repo);
1100
+ continue;
1101
+ }
1102
+ if (n === 0) continue;
1103
+ const r = await ctx.runGit(["diff", "--name-only", `${base}...${sha}`], repo);
1093
1104
  if (!r.ok) {
1094
1105
  errRepos.push(repo);
1095
1106
  continue;
@@ -1098,7 +1109,7 @@ ${ctx.reposScanDetail}`
1098
1109
  if (leaked.length > 0) leakByRepo.push({ repo, leaked });
1099
1110
  }
1100
1111
  if (errRepos.length > 0) {
1101
- return fail3(type, `\u7248\u672C diff \u5931\u8D25\uFF08\u4ED3 ${errRepos.join("\u3001")}\uFF09`, `\u68C0\u67E5 verifiedCommit \u4E0E\u57FA\u7840\u5206\u652F\u53EF\u7528\u6027
1112
+ return fail3(type, `\u7248\u672C\u5224\u5B9A\u5931\u8D25\uFF08\u4ED3 ${errRepos.join("\u3001")}\uFF09`, `\u68C0\u67E5 verifiedCommit \u4E0E\u57FA\u7840\u5206\u652F\u53EF\u7528\u6027
1102
1113
  ${ctx.reposScanDetail}`);
1103
1114
  }
1104
1115
  if (leakByRepo.length > 0) {
@@ -1106,8 +1117,8 @@ ${ctx.reposScanDetail}`);
1106
1117
  const suffix = leakByRepo.length > 3 ? `\uFF08\u53E6\u6709 ${leakByRepo.length - 3} \u4ED3\u6CC4\u6F0F\u89C1\u9010\u4ED3\u91CD\u67E5\uFF09` : "";
1107
1118
  return fail3(
1108
1119
  type,
1109
- `verifiedCommit \u4E0E ${base} \u5B58\u5728\u975E\u6587\u6863\u5DEE\u5F02\u2014\u2014${lines.join("\uFF1B")}${suffix}`,
1110
- `\u4EE3\u7801\u6539\u52A8\u987B\u5408\u5E76\u8FDB\u57FA\u7840\u5206\u652F\uFF08\u542B\u5E76\u884C\u4EFB\u52A1 base \u524D\u8FDB\u573A\u666F\uFF1A\u91CD\u8D70\u5408\u5E76\u6216\u7ECF\u7528\u6237\u660E\u793A\u540E force \u63A8\u8FDB\u5E76\u7559\u75D5\uFF09
1120
+ `verifiedCommit \u672A\u5B8C\u5168\u8FDB\u5165\u57FA\u7840\u5206\u652F ${base}\u2014\u2014${lines.join("\uFF1B")}${suffix}`,
1121
+ `\u5C06\u542B\u9A8C\u8BC1\u7248\u672C\u7684\u4EFB\u52A1\u5206\u652F\u5408\u5E76\u8FDB\u57FA\u7840\u5206\u652F\u540E\u91CD\u8BD5\uFF08\u5E76\u884C\u4EFB\u52A1\u81F4\u57FA\u7840\u5206\u652F\u524D\u8FDB\u7684\u5206\u53C9\u573A\u666F\uFF1A\u91CD\u8D70\u5408\u5E76\uFF1B\u65E0\u6CD5\u53EF\u9760\u5408\u5E76\u65F6\u7ECF\u7528\u6237\u660E\u793A\u540E force \u63A8\u8FDB\u5E76\u7559\u75D5\uFF09
1111
1122
  ${ctx.reposScanDetail}`
1112
1123
  );
1113
1124
  }
@@ -1116,7 +1127,7 @@ ${ctx.reposScanDetail}`
1116
1127
  return {
1117
1128
  type,
1118
1129
  status: "pass",
1119
- detail: `verifiedCommit ${sha} \u4E0E ${base} \u4E00\u81F4\uFF08\u547D\u4E2D\u4ED3 ${hitRepos.join("\u3001")}\uFF1B\u6587\u6863\u8DEF\u5F84\u8C41\u514D ${ctx.docPaths.join(" ")}${naPart}\uFF09
1130
+ detail: `verifiedCommit ${sha} \u5DF2\u5305\u542B\u4E8E\u57FA\u7840\u5206\u652F ${base}\uFF08\u57FA\u7840\u5206\u652F\u524D\u8FDB\u4E0D\u5224\u6CC4\u6F0F\uFF1B\u547D\u4E2D\u4ED3 ${hitRepos.join("\u3001")}\uFF1B\u6587\u6863\u8DEF\u5F84\u8C41\u514D ${ctx.docPaths.join(" ")}${naPart}\uFF09
1120
1131
  ${ctx.reposScanDetail}`
1121
1132
  };
1122
1133
  }
@@ -1222,13 +1233,13 @@ function auditAiChecks(aiChecks, record) {
1222
1233
  results.push({ id: check.id, item: check.item, status: "pass", detail: "\u5B8C\u6210\u5224\u5B9A\u9879\u5DF2\u81EA\u68C0\u901A\u8FC7\uFF08refId \u5173\u8054\uFF09" });
1223
1234
  continue;
1224
1235
  }
1225
- const rejected = (record?.checks ?? []).some((c) => c.refId === check.id && c.passed === false);
1236
+ const rejected = (record?.checks ?? []).find((c) => c.refId === check.id && c.passed === false);
1226
1237
  if (rejected) {
1227
1238
  results.push({
1228
1239
  id: check.id,
1229
1240
  item: check.item,
1230
1241
  status: "fail",
1231
- detail: `\u7559\u75D5\u7ED3\u8BBA\u672A\u901A\u8FC7\uFF08check ${check.id} passed=false\uFF09\u3002\u4FEE\u590D\uFF1A\u91CD\u505A\u540E\u7FFB\u7EFF\uFF08record-check-patch --check ${check.id} --passed\uFF09\u6216\u5982\u5B9E\u8865\u5199\u4E0D\u9002\u7528`
1242
+ detail: `\u7559\u75D5\u7ED3\u8BBA\u672A\u901A\u8FC7\uFF08entry ${rejected.id} refId=${check.id} passed=false\uFF09\u3002\u4FEE\u590D\uFF1A\u91CD\u505A\u540E\u6309 entry \u7FFB\u7EFF\uFF08CLI record-check-patch --check ${rejected.id}\uFF1BMCP action=record-check-patch checkId=${rejected.id} passed=true\uFF09\uFF0C\u6216\u91CD\u505A\u540E record-check-add \u5E26 refId=${check.id} \u91CD\u8BB0`
1232
1243
  });
1233
1244
  continue;
1234
1245
  }
@@ -1242,12 +1253,20 @@ function auditAiChecks(aiChecks, record) {
1242
1253
  id: check.id,
1243
1254
  item: check.item,
1244
1255
  status: "fail",
1245
- detail: `item \u8FC7\u77ED\uFF08${check.item.length} < ${MIN_AI_CHECK_ITEM_LENGTH} \u5B57\u7B26\uFF0C\u6700\u5C0F\u5F62\u6001\u8981\u6C42\u53EF\u6838\u5BF9\u7684\u5177\u4F53\u4E8B\u5B9E\uFF09`
1256
+ // T202610130004 C3:过短分支同构补 item 原文与操作指引(同模糊语分支——无留痕时 patch 无目标,指引指向 add 带 refId)
1257
+ detail: `item\u300C${check.item}\u300D\u8FC7\u77ED\uFF08${check.item.length} < ${MIN_AI_CHECK_ITEM_LENGTH} \u5B57\u7B26\uFF0C\u6700\u5C0F\u5F62\u6001\u8981\u6C42\u53EF\u6838\u5BF9\u7684\u5177\u4F53\u4E8B\u5B9E\uFF09\u3002\u4FEE\u590D\uFF1Arecord-check-add \u5E26 refId=${check.id}\uFF08CLI --ref-id\uFF09+ \u5177\u4F53\u4E8B\u5B9E + passed=true`
1246
1258
  });
1247
1259
  continue;
1248
1260
  }
1249
1261
  if (VAGUE_AI_CHECK_BLACKLIST.some((w) => lowered.includes(w))) {
1250
- results.push({ id: check.id, item: check.item, status: "fail", detail: `item \u4E3A\u6A21\u7CCA\u5B8C\u6210\u8BED\uFF08\u547D\u4E2D\u9ED1\u540D\u5355\u300C${VAGUE_AI_CHECK_BLACKLIST.join("/")}\u300D\uFF09\uFF0C\u987B\u6539\u5199\u4E3A\u53EF\u6838\u5BF9\u7684\u5177\u4F53\u4E8B\u5B9E` });
1262
+ results.push({
1263
+ id: check.id,
1264
+ item: check.item,
1265
+ status: "fail",
1266
+ // T202610130004 C3(I202610120001):模糊语分支仅在无 refId 留痕时触发,record-check-patch 无可修补目标(按 entry id 寻址)——
1267
+ // 指引指向 add 带 refId 重记;补 item 原文让被打回方定位是哪条自检项被判模糊
1268
+ detail: `item\u300C${check.item}\u300D\u4E3A\u6A21\u7CCA\u5B8C\u6210\u8BED\uFF08\u547D\u4E2D\u9ED1\u540D\u5355\u300C${VAGUE_AI_CHECK_BLACKLIST.join("/")}\u300D\uFF09\u3002\u4FEE\u590D\uFF1A\u6539\u5199\u4E3A\u53EF\u6838\u5BF9\u7684\u5177\u4F53\u4E8B\u5B9E\u540E record-check-add \u5E26 refId=${check.id}\uFF08CLI --ref-id\uFF09+ passed=true \u91CD\u8BB0`
1269
+ });
1251
1270
  continue;
1252
1271
  }
1253
1272
  results.push({
@@ -1353,7 +1372,7 @@ function scanWorkspaceRepos(cwd, scanDepthOverride) {
1353
1372
  var execFileAsync = promisify(execFile);
1354
1373
  var defaultGitRunner = async (args, cwd) => {
1355
1374
  try {
1356
- const { stdout, stderr } = await execFileAsync("git", args, { cwd, timeout: 1e4 });
1375
+ const { stdout, stderr } = await execFileAsync("git", ["-c", "core.quotepath=false", ...args], { cwd, timeout: 1e4 });
1357
1376
  return { ok: true, stdout, stderr };
1358
1377
  } catch (err2) {
1359
1378
  const e = err2;
@@ -1844,7 +1863,9 @@ import { parse as parseYaml } from "yaml";
1844
1863
  import {
1845
1864
  BIZ_CODE_MESSAGES,
1846
1865
  bumpPatchOrPassthrough,
1847
- diffTemplateContent
1866
+ diffTemplateContent,
1867
+ findSameTrackForks,
1868
+ simulateTrackChains
1848
1869
  } from "@siming-org/core";
1849
1870
  import {
1850
1871
  DagTemplateCreateSchema,
@@ -1897,6 +1918,17 @@ ${issues}`, httpStatus: 0 });
1897
1918
  }
1898
1919
  const input = parsed.data;
1899
1920
  const finalName = input.name;
1921
+ const forkIssues = findSameTrackForks(input.nodes, input.edges);
1922
+ if (forkIssues.length > 0) {
1923
+ const detail = forkIssues.map((issue) => `\u8282\u70B9 ${issue.nodeId} \u6709 ${String(issue.count)} \u6761\u6307\u5411 ${issue.targetTrack} \u8F68\u8282\u70B9\u7684\u51FA\u8FB9`).join("\uFF1B");
1924
+ return fail({
1925
+ message: `${BIZ_CODE_MESSAGES.TEMPLATE_SAME_TRACK_FORK}\uFF08${detail}\uFF09`,
1926
+ httpStatus: 0,
1927
+ bizCode: "TEMPLATE_SAME_TRACK_FORK",
1928
+ hint: "\u540C\u8F68\u51FA\u8FB9\u4EC5\u5141\u8BB8\u4E00\u6761\uFF1B\u8DF3\u8FC7\u53EF\u9009\u8282\u70B9\u7531\u526A\u679D\u6865\u63A5\u673A\u5236\u81EA\u52A8\u8865\u8FB9\uFF0C\u52FF\u624B\u5DE5\u6DFB\u52A0\u65C1\u8DEF\u76F4\u8FB9\uFF084 \u6761\u7ED3\u6784\u7EA6\u675F\u901F\u67E5\u89C1 siming flow compose \u8F93\u51FA\uFF09"
1929
+ });
1930
+ }
1931
+ const trackChains = simulateTrackChains(input);
1900
1932
  const existingResult = await client.getJson(
1901
1933
  `/api/dag/templates?projectId=${encodeURIComponent(projectId)}&name=${encodeURIComponent(finalName)}&includeDisabled=true`
1902
1934
  );
@@ -1952,6 +1984,7 @@ ${issues}`, httpStatus: 0 });
1952
1984
  action,
1953
1985
  importVersion,
1954
1986
  resultVersion,
1987
+ trackChains,
1955
1988
  ...existing?.id !== void 0 ? { targetId: existing.id } : {},
1956
1989
  ...existing?.version !== void 0 ? { serverVersion: existing.version } : {},
1957
1990
  ...existing?.enabled === false ? { enabled: false } : {},
@@ -2417,7 +2450,7 @@ var taskArgs = {
2417
2450
  // create / query
2418
2451
  templateId: z3.string().optional(),
2419
2452
  taskTitle: z3.string().optional(),
2420
- track: z3.string().optional(),
2453
+ track: z3.union([z3.string(), z3.array(z3.string())]).optional(),
2421
2454
  type: hostNeutralEnum(z3.enum(TASK_TYPES)).optional(),
2422
2455
  skipNodes: z3.array(z3.string()).optional(),
2423
2456
  projectId: z3.string().optional(),
@@ -2666,7 +2699,7 @@ function createMcpServer() {
2666
2699
  const client = createClient(void 0, "mcp");
2667
2700
  server.tool(
2668
2701
  "siming_task",
2669
- "task \u8D44\u6E90\u57DF\u805A\u5408\u5DE5\u5177\uFF08\u4EFB\u52A1\u5168\u64CD\u4F5C\u7ECF\u672C\u5DE5\u5177 + action \u53C2\u6570\uFF09\u3002action \u5FC5\u586B\uFF1B\u8C03\u7528\u65B9\u5E94\u5728 fieldMask \u4E2D\u5217\u51FA\u672C\u6B21\u771F\u5B9E\u63D0\u4F9B\u7684\u53EF\u9009\u5B57\u6BB5\uFF0Cmask \u5916\u7531\u5BBF\u4E3B\u81EA\u52A8\u586B\u5145\u7684\u7A7A\u4E32\u3001\u7A7A\u6570\u7EC4\u3001false\u30010 \u5747\u5FFD\u7565\uFF0Cmask \u5185\u7A7A\u6570\u7EC4/false \u8868\u793A\u663E\u5F0F\u6E05\u7A7A\u6216\u5173\u95ED\uFF1B\u5404 action \u56FA\u5B9A\u5FC5\u586B\u5B57\u6BB5\u65E0\u9700\u5199\u5165 mask\u3002\u5176\u4F59\u53C2\u6570\u5168\u53EF\u9009\u3001\u6309 action \u8FD0\u884C\u65F6\u6821\u9A8C\u5FC5\u586B\uFF08\u7F3A\u5931\u8FD4\u56DE\u5931\u8D25\u4E09\u8981\u7D20\uFF1A\u5BF9\u8C61+\u6839\u56E0+\u4FEE\u590D\u6307\u5F15\uFF09\u3002projectId \u4E3A key|id \u53CC\u5F62\u6001\uFF0C\u901A\u9053\u5C42\u81EA\u52A8\u5F52\u4E00\u4E3A 24-hex id\uFF1B\u663E\u5F0F\u6307\u5B9A\u89E3\u6790\u5931\u8D25\u62A5\u9519\u4E0D\u515C\u5E95\uFF1B\u7F3A\u7701\u8BED\u4E49\u6309 action\uFF1Acreate \u843D\u9ED8\u8BA4\u9879\u76EE\u94FE\uFF08\u5DE5\u4F5C\u533A defaultProject \u5931\u6548\u62A5\u9519\uFF0C\u65E0\u914D\u7F6E\u4E0D\u4F20\u7531 server \u6309\u6A21\u677F\u5F52\u5C5E\u515C\u5E95\uFF09\uFF0Cquery \u4E0D\u8FC7\u6EE4\uFF08\u5168\u5C40\u67E5\u8BE2\uFF09\u3002\u5199\u64CD\u4F5C\uFF08create/doc-*/record-*/archnote-add/pause/resume/cancel\uFF09\u54CD\u5E94\u4E3A\u8F7B\u91CF\u56DE\u6267\uFF1A{taskId, updated(\u89E6\u53CA\u5B57\u6BB5\u8DEF\u5F84), entry(\u65B0\u6761\u76EE id+kind\uFF0C\u4F9B\u540E\u7EED patch \u5B9A\u4F4D), echo(\u5199\u5165\u5185\u5BB9\u56DE\u663E), updatedAt, task(\u4EFB\u52A1\u8FDB\u5EA6\u6458\u8981 progress: {completed,total})}\u2014\u2014\u4E0D\u8FD4\u56DE\u5B8C\u6574\u4EFB\u52A1\u5B9E\u4F53\u3002action \u6E05\u5355\uFF08\u62EC\u53F7\u5185\u4E3A\u8BE5 action \u5FC5\u586B\u53C2\u6570\uFF09\uFF1Acreate(templateId,taskTitle,track\uFF1B\u53EF\u9009 type=feature|bugfix|ui-tweak|research\u3001skipNodes\u3001projectId\uFF1BtemplateId \u652F\u6301 code|id \u53CC\u5F62\u6001\u2014\u2014code \u4E3A\u6A21\u677F\u4E1A\u52A1\u6807\u8BC6\uFF08\u9879\u76EE\u5185\u552F\u4E00\u3001kebab-case \u5FC5\u542B\u8FDE\u5B57\u7B26\uFF0C\u5982 full-workflow\uFF09\uFF0C\u63A8\u8350\u5F15\u7528\u5F62\u6001\uFF0C\u5BFB\u5740\u987B\u914D projectId \u6307\u5B9A\u9879\u76EE\u57DF\uFF1B24-hex \u6570\u636E\u5E93 id \u76F4\u67E5\u517C\u5BB9\uFF1Bcode \u5F62\u6001\u4E0D\u5B58\u5728\u65F6\u9519\u8BEF\u542B candidates \u76F8\u8FD1\u5019\u9009\u6E05\u5355\uFF08id/code/name \u22645 \u6761\uFF09\uFF1B\u54CD\u5E94 {task, firstNode}\u2014\u2014firstNode \u5373\u9996\u8282\u70B9\u5B8C\u6574\u8D44\u6599\u5305\uFF0C\u514D\u8C03 context)\uFF1Bquery(taskId \u8FD4\u56DE\u5355\u4EFB\u52A1\u8BE6\u60C5\uFF0C\u7F3A\u7701\u8FD4\u56DE\u5217\u8868\uFF0C\u53EF\u9009 status/track/projectId/page/limit)\uFF1Bcontext(taskId\uFF1B\u53EF\u9009 view=basic|full\u2014\u2014basic \u7F3A\u7701\u4E0D\u643A\u5E26 artifact \u5168\u6587\u5FEB\u7167\uFF0Cfull \u65AD\u70B9\u7EED\u8DD1\u9700\u5386\u53F2\u4EA7\u7269\u5168\u6587\u65F6\u7528\u3002\u26A0 \u514D\u91CD\u8BFB\uFF1Aadvance/approve \u6D41\u8F6C\u54CD\u5E94\u5DF2\u542B\u4E0B\u4E00\u8282\u70B9\u5B8C\u6574\u8D44\u6599\u5305\uFF0C\u540C\u4F1A\u8BDD\u5185\u6D41\u8F6C\u540E\u76F4\u63A5\u5F00\u5DE5\u3001\u65E0\u9700\u518D\u8C03 context\uFF1B\u4EC5\u65B0\u4F1A\u8BDD/\u65AD\u70B9\u7EED\u8DD1\u8C03\u7528)\uFF1Bnode(taskId,view=prompt|skills\uFF1BnodeId \u7F3A\u7701\u7528\u5F53\u524D\u8282\u70B9\uFF1B\u26A0 view \u503C\u968F action \u4E0D\u540C\uFF1Anode\u2192prompt|skills\uFF0Ccontext\u2192basic|full\uFF0C\u9519\u914D\u62A5\u9519)\uFF1Badvance(taskId\uFF1Bnote \u5199 history\u3001summary \u5199 nodeRecords\uFF0C\u4E24\u4F4D\u72EC\u7ACB\uFF1B\u54CD\u5E94\u5DF2\u542B\u4E0B\u4E00\u8282\u70B9\u8D44\u6599\u5305\uFF0C\u540C\u4F1A\u8BDD\u514D\u91CD\u8BFB context\u3002\u26A0 T202609230001 \u8282\u70B9\u95E8\u7981\uFF1A\u914D\u7F6E\u4E86 toolChecks/aiChecks \u7684\u8282\u70B9\u63A8\u8FDB\u524D\u81EA\u52A8\u6267\u884C\u68C0\u67E5\u2014\u2014fail \u4F1A\u88AB\u6253\u56DE\u5E76\u8FD4\u56DE\u9010\u9879\u4FEE\u590D\u6307\u5F15\uFF08\u7ED3\u679C\u5DF2\u5199 history checks_rejected\uFF09\uFF0C\u6309\u6307\u5F15\u4FEE\u590D\u6216\u83B7\u7528\u6237\u8C41\u514D\u7559\u75D5\u540E\u91CD\u63A8\uFF1B\u975E\u4EBA\u5DE5\u5BA1\u6279\u8282\u70B9\u7981\u6B62\u56E0\u95E8\u7981\u4E2D\u65AD\u4EFB\u52A1\uFF08\u6253\u56DE\u4FE1\u606F\u5373\u7EE7\u7EED\u4F9D\u636E\uFF09\u3002force+forceReason \u6210\u5BF9\u63D0\u4F9B\u65F6\u53EF\u8D8A\u8FC7 fail \u5F3A\u5236\u63A8\u8FDB\u2014\u2014\u4EC5\u51ED\u7528\u6237\u660E\u793A\u6307\u4EE4\uFF0CAI \u7981\u6B62\u81EA\u51B3\uFF0C\u7406\u7531\u539F\u6587\u843D history \u5BA1\u8BA1)\uFF1Bcheck(taskId\uFF1B\u95E8\u7981\u53EA\u8BFB\u9884\u68C0\u2014\u2014\u9010\u9879\u62A5\u544A\u4E0D\u5199\u4EFB\u4F55\u72B6\u6001\uFF0Cadvance \u524D\u81EA\u67E5\u7528)\uFF1Bapprove(taskId,decision=approved|rejected\uFF1B\u53EF\u9009 comment\uFF1B\u54CD\u5E94\u5DF2\u542B\u4E0B\u4E00\u8282\u70B9\u8D44\u6599\u5305\uFF0C\u540C\u4F1A\u8BDD\u514D\u91CD\u8BFB context)\uFF1Bpause(taskId\uFF1B\u53EF\u9009 reason)\uFF1Bresume(taskId\uFF1B\u53EF\u9009 resumeNote)\uFF1Bcancel(taskId\uFF1B\u53EF\u9009 reason 1-500 \u5B57\u7B26\uFF1B\u26A0 \u7EC8\u6001\u4E0D\u53EF\u9006\u2014\u2014active/paused \u53EF\u53D6\u6D88\uFF0Ccompleted/cancelled \u62D2\u7EDD\u5E76\u8FD4\u56DE TASK_TERMINATED\uFF1B\u53D6\u6D88\u540E\u7ECF\u672C\u5DE5\u5177\u7684\u6D41\u8F6C\u4E0E\u8BB0\u5F55\u5199\u64CD\u4F5C\u88AB\u62D2)\uFF1Bhistory(taskId)\uFF1Binstance(taskId\u2014\u2014\u67E5\u770B\u4EFB\u52A1 DAG \u5B9E\u4F8B\u5FEB\u7167\uFF1A\u521B\u5EFA\u4EFB\u52A1\u65F6\u51BB\u7ED3\u7684\u6A21\u677F\u5B9E\u4F8B\uFF0C\u6A21\u677F\u540E\u7EED\u53D8\u66F4\u4E0D\u56DE\u6EAF)\u3002\u8BB0\u5F55\u5199\u5165\uFF1Arecord-set(taskId,node\uFF1Bsummary \u4E0E\u516D\u4E2A\u7ED3\u6784\u5316\u5B57\u6BB5\uFF08baseBranch/verifiedCommit/fixesApplied/testReport/deferredIssues/evidenceFiles\uFF09\u81F3\u5C11\u5176\u4E00\u2014\u2014\u7ED3\u6784\u5316\u5B57\u6BB5\u6309\u8282\u70B9 prompt\u300C\u7ED3\u6784\u5316\u5B57\u6BB5\u5199\u5165\u8981\u6C42\u300D\u9010\u5B57\u6BB5\u843D\u5E93\uFF0CPATCH \u8BED\u4E49=\u4EC5\u66F4\u65B0\u63D0\u4F9B\u5B57\u6BB5)\uFF1Brecord-check-add(taskId,node,item\uFF1B\u53EF\u9009 passed \u7F3A\u7701 true\u3001refId=aiChecks \u81EA\u68C0\u7559\u75D5\u951A\uFF08\u5BA1\u8BA1\u8BA4 refId===aiCheck.id \u4E14 passed=true\uFF0C\u7F3A\u7559\u75D5\u7684\u5B8C\u6210\u5224\u5B9A\u5BA1\u8BA1 fail\uFF09\u3001source=self|tool \u672C\u7248\u5DE5\u5177\u7F3A\u7701\u4E0D\u5199\uFF1B\u6279\u91CF checkItems \u5143\u7D20\u540C\u6784\uFF1B\u56DE\u6267 entry.id \u4F9B record-check-patch \u5B9A\u4F4D)\uFF1Brecord-check-patch(taskId,node,checkId\uFF1B\u53EF\u9009 passed/item/refId/source\uFF0C\u4EC5\u66F4\u65B0\u63D0\u4F9B\u5B57\u6BB5)\uFF1Brecord-artifact-add(taskId,node,artifactType=prd|tech|code|test|doc|other\uFF1Bpath \u7EAF\u5F15\u7528 / file \u8BFB\u672C\u673A\u6587\u4EF6 / content \u76F4\u4F20\u5168\u6587\u2014\u2014file \u4E0E content\u3001file \u4E0E path \u4E92\u65A5\uFF0Ccontent \u53EF\u4E0E path \u6210\u5BF9\u6216\u5355\u72EC\uFF0C\u5355\u72EC\u65F6\u767B\u8BB0\u503C\u5408\u6210 mcp-inline/<type>\uFF1B\u53EF\u9009 note)\uFF1Brecord-confirm(taskId,node,quote\u2014\u2014\u6682\u505C\u70B9\u7528\u6237\u786E\u8BA4\u539F\u6587\u9010\u5B57)\uFF1Brecord-decision-add(taskId,node,topic,decisionText)\uFF1Brecord-review-set(taskId,node,verdict=pass|fail,rounds,critical)\u3002\u9700\u6C42\u6587\u6863\uFF1Adoc-set(taskId\uFF1Bwhat/why/trackNote \u81F3\u5C11\u4F20\u4E00)\uFF1Bdoc-acceptance-add(taskId,text)\uFF1Bdoc-non-goal-add(taskId,text)\u3002\u7D20\u6750\uFF1Aarchnote-add(taskId,text)\u3002\u6279\u91CF\u5F62\u6001\uFF08\u63A8\u8350\uFF0C\u516D\u7C7B\u540C\u6784\uFF09\uFF1Arecord-check-add \u4F20 checkItems=[{item,passed?}]\u3001record-artifact-add \u4F20 artifactEntries=[{artifactType,path?/file?/content?,note?}]\u3001record-decision-add \u4F20 decisionEntries=[{topic,decisionText}]\u3001doc-acceptance-add/doc-non-goal-add/archnote-add \u4F20 textItems=[string]\u2014\u2014\u6279\u91CF\u53C2\u6570\u4E0E\u5355\u6761\u53C2\u6570\u4E8C\u9009\u4E00\uFF0C\u4E00\u6B21\u8C03\u7528\u5199\u591A\u6761\uFF08\u4E0A\u9650 50 \u6761/\u6279\uFF0Cartifact \u5168\u6587\u5FEB\u7167\u603B\u91CF \u22642M \u5B57\u7B26/\u6279\uFF09\uFF1B\u90E8\u5206\u5931\u8D25\u4FDD\u7559\u6210\u529F\u6761\u76EE\u5E76\u9010\u6761\u62A5\u544A\uFF08failures[].index=\u539F\u59CB\u63D0\u4EA4\u5E8F\uFF0C\u53EA\u91CD\u8BD5\u5931\u8D25\u9879\uFF09\uFF0Capplied=0 \u6574\u4F53\u62A5\u5931\u8D25\u3002",
2702
+ 'task \u8D44\u6E90\u57DF\u805A\u5408\u5DE5\u5177\uFF08\u4EFB\u52A1\u5168\u64CD\u4F5C\u7ECF\u672C\u5DE5\u5177 + action \u53C2\u6570\uFF09\u3002action \u5FC5\u586B\uFF1B\u8C03\u7528\u65B9\u5E94\u5728 fieldMask \u4E2D\u5217\u51FA\u672C\u6B21\u771F\u5B9E\u63D0\u4F9B\u7684\u53EF\u9009\u5B57\u6BB5\uFF0Cmask \u5916\u7531\u5BBF\u4E3B\u81EA\u52A8\u586B\u5145\u7684\u7A7A\u4E32\u3001\u7A7A\u6570\u7EC4\u3001false\u30010 \u5747\u5FFD\u7565\uFF0Cmask \u5185\u7A7A\u6570\u7EC4/false \u8868\u793A\u663E\u5F0F\u6E05\u7A7A\u6216\u5173\u95ED\uFF1B\u5404 action \u56FA\u5B9A\u5FC5\u586B\u5B57\u6BB5\u65E0\u9700\u5199\u5165 mask\u3002\u5176\u4F59\u53C2\u6570\u5168\u53EF\u9009\u3001\u6309 action \u8FD0\u884C\u65F6\u6821\u9A8C\u5FC5\u586B\uFF08\u7F3A\u5931\u8FD4\u56DE\u5931\u8D25\u4E09\u8981\u7D20\uFF1A\u5BF9\u8C61+\u6839\u56E0+\u4FEE\u590D\u6307\u5F15\uFF09\u3002projectId \u4E3A key|id \u53CC\u5F62\u6001\uFF0C\u901A\u9053\u5C42\u81EA\u52A8\u5F52\u4E00\u4E3A 24-hex id\uFF1B\u663E\u5F0F\u6307\u5B9A\u89E3\u6790\u5931\u8D25\u62A5\u9519\u4E0D\u515C\u5E95\uFF1B\u7F3A\u7701\u8BED\u4E49\u6309 action\uFF1Acreate \u843D\u9ED8\u8BA4\u9879\u76EE\u94FE\uFF08\u5DE5\u4F5C\u533A defaultProject \u5931\u6548\u62A5\u9519\uFF0C\u65E0\u914D\u7F6E\u4E0D\u4F20\u7531 server \u6309\u6A21\u677F\u5F52\u5C5E\u515C\u5E95\uFF09\uFF0Cquery \u4E0D\u8FC7\u6EE4\uFF08\u5168\u5C40\u67E5\u8BE2\uFF09\u3002\u5199\u64CD\u4F5C\uFF08create/doc-*/record-*/archnote-add/pause/resume/cancel\uFF09\u54CD\u5E94\u4E3A\u8F7B\u91CF\u56DE\u6267\uFF1A{taskId, updated(\u89E6\u53CA\u5B57\u6BB5\u8DEF\u5F84), entry(\u65B0\u6761\u76EE id+kind\uFF0C\u4F9B\u540E\u7EED patch \u5B9A\u4F4D), echo(\u5199\u5165\u5185\u5BB9\u56DE\u663E), updatedAt, task(\u4EFB\u52A1\u8FDB\u5EA6\u6458\u8981 progress: {completed,total})}\u2014\u2014\u4E0D\u8FD4\u56DE\u5B8C\u6574\u4EFB\u52A1\u5B9E\u4F53\u3002action \u6E05\u5355\uFF08\u62EC\u53F7\u5185\u4E3A\u8BE5 action \u5FC5\u586B\u53C2\u6570\uFF09\uFF1Acreate(templateId,taskTitle,track\uFF1Btrack \u652F\u6301\u7EC4\u5408\u8F68\u9053\u2014\u2014\u6570\u7EC4\u5F62\u6001\uFF08\u5982 ["backend","godot"]\uFF0C\u6210\u5458=\u6CE8\u518C\u8868 active \u5355\u8F68\uFF09\u6216\u5355\u503C string\uFF1Ball \u4E3A\u4EFB\u52A1\u7EA7\u901A\u914D\uFF08\u6FC0\u6D3B\u521B\u5EFA\u65F6\u70B9\u5168\u90E8\u542F\u7528\u5355\u8F68\uFF0C\u5355\u503C\u4F7F\u7528\uFF09\uFF1B\u53EF\u9009 type=feature|bugfix|ui-tweak|research\u3001skipNodes\u3001projectId\uFF1BtemplateId \u652F\u6301 code|id \u53CC\u5F62\u6001\u2014\u2014code \u4E3A\u6A21\u677F\u4E1A\u52A1\u6807\u8BC6\uFF08\u9879\u76EE\u5185\u552F\u4E00\u3001kebab-case \u5FC5\u542B\u8FDE\u5B57\u7B26\uFF0C\u5982 full-workflow\uFF09\uFF0C\u63A8\u8350\u5F15\u7528\u5F62\u6001\uFF0C\u5BFB\u5740\u987B\u914D projectId \u6307\u5B9A\u9879\u76EE\u57DF\uFF1B24-hex \u6570\u636E\u5E93 id \u76F4\u67E5\u517C\u5BB9\uFF1Bcode \u5F62\u6001\u4E0D\u5B58\u5728\u65F6\u9519\u8BEF\u542B candidates \u76F8\u8FD1\u5019\u9009\u6E05\u5355\uFF08id/code/name \u22645 \u6761\uFF09\uFF1B\u54CD\u5E94 {task, firstNode}\u2014\u2014firstNode \u5373\u9996\u8282\u70B9\u5B8C\u6574\u8D44\u6599\u5305\uFF0C\u514D\u8C03 context)\uFF1Bquery(taskId \u8FD4\u56DE\u5355\u4EFB\u52A1\u8BE6\u60C5\uFF0C\u7F3A\u7701\u8FD4\u56DE\u5217\u8868\uFF0C\u53EF\u9009 status/track/projectId/page/limit)\uFF1Bcontext(taskId\uFF1B\u53EF\u9009 view=basic|full\u2014\u2014basic \u7F3A\u7701\u4E0D\u643A\u5E26 artifact \u5168\u6587\u5FEB\u7167\uFF0Cfull \u65AD\u70B9\u7EED\u8DD1\u9700\u5386\u53F2\u4EA7\u7269\u5168\u6587\u65F6\u7528\u3002\u26A0 \u514D\u91CD\u8BFB\uFF1Aadvance/approve \u6D41\u8F6C\u54CD\u5E94\u5DF2\u542B\u4E0B\u4E00\u8282\u70B9\u5B8C\u6574\u8D44\u6599\u5305\uFF0C\u540C\u4F1A\u8BDD\u5185\u6D41\u8F6C\u540E\u76F4\u63A5\u5F00\u5DE5\u3001\u65E0\u9700\u518D\u8C03 context\uFF1B\u4EC5\u65B0\u4F1A\u8BDD/\u65AD\u70B9\u7EED\u8DD1\u8C03\u7528)\uFF1Bnode(taskId,view=prompt|skills\uFF1BnodeId \u7F3A\u7701\u7528\u5F53\u524D\u8282\u70B9\uFF1B\u26A0 view \u503C\u968F action \u4E0D\u540C\uFF1Anode\u2192prompt|skills\uFF0Ccontext\u2192basic|full\uFF0C\u9519\u914D\u62A5\u9519)\uFF1Badvance(taskId\uFF1Bnote \u5199 history\u3001summary \u5199 nodeRecords\uFF0C\u4E24\u4F4D\u72EC\u7ACB\uFF1B\u26A0 T202610130004 \u7EC8\u6001\u6536\u5C3E\uFF1A\u4EFB\u52A1\u5904\u4E8E\u7EC8\u8282\u70B9\u65F6 advance \u5FC5\u5E26 finalize=true \u4F5C\u6536\u5C3E\u786E\u8BA4\uFF08\u7F3A\u7701\u88AB\u62D2\u5E76\u8FD4\u56DE\u63D0\u793A\uFF09\uFF0C\u4E2D\u95F4\u8282\u70B9\u5FFD\u7565\u8BE5\u53C2\u6570\uFF1B\u54CD\u5E94\u5DF2\u542B\u4E0B\u4E00\u8282\u70B9\u8D44\u6599\u5305\uFF0C\u540C\u4F1A\u8BDD\u514D\u91CD\u8BFB context\u3002\u26A0 T202609230001 \u8282\u70B9\u95E8\u7981\uFF1A\u914D\u7F6E\u4E86 toolChecks/aiChecks \u7684\u8282\u70B9\u63A8\u8FDB\u524D\u81EA\u52A8\u6267\u884C\u68C0\u67E5\u2014\u2014fail \u4F1A\u88AB\u6253\u56DE\u5E76\u8FD4\u56DE\u9010\u9879\u4FEE\u590D\u6307\u5F15\uFF08\u7ED3\u679C\u5DF2\u5199 history checks_rejected\uFF09\uFF0C\u6309\u6307\u5F15\u4FEE\u590D\u6216\u83B7\u7528\u6237\u8C41\u514D\u7559\u75D5\u540E\u91CD\u63A8\uFF1B\u975E\u4EBA\u5DE5\u5BA1\u6279\u8282\u70B9\u7981\u6B62\u56E0\u95E8\u7981\u4E2D\u65AD\u4EFB\u52A1\uFF08\u6253\u56DE\u4FE1\u606F\u5373\u7EE7\u7EED\u4F9D\u636E\uFF09\u3002force+forceReason \u6210\u5BF9\u63D0\u4F9B\u65F6\u53EF\u8D8A\u8FC7 fail \u5F3A\u5236\u63A8\u8FDB\u2014\u2014\u4EC5\u51ED\u7528\u6237\u660E\u793A\u6307\u4EE4\uFF0CAI \u7981\u6B62\u81EA\u51B3\uFF0C\u7406\u7531\u539F\u6587\u843D history \u5BA1\u8BA1)\uFF1Bcheck(taskId\uFF1B\u95E8\u7981\u53EA\u8BFB\u9884\u68C0\u2014\u2014\u9010\u9879\u62A5\u544A\u4E0D\u5199\u4EFB\u4F55\u72B6\u6001\uFF0Cadvance \u524D\u81EA\u67E5\u7528)\uFF1Bapprove(taskId,decision=approved|rejected\uFF1B\u53EF\u9009 comment\uFF1B\u54CD\u5E94\u5DF2\u542B\u4E0B\u4E00\u8282\u70B9\u8D44\u6599\u5305\uFF0C\u540C\u4F1A\u8BDD\u514D\u91CD\u8BFB context)\uFF1Bpause(taskId\uFF1B\u53EF\u9009 reason)\uFF1Bresume(taskId\uFF1B\u53EF\u9009 resumeNote)\uFF1Bcancel(taskId\uFF1B\u53EF\u9009 reason 1-500 \u5B57\u7B26\uFF1B\u26A0 \u7EC8\u6001\u4E0D\u53EF\u9006\u2014\u2014active/paused \u53EF\u53D6\u6D88\uFF0Ccompleted/cancelled \u62D2\u7EDD\u5E76\u8FD4\u56DE TASK_TERMINATED\uFF1B\u53D6\u6D88\u540E\u7ECF\u672C\u5DE5\u5177\u7684\u6D41\u8F6C\u4E0E\u8BB0\u5F55\u5199\u64CD\u4F5C\u88AB\u62D2)\uFF1Bhistory(taskId)\uFF1Binstance(taskId\u2014\u2014\u67E5\u770B\u4EFB\u52A1 DAG \u5B9E\u4F8B\u5FEB\u7167\uFF1A\u521B\u5EFA\u4EFB\u52A1\u65F6\u51BB\u7ED3\u7684\u6A21\u677F\u5B9E\u4F8B\uFF0C\u6A21\u677F\u540E\u7EED\u53D8\u66F4\u4E0D\u56DE\u6EAF)\u3002\u8BB0\u5F55\u5199\u5165\uFF1Arecord-set(taskId,node\uFF1Bsummary \u4E0E\u516D\u4E2A\u7ED3\u6784\u5316\u5B57\u6BB5\uFF08baseBranch/verifiedCommit/fixesApplied/testReport/deferredIssues/evidenceFiles\uFF09\u81F3\u5C11\u5176\u4E00\u2014\u2014\u7ED3\u6784\u5316\u5B57\u6BB5\u6309\u8282\u70B9 prompt\u300C\u7ED3\u6784\u5316\u5B57\u6BB5\u5199\u5165\u8981\u6C42\u300D\u9010\u5B57\u6BB5\u843D\u5E93\uFF0CPATCH \u8BED\u4E49=\u4EC5\u66F4\u65B0\u63D0\u4F9B\u5B57\u6BB5)\uFF1Brecord-check-add(taskId,node,item\uFF1B\u53EF\u9009 passed \u7F3A\u7701 true\u3001refId=aiChecks \u81EA\u68C0\u7559\u75D5\u951A\uFF08\u5BA1\u8BA1\u8BA4 refId===aiCheck.id \u4E14 passed=true\uFF0C\u7F3A\u7559\u75D5\u7684\u5B8C\u6210\u5224\u5B9A\u5BA1\u8BA1 fail\uFF09\u3001source=self|tool \u672C\u7248\u5DE5\u5177\u7F3A\u7701\u4E0D\u5199\uFF1B\u6279\u91CF checkItems \u5143\u7D20\u540C\u6784\uFF1B\u56DE\u6267 entry.id \u4F9B record-check-patch \u5B9A\u4F4D)\uFF1Brecord-check-patch(taskId,node,checkId\uFF1B\u53EF\u9009 passed/item/refId/source\uFF0C\u4EC5\u66F4\u65B0\u63D0\u4F9B\u5B57\u6BB5)\uFF1Brecord-artifact-add(taskId,node,artifactType=prd|tech|code|test|doc|other\uFF1Bpath \u7EAF\u5F15\u7528 / file \u8BFB\u672C\u673A\u6587\u4EF6 / content \u76F4\u4F20\u5168\u6587\u2014\u2014file \u4E0E content\u3001file \u4E0E path \u4E92\u65A5\uFF0Ccontent \u53EF\u4E0E path \u6210\u5BF9\u6216\u5355\u72EC\uFF0C\u5355\u72EC\u65F6\u767B\u8BB0\u503C\u5408\u6210 mcp-inline/<type>\uFF1B\u53EF\u9009 note)\uFF1Brecord-confirm(taskId,node,quote\u2014\u2014\u6682\u505C\u70B9\u7528\u6237\u786E\u8BA4\u539F\u6587\u9010\u5B57)\uFF1Brecord-decision-add(taskId,node,topic,decisionText)\uFF1Brecord-review-set(taskId,node,verdict=pass|fail,rounds,critical)\u3002\u9700\u6C42\u6587\u6863\uFF1Adoc-set(taskId\uFF1Bwhat/why/trackNote \u81F3\u5C11\u4F20\u4E00)\uFF1Bdoc-acceptance-add(taskId,text)\uFF1Bdoc-non-goal-add(taskId,text)\u3002\u7D20\u6750\uFF1Aarchnote-add(taskId,text)\u3002\u6279\u91CF\u5F62\u6001\uFF08\u63A8\u8350\uFF0C\u516D\u7C7B\u540C\u6784\uFF09\uFF1Arecord-check-add \u4F20 checkItems=[{item,passed?}]\u3001record-artifact-add \u4F20 artifactEntries=[{artifactType,path?/file?/content?,note?}]\u3001record-decision-add \u4F20 decisionEntries=[{topic,decisionText}]\u3001doc-acceptance-add/doc-non-goal-add/archnote-add \u4F20 textItems=[string]\u2014\u2014\u6279\u91CF\u53C2\u6570\u4E0E\u5355\u6761\u53C2\u6570\u4E8C\u9009\u4E00\uFF0C\u4E00\u6B21\u8C03\u7528\u5199\u591A\u6761\uFF08\u4E0A\u9650 50 \u6761/\u6279\uFF0Cartifact \u5168\u6587\u5FEB\u7167\u603B\u91CF \u22642M \u5B57\u7B26/\u6279\uFF09\uFF1B\u90E8\u5206\u5931\u8D25\u4FDD\u7559\u6210\u529F\u6761\u76EE\u5E76\u9010\u6761\u62A5\u544A\uFF08failures[].index=\u539F\u59CB\u63D0\u4EA4\u5E8F\uFF0C\u53EA\u91CD\u8BD5\u5931\u8D25\u9879\uFF09\uFF0Capplied=0 \u6574\u4F53\u62A5\u5931\u8D25\u3002',
2670
2703
  taskArgs,
2671
2704
  async (rawArgs) => {
2672
2705
  const masked = applyFieldMask(rawArgs, TASK_FIELD_SPECS);
@@ -2709,7 +2742,9 @@ function createMcpServer() {
2709
2742
  return mcpContent(
2710
2743
  await handleListTasks(client, {
2711
2744
  ...args.status !== void 0 ? { status: args.status } : {},
2712
- ...args.track !== void 0 ? { track: args.track } : {},
2745
+ // T202610120005:query 通道 track 收窄单值——列表按 trackAnchor 精确过滤;
2746
+ // 数组形态(组合)收窄为 join('+') 规范串(=组合任务的 anchor 形态,语义等价)
2747
+ ...args.track !== void 0 ? { track: Array.isArray(args.track) ? args.track.join("+") : args.track } : {},
2713
2748
  ...queryProjectId !== void 0 ? { projectId: queryProjectId } : {},
2714
2749
  ...args.page !== void 0 ? { page: args.page } : {},
2715
2750
  ...args.limit !== void 0 ? { limit: args.limit } : {}
@@ -3410,8 +3445,15 @@ function createTaskCommand() {
3410
3445
  const result = await handleQueryState(client, taskId);
3411
3446
  renderResult(opts.format, result, { fields: result.success ? taskFields(result.data) : [] });
3412
3447
  });
3413
- task.command("create").description("Create a task from a DAG template").option("--url <url>", "server base URL").requiredOption("--title <t>", "task title").requiredOption("--template <code|name|id>", "DAG template code (preferred), name, or 24-hex id (code/name resolved within project)").requiredOption("--track <t>", "task track (e.g. backend|ui|mixed|research \u2014 research \u4E3A\u8C03\u7814\u7C7B\u578B\u4E13\u7528\uFF0C\u987B\u914D --type research)").option("--type <t>", "task type (feature|bugfix|ui-tweak|research) \u2014 \u7C7B\u578B\u2192\u8DEF\u5F84\u6620\u5C04\u7531 task-create skill \u6301\u6709").option("--skip <ids>", "node ids to prune at creation (comma-separated, repeatable) \u2014 \u53EA\u5141\u8BB8\u6765\u81EA task-create skill \u7684\u6620\u5C04\u77E9\u9635", collectArgs, []).option("--project <key|id>", "projectId (key|id; defaults to workspace defaultProject then template projectId)").action(async (opts) => {
3448
+ task.command("create").description("Create a task from a DAG template").option("--url <url>", "server base URL").requiredOption("--title <t>", "task title").requiredOption("--template <code|name|id>", "DAG template code (preferred), name, or 24-hex id (code/name resolved within project)").requiredOption("--track <t>", "task track \u2014 \u7EC4\u5408\u8F68\u9053\uFF1A\u53EF\u91CD\u590D flag \u6216\u9017\u53F7\u5206\u9694\uFF08\u5982 --track backend,godot\uFF09\uFF1B\u5355\u8F68/all \u901A\u914D\u4F20\u5355\u503C\uFF08all=\u6FC0\u6D3B\u5168\u90E8\u542F\u7528\u5355\u8F68\uFF1Bresearch \u987B\u914D --type research\uFF09", collectArgs, []).option("--type <t>", "task type (feature|bugfix|ui-tweak|research) \u2014 \u7C7B\u578B\u2192\u8DEF\u5F84\u6620\u5C04\u7531 task-create skill \u6301\u6709").option("--skip <ids>", "node ids to prune at creation (comma-separated, repeatable) \u2014 \u53EA\u5141\u8BB8\u6765\u81EA task-create skill \u7684\u6620\u5C04\u77E9\u9635", collectArgs, []).option("--project <key|id>", "projectId (key|id; defaults to workspace defaultProject then template projectId)").action(async (opts) => {
3414
3449
  const client = createClient(opts.url);
3450
+ const rawTrack = typeof opts.track === "string" ? [opts.track] : opts.track ?? [];
3451
+ const trackMembers = [...new Set(rawTrack.flatMap((s) => s.split(",")).map((s) => s.trim()).filter((s) => s.length > 0))];
3452
+ if (trackMembers.length === 0) {
3453
+ renderResult("json", { success: false, error: { message: "--track \u4E0D\u80FD\u4E3A\u7A7A\uFF08\u5355\u8F68/all \u901A\u914D\u5355\u503C\uFF1B\u7EC4\u5408\u8F68\u9053\u9017\u53F7\u5206\u9694\u6216\u91CD\u590D\u4F20 flag\uFF0C\u5982 --track backend,godot\uFF09", httpStatus: 0 } });
3454
+ return;
3455
+ }
3456
+ const track = trackMembers.length === 1 ? trackMembers[0] : trackMembers;
3415
3457
  let type;
3416
3458
  if (opts.type !== void 0) {
3417
3459
  const r = parseEnum(opts.type, z5.enum(TASK_TYPES2), "--type");
@@ -3443,7 +3485,7 @@ function createTaskCommand() {
3443
3485
  }
3444
3486
  const result = await handleCreateTask(client, {
3445
3487
  title: opts.title,
3446
- track: opts.track,
3488
+ track,
3447
3489
  dagTemplateId: templateRef,
3448
3490
  ...type !== void 0 ? { type } : {},
3449
3491
  ...skipNodes !== void 0 && skipNodes.length > 0 ? { skipNodes } : {},
@@ -5256,6 +5298,12 @@ function renderYamlImportOutcome(outcome, planOnly) {
5256
5298
  if (c.descriptionChanged) console.log("\u63CF\u8FF0\u6709\u53D8\u66F4");
5257
5299
  if (c.layoutChanged) console.log("\u5E03\u5C40\u6709\u53D8\u66F4");
5258
5300
  }
5301
+ if (outcome.trackChains.length > 0) {
5302
+ console.log("\u8F68\u9053\u94FE\u5E8F\uFF08\u6A21\u62DF\u526A\u679D\u6865\u63A5 + \u5F15\u64CE\u8DEF\u7531\uFF09:");
5303
+ for (const tc of outcome.trackChains) {
5304
+ console.log(` ${tc.track}: ${tc.error !== void 0 ? `\u2717 ${tc.error}` : tc.chain.join(" \u2192 ")}`);
5305
+ }
5306
+ }
5259
5307
  if (outcome.id !== void 0) console.log(`\u6A21\u677F id: ${outcome.id}`);
5260
5308
  if (outcome.name !== void 0) console.log(`\u6A21\u677F\u540D: ${outcome.name}`);
5261
5309
  }
@@ -5801,7 +5849,8 @@ import { promisify as promisify2 } from "util";
5801
5849
  import { createInterface } from "readline/promises";
5802
5850
  import { Command as Command7 } from "commander";
5803
5851
  import {
5804
- SkillScopeSchema as SkillScopeSchema3
5852
+ SkillScopeSchema as SkillScopeSchema3,
5853
+ TEMPLATE_STRUCTURE_CONSTRAINTS
5805
5854
  } from "@siming-org/core";
5806
5855
 
5807
5856
  // src/commands/flow/manifest.ts
@@ -5812,7 +5861,8 @@ import {
5812
5861
  REFERENCE_LIMITS,
5813
5862
  SIMING_CODE_REGEX,
5814
5863
  SKILL_MAIN_DOC as SKILL_MAIN_DOC2,
5815
- createReferencesSchema as createReferencesSchema2
5864
+ createReferencesSchema as createReferencesSchema2,
5865
+ DagNodeTrackSchema
5816
5866
  } from "@siming-org/core";
5817
5867
  var FLOW_MANIFEST_FORMAT_VERSION = "1.2";
5818
5868
  var uniqueStrings = (values, ctx, label) => {
@@ -5846,7 +5896,8 @@ var nodePresetPayloadBaseSchema = z6.object({
5846
5896
  label: z6.string().min(1),
5847
5897
  nodeId: z6.string().regex(/^[A-Za-z0-9_-]+$/),
5848
5898
  phase: z6.string().min(1),
5849
- track: z6.string().min(1),
5899
+ // T202610120005 R7:节点轨道 union(与 core DagNodeTrackSchema 同源)
5900
+ track: DagNodeTrackSchema,
5850
5901
  prompt: z6.string().min(1),
5851
5902
  skills: capabilityRefsSchema,
5852
5903
  description: z6.string(),
@@ -6230,7 +6281,10 @@ ${conflicts.map((item) => ` ${item.kind}:${item.key} \u2014 ${item.reason ?? "\
6230
6281
  version: template.version,
6231
6282
  projectId: template.projectId,
6232
6283
  nodes: template.nodes.map((node) => ({ id: node.id, code: node.sourcePreset?.code ?? null })),
6233
- message: `\u7EC4\u5408 "${composition}" \u5DF2\u7EC4\u88C5\u4E3A\u6A21\u677F ${template.name}\uFF08${String(template.nodes.length)} \u8282\u70B9\uFF09`
6284
+ message: `\u7EC4\u5408 "${composition}" \u5DF2\u7EC4\u88C5\u4E3A\u6A21\u677F ${template.name}\uFF08${String(template.nodes.length)} \u8282\u70B9\uFF09\u2014\u2014\u6A21\u677F\u7ED3\u6784\u7EA6\u675F\u901F\u67E5\uFF084 \u6761\u6B63\u53CD\u4F8B\uFF09\u89C1 structureConstraints \u5B57\u6BB5`,
6285
+ // T202610120004 C3:结构约束速查(4 条正反例——配置者不读引擎源码也能写出单链轨道模板;
6286
+ // 文案单源 core TEMPLATE_STRUCTURE_CONSTRAINTS,web 画布速查面板同源消费)
6287
+ structureConstraints: TEMPLATE_STRUCTURE_CONSTRAINTS
6234
6288
  }));
6235
6289
  });
6236
6290
  return flow;
@@ -9123,7 +9177,7 @@ ${ROADMAP_TEXT}
9123
9177
  \u4E24\u5C42\u6982\u5FF5\u533A\u5206\uFF1A\u4EE5\u4E0A\u88C1\u526A\u662F\u6A21\u677F\u7EA7\u6C38\u4E45\u88C1\u526A\uFF08\u6539\u6A21\u677F\u5B9A\u4E49\uFF0C\u5F71\u54CD\u8BE5\u9879\u76EE
9124
9178
  \u6240\u6709\u540E\u7EED\u4EFB\u52A1\uFF09\uFF1B\u521B\u5EFA\u4EFB\u52A1\u65F6\u5F15\u64CE\u8FD8\u4F1A\u6309\u4EFB\u52A1\u8F68\u9053\u5BF9\u8282\u70B9 track \u81EA\u52A8\u526A\u679D
9125
9179
  \uFF08backend/ui/research \u53CA\u81EA\u5B9A\u4E49\u8F68\u9053\u4EFB\u52A1\u4FDD\u7559\u672C\u8F68\u9053+all \u8282\u70B9\uFF0C
9126
- mixed \u4EFB\u52A1\u4FDD\u7559\u53CC\u8F68\u5168\u94FE\uFF09\uFF0C\u8F68\u9053\u526A\u679D\u672C\u8EAB\u65E0\u9700\u624B\u52A8\u8DF3\u8FC7\u2014\u2014\u6A21\u677F\u5B58\u5728
9180
+ \u7EC4\u5408\u4EFB\u52A1\u4FDD\u7559\u6210\u5458\u8F68\u5168\u94FE\uFF09\uFF0C\u8F68\u9053\u526A\u679D\u672C\u8EAB\u65E0\u9700\u624B\u52A8\u8DF3\u8FC7\u2014\u2014\u6A21\u677F\u5B58\u5728
9127
9181
  \u8F68\u9053\u526A\u679D\u540E\u4E0D\u88AB\u884C\u8D70\u7684\u5206\u652F\u65F6\uFF0C\u4ECD\u987B\u6309\u6A21\u677F\u5339\u914D\u89C4\u5219 skip \u989D\u5916\u88C1\u526A\uFF1B
9128
9182
  \u4EFB\u52A1\u7EA7\u8F68\u9053\u526A\u679D\u8BED\u4E49\u8BE6\u89C1 task-create \u5B9A\u5236\u9AA8\u67B6\u3002
9129
9183
 
@@ -9174,10 +9228,13 @@ ${MCP_TOOLING_TEXT}
9174
9228
  1. \u786E\u8BA4 server \u53EF\u8FBE\uFF1Asiming healthcheck\uFF08\u6216 siming doctor \u5168\u9762\u81EA\u68C0\uFF09\uFF1B
9175
9229
  \u5E76\u786E\u8BA4\u5BBF\u4E3B\u5DE5\u5177\u9762\u677F\u5DF2\u51FA\u73B0\u4E0A\u8FF0\u4E09\u4E2A siming MCP \u5DE5\u5177\u2014\u2014\u4EFB\u4E00\u7F3A\u5931\u65F6\uFF0C
9176
9230
  \u6309\u4E0A\u65B9\u300C\u5BBF\u4E3B\u517C\u5BB9\u6027\u81EA\u68C0\u4E0E\u9002\u914D\u300D\u5B8C\u6210\u590D\u5236\u6539\u5199\u4E0E\u843D\u70B9\u9002\u914D\uFF0C\u5BBF\u4E3B
9177
- \u4E0D\u652F\u6301 MCP \u65F6\u8D70 siming CLI \u515C\u5E95
9231
+ \u4E0D\u652F\u6301 MCP \u65F6\u8D70 siming CLI \u515C\u5E95\u3002
9232
+ opencode v2 \u5BBF\u4E3B\u63A5\u5165\u9996\u9009\u63D2\u4EF6\u5F62\u6001\uFF1Aopencode plugin add @siming-org/opencode-plugin
9233
+ \u2014\u2014MCP \u4E09\u4EF6\u5DE5\u5177\u4E0E\u6280\u80FD/\u5B50\u4EE3\u7406\u7ECF\u63D2\u4EF6\u81EA\u52A8\u6CE8\u518C\u5E76\u968F server \u72B6\u6001\u4FDD\u6301\u65B0\u9C9C\uFF1B
9234
+ .agents \u624B\u5DE5\u94FE\u8DEF\u4FDD\u7559\u4E3A\u65E0\u63D2\u4EF6\u73AF\u5883\u7684\u56DE\u9000\u8DEF\u5F84
9178
9235
  2. AI \u5BBF\u4E3B\u65B0\u4F1A\u8BDD\u52A0\u8F7D\u9879\u76EE\u7EA7 task-create\uFF0C\u6309\u5176\u5339\u914D\u89C4\u5219\u9009\u6A21\u677F\u4E0E\u526A\u679D
9179
9236
  \uFF08\u5224\u5B9A\u8F68\u9053\u540E\u5F15\u64CE\u6309\u8282\u70B9 track \u81EA\u52A8\u526A\u679D\uFF1A\u5355\u8F68\u4EFB\u52A1\u4FDD\u7559\u672C\u8F68\u9053+all \u8282\u70B9\uFF0C
9180
- mixed \u4EFB\u52A1\u4FDD\u7559\u53CC\u8F68\u5168\u94FE\uFF1Bskip \u4EC5\u7528\u4E8E\u8F68\u9053\u526A\u679D\u4E4B\u5916\u7684\u989D\u5916\u88C1\u526A\uFF0C
9237
+ \u7EC4\u5408\u4EFB\u52A1\u4FDD\u7559\u6210\u5458\u8F68\u5168\u94FE\uFF1Bskip \u4EC5\u7528\u4E8E\u8F68\u9053\u526A\u679D\u4E4B\u5916\u7684\u989D\u5916\u88C1\u526A\uFF0C
9181
9238
  \u6A21\u677F\u5B58\u5728\u8F68\u9053\u526A\u679D\u540E\u4E0D\u88AB\u884C\u8D70\u7684\u5206\u652F\u65F6\u5FC5\u987B skip\uFF09
9182
9239
  3. \u521B\u5EFA\u9996\u4EFB\u52A1\uFF1A\u4EFB\u52A1\u5F15\u7528\u6A21\u677F\u4E00\u5F8B\u7528 code \u5F62\u6001\uFF08templateId \u4F20\u6A21\u677F code +
9183
9240
  projectId \u6307\u5B9A\u9879\u76EE\u57DF\uFF1B24 \u4F4D\u6570\u636E\u5E93 id \u517C\u5BB9\uFF09\u2014\u2014code \u7ECF
@@ -10085,8 +10142,17 @@ function createIssueCommand() {
10085
10142
  const result = await handleDoneIssue(client, issueId, opts.note);
10086
10143
  renderResult(opts.format ?? "fancy", result);
10087
10144
  });
10088
- withCommonOpts(issue.command("convert"), "fancy").requiredOption("--issue-ids <ids>", "comma-separated issue ids (or repeatable flag)", collectArgs, []).option("--declaration <mode>", "uniform declaration for all issues: all|partial (default all)").option("--declarations <map>", "per-issue declarations: id1:all,id2:partial (overrides --declaration)").requiredOption("--title <t>", "new task title").requiredOption("--template <code|name|id>", "DAG template code (preferred), name, or 24-hex id").requiredOption("--track <t>", "task track (backend|ui|mixed|research)").option("--type <t>", "task type (feature|bugfix|ui-tweak|research)").option("--skip <ids>", "node ids to prune (comma-separated, repeatable)", collectArgs, []).option("--project <key|id>", "projectId (key|id; issues and new task must belong to it)").description("Convert issues to a task (single group: N issues \u2192 1 task; split = multiple calls)").action(async (opts) => {
10145
+ withCommonOpts(issue.command("convert"), "fancy").requiredOption("--issue-ids <ids>", "comma-separated issue ids (or repeatable flag)", collectArgs, []).option("--declaration <mode>", "uniform declaration for all issues: all|partial (default all)").option("--declarations <map>", "per-issue declarations: id1:all,id2:partial (overrides --declaration)").requiredOption("--title <t>", "new task title").requiredOption("--template <code|name|id>", "DAG template code (preferred), name, or 24-hex id").requiredOption("--track <t>", "task track \u2014 \u7EC4\u5408\u8F68\u9053\uFF1A\u53EF\u91CD\u590D flag \u6216\u9017\u53F7\u5206\u9694\uFF08\u5982 --track backend,godot\uFF09\uFF1B\u5355\u8F68/all \u901A\u914D\u4F20\u5355\u503C", collectArgs, []).option("--type <t>", "task type (feature|bugfix|ui-tweak|research)").option("--skip <ids>", "node ids to prune (comma-separated, repeatable)", collectArgs, []).option("--project <key|id>", "projectId (key|id; issues and new task must belong to it)").description("Convert issues to a task (single group: N issues \u2192 1 task; split = multiple calls)").action(async (opts) => {
10089
10146
  const client = createClient(opts.url);
10147
+ const trackMembers = [...new Set((opts.track ?? []).flatMap((s) => s.split(",")).map((s) => s.trim()).filter((s) => s.length > 0))];
10148
+ if (trackMembers.length === 0) {
10149
+ renderResult("json", {
10150
+ success: false,
10151
+ error: { message: "--track \u4E0D\u80FD\u4E3A\u7A7A\uFF08\u5355\u8F68/all \u901A\u914D\u5355\u503C\uFF1B\u7EC4\u5408\u8F68\u9053\u9017\u53F7\u5206\u9694\u6216\u91CD\u590D\u4F20 flag\uFF09", httpStatus: 0 }
10152
+ });
10153
+ return;
10154
+ }
10155
+ const track = trackMembers.length === 1 ? trackMembers[0] : trackMembers;
10090
10156
  const issueIds = [
10091
10157
  ...new Set((opts.issueIds ?? []).flatMap((s) => s.split(",")).map((s) => s.trim()).filter((s) => s.length > 0))
10092
10158
  ];
@@ -10160,7 +10226,7 @@ function createIssueCommand() {
10160
10226
  issueIds,
10161
10227
  task: {
10162
10228
  title: opts.title,
10163
- track: opts.track,
10229
+ track,
10164
10230
  dagTemplateId: templateRef,
10165
10231
  ...skipNodes !== void 0 && skipNodes.length > 0 ? { skipNodes } : {},
10166
10232
  ...type !== void 0 ? { type } : {}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@siming-org/cli",
3
- "version": "0.8.4",
3
+ "version": "0.8.6",
4
4
  "license": "MIT",
5
5
  "author": "Wuchao",
6
6
  "engines": {
@@ -27,8 +27,8 @@
27
27
  "picocolors": "^1.1.1",
28
28
  "yaml": "^2.6.0",
29
29
  "zod": "^4.4.3",
30
- "@siming-org/server": "0.8.4",
31
- "@siming-org/core": "0.8.4"
30
+ "@siming-org/core": "0.8.6",
31
+ "@siming-org/server": "0.8.6"
32
32
  },
33
33
  "devDependencies": {
34
34
  "tsup": "^8.3.5",