@siming-org/cli 0.7.3 → 0.7.4

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.
Files changed (2) hide show
  1. package/dist/index.js +408 -235
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -1307,17 +1307,24 @@ async function handleUpdateProject(client, id, patch) {
1307
1307
  return client.putJson(`/api/projects/${encodeURIComponent(id)}`, patch);
1308
1308
  }
1309
1309
  var OBJECT_ID_HEX = /^[a-f0-9]{24}$/;
1310
- async function resolveProjectId(client, input) {
1310
+ function formatCandidateHint(projects, input) {
1311
+ const q = input.toLowerCase();
1312
+ const hits = projects.filter((p) => p.key.toLowerCase().includes(q) || p.name.toLowerCase().includes(q)).slice(0, 5).map((p) => `${p.key} (${p.name})`);
1313
+ if (hits.length === 0) return void 0;
1314
+ return `\u76F8\u8FD1\u9879\u76EE\uFF1A${hits.join("\u3001")}\uFF1B\u68C0\u67E5\u62FC\u5199\uFF0C\u6216 siming project list \u67E5\u770B\u5168\u90E8\u9879\u76EE`;
1315
+ }
1316
+ async function resolveProjectId(client, input, opts) {
1311
1317
  if (OBJECT_ID_HEX.test(input)) return { success: true, data: input };
1312
1318
  const list = await handleListProjects(client);
1313
1319
  if (!list.success) return list;
1314
1320
  const hit = list.data.find((p) => p.key === input);
1315
1321
  if (!hit) {
1322
+ const candidateHint = opts?.withCandidates === true ? formatCandidateHint(list.data, input) : void 0;
1316
1323
  const error = {
1317
1324
  message: `project "${input}" not found`,
1318
1325
  httpStatus: 404,
1319
1326
  bizCode: "PROJECT_NOT_FOUND",
1320
- hint: `check \`siming project list\` for available keys; pass --project <key|id>`
1327
+ hint: candidateHint ?? `check \`siming project list\` for available keys; pass --project <key|id>`
1321
1328
  };
1322
1329
  return fail(error);
1323
1330
  }
@@ -1331,6 +1338,74 @@ async function resolveProjectId(client, input) {
1331
1338
  }
1332
1339
  return { success: true, data: hit.id };
1333
1340
  }
1341
+ async function findProjectDetailByKey(client, key) {
1342
+ const list = await handleListProjects(client);
1343
+ if (!list.success) return list;
1344
+ const hit = list.data.find((p) => p.key === key);
1345
+ if (hit === void 0) {
1346
+ return fail({
1347
+ message: `workspace defaultProject "${key}" not found (removed or renamed)`,
1348
+ httpStatus: 0,
1349
+ bizCode: "DEFAULT_PROJECT_INVALID",
1350
+ hint: DEFAULT_PROJECT_HINT
1351
+ });
1352
+ }
1353
+ if (hit.id === void 0) {
1354
+ return fail({
1355
+ message: `workspace defaultProject "${key}" has no id`,
1356
+ httpStatus: 500,
1357
+ hint: "server returned a project without id; check `siming project list`"
1358
+ });
1359
+ }
1360
+ return ok2({ id: hit.id, status: hit.status });
1361
+ }
1362
+ var MCP_PROJECT_HINT = "MCP \u8C03\u7528\u8BF7\u4F20 projectId \u5B57\u6BB5\uFF08\u9879\u76EE key \u6216 24-hex id \u53CC\u5F62\u6001\uFF0C\u81EA\u52A8\u5F52\u4E00\uFF09\uFF1B\u53EF\u7528 `siming project list` \u67E5\u8BE2\u53EF\u7528\u9879\u76EE";
1363
+ var DEFAULT_PROJECT_HINT = "siming config unset defaultProject \u540E\u91CD\u8BD5\uFF0C\u6216 siming config set defaultProject <key|id> \u91CD\u8BBE\uFF1Bsiming project list \u67E5\u770B\u53EF\u7528\u9879\u76EE";
1364
+ var PROJECT_REQUIRED_HINT = "\u663E\u5F0F\u4F20 --project <key|id>\uFF0C\u6216 siming config set defaultProject <key|id> \u914D\u7F6E\u9ED8\u8BA4\u9879\u76EE\uFF1Bsiming project list \u67E5\u770B\u53EF\u7528\u9879\u76EE";
1365
+ async function resolveScopedProject(client, explicit, tail, opts) {
1366
+ const value = explicit !== void 0 && explicit.trim().length > 0 ? explicit.trim() : void 0;
1367
+ if (value !== void 0) {
1368
+ const r = await resolveProjectId(client, value, { withCandidates: true });
1369
+ if (!r.success) {
1370
+ return fail(
1371
+ opts?.channel === "mcp" && r.error.bizCode === "PROJECT_NOT_FOUND" ? { ...r.error, hint: MCP_PROJECT_HINT } : r.error
1372
+ );
1373
+ }
1374
+ return ok2({ projectId: r.data, source: "explicit" });
1375
+ }
1376
+ if (tail === "explicit-only") {
1377
+ return ok2({ source: "explicit" });
1378
+ }
1379
+ const wsDefault = readWorkspaceConfig()?.defaultProject;
1380
+ if (wsDefault !== void 0) {
1381
+ const detail = await findProjectDetailByKey(client, wsDefault);
1382
+ if (!detail.success) return detail;
1383
+ if (detail.data.status !== "active") {
1384
+ return fail({
1385
+ message: `workspace defaultProject "${wsDefault}" is archived`,
1386
+ httpStatus: 0,
1387
+ bizCode: "DEFAULT_PROJECT_INVALID",
1388
+ hint: DEFAULT_PROJECT_HINT
1389
+ });
1390
+ }
1391
+ return ok2({ projectId: detail.data.id, source: "workspace-default" });
1392
+ }
1393
+ if (tail === "ws-default") {
1394
+ return ok2({ source: "delegated" });
1395
+ }
1396
+ const list = await handleListProjects(client);
1397
+ if (!list.success) return list;
1398
+ const instanceDefault = list.data.find((p) => p.key === "default");
1399
+ if (instanceDefault === void 0 || instanceDefault.id === void 0) {
1400
+ return fail({
1401
+ message: `${opts?.commandLabel ?? "this command"} needs a project: no --project given, no workspace defaultProject, and no key=default project on server`,
1402
+ httpStatus: 0,
1403
+ bizCode: "PROJECT_REQUIRED",
1404
+ hint: PROJECT_REQUIRED_HINT
1405
+ });
1406
+ }
1407
+ return ok2({ projectId: instanceDefault.id, source: "instance-default" });
1408
+ }
1334
1409
  async function resolveProjectKey(client, input) {
1335
1410
  const list = await handleListProjects(client);
1336
1411
  if (!list.success) return list;
@@ -1463,7 +1538,7 @@ var issueArgs = {
1463
1538
  // create
1464
1539
  title: z3.string().optional(),
1465
1540
  description: z3.string().optional(),
1466
- // 公共:create 缺省按工作区 defaultProject,无配置时按 key=default / query 过滤(24-hex)
1541
+ // 公共:create 缺省按工作区 defaultProject(key|id 双形态通道层归一,失效报错)/ query 过滤(空/未传不过滤)
1467
1542
  projectId: z3.string().optional(),
1468
1543
  // query:view 缺省 open(有效未跟进完);与 REST 词汇统一(status/taskId 指定时切对应过滤)
1469
1544
  view: hostNeutralEnum(z3.enum(["open", "all"])).optional(),
@@ -1608,7 +1683,7 @@ function createMcpServer() {
1608
1683
  const client = createClient(void 0, "mcp");
1609
1684
  server.tool(
1610
1685
  "siming_task",
1611
- "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\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)\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,summary)\uFF1Brecord-check-add(taskId,node,item\uFF1B\u53EF\u9009 passed \u7F3A\u7701 true\uFF1B\u56DE\u6267 entry.id \u4F9B record-check-patch \u5B9A\u4F4D)\uFF1Brecord-check-patch(taskId,node,checkId\uFF1B\u53EF\u9009 passed)\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",
1686
+ "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)\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,summary)\uFF1Brecord-check-add(taskId,node,item\uFF1B\u53EF\u9009 passed \u7F3A\u7701 true\uFF1B\u56DE\u6267 entry.id \u4F9B record-check-patch \u5B9A\u4F4D)\uFF1Brecord-check-patch(taskId,node,checkId\uFF1B\u53EF\u9009 passed)\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",
1612
1687
  taskArgs,
1613
1688
  async (rawArgs) => {
1614
1689
  const masked = applyFieldMask(rawArgs, TASK_FIELD_SPECS);
@@ -1620,13 +1695,15 @@ function createMcpServer() {
1620
1695
  if (templateId === void 0 || taskTitle === void 0 || track === void 0) {
1621
1696
  return requireError("create", ["templateId", "taskTitle", "track"], args);
1622
1697
  }
1698
+ const projectR = await resolveScopedProject(client, args.projectId, "ws-default", { channel: "mcp" });
1699
+ if (!projectR.success) return mcpContent(projectR);
1623
1700
  const input = {
1624
1701
  title: taskTitle,
1625
1702
  track,
1626
1703
  dagTemplateId: templateId,
1627
1704
  ...args.type !== void 0 ? { type: args.type } : {},
1628
1705
  ...args.skipNodes !== void 0 ? { skipNodes: args.skipNodes } : {},
1629
- ...args.projectId !== void 0 ? { projectId: args.projectId } : {}
1706
+ ...projectR.data.projectId !== void 0 ? { projectId: projectR.data.projectId } : {}
1630
1707
  };
1631
1708
  return mcpContent(await handleCreateTask(client, input));
1632
1709
  }
@@ -1640,11 +1717,17 @@ function createMcpServer() {
1640
1717
  if (args.taskId) {
1641
1718
  return mcpContent(await handleQueryState(client, args.taskId));
1642
1719
  }
1720
+ let queryProjectId;
1721
+ if (args.projectId !== void 0 && args.projectId.trim().length > 0) {
1722
+ const pr = await resolveScopedProject(client, args.projectId, "explicit-only", { channel: "mcp" });
1723
+ if (!pr.success) return mcpContent(pr);
1724
+ queryProjectId = pr.data.projectId;
1725
+ }
1643
1726
  return mcpContent(
1644
1727
  await handleListTasks(client, {
1645
1728
  ...args.status !== void 0 ? { status: args.status } : {},
1646
1729
  ...args.track !== void 0 ? { track: args.track } : {},
1647
- ...args.projectId !== void 0 ? { projectId: args.projectId } : {},
1730
+ ...queryProjectId !== void 0 ? { projectId: queryProjectId } : {},
1648
1731
  ...args.page !== void 0 ? { page: args.page } : {},
1649
1732
  ...args.limit !== void 0 ? { limit: args.limit } : {}
1650
1733
  })
@@ -1942,26 +2025,38 @@ function createMcpServer() {
1942
2025
  );
1943
2026
  server.tool(
1944
2027
  "siming_template",
1945
- "DAG \u6A21\u677F\u53EA\u8BFB\u67E5\u8BE2\uFF08\u4EFB\u52A1\u521B\u5EFA\u524D\u9009\u6A21\u677F/\u6838\u5BF9\u6A21\u677F\u7ED3\u6784\u7528\uFF1B\u672C\u5DE5\u5177\u65E0\u5199\u64CD\u4F5C\uFF09\u3002action\uFF1Alist=\u6A21\u677F\u5217\u8868\uFF08\u6982\u8981\u6295\u5F71\uFF0C\u542B id/code/name/version/isDefault/projectId/nodeCount/nodes \u6982\u8981/pausePoints/description\uFF0C\u4E0D\u542B\u8282\u70B9 prompt \u5168\u6587\uFF1B\u53EF\u9009 projectId \u8FC7\u6EE4\u9879\u76EE\u57DF\uFF1B\u8FD4\u56DE code \u4E3A\u540E\u7EED\u5F15\u7528\u6A21\u677F\u7684\u63A8\u8350\u5F62\u6001\uFF09\uFF1Bshow=\u6A21\u677F\u8BE6\u60C5\uFF08\u542B\u5168\u90E8\u8282\u70B9 prompt\uFF1BtemplateId \u652F\u6301 code|id \u53CC\u5F62\u6001\u2014\u2014code \u4E3A\u4E1A\u52A1\u6807\u8BC6\uFF08\u9879\u76EE\u5185\u552F\u4E00\u3001\u521B\u5EFA\u540E\u4E0D\u53EF\u53D8\u3001kebab-case \u5FC5\u542B\u8FDE\u5B57\u7B26\u4E14\u975E\u7EAF 24-hex \u5F62\u6001\uFF0C\u5982 full-workflow\uFF09\uFF0Ccode \u5F62\u6001\u5BFB\u5740\u987B\u914D projectId \u6307\u5B9A\u9879\u76EE\u57DF\uFF1B24 \u4F4D\u6570\u636E\u5E93 id \u76F4\u67E5\u517C\u5BB9\uFF0C\u65E0\u9700 projectId\uFF09\u3002\u6A21\u677F\u4E0D\u5B58\u5728\u65F6\u9519\u8BEF\u4FE1\u606F\u542B candidates \u5019\u9009\u6E05\u5355\uFF08\u9879\u76EE\u5185\u76F8\u8FD1\u6A21\u677F\u7684 id/code/name\uFF0C\u6309\u76F8\u5173\u5EA6\u6392\u5E8F\u4E0A\u9650 5 \u6761\uFF09\u2014\u2014\u8F6C\u5F55\u9519\u8BEF\u53EF\u636E\u6E05\u5355\u5F53\u573A\u7EA0\u6B63\u3002\u505C\u7528\u6A21\u677F\uFF08Web \u7BA1\u7406\u53F0\u542F\u505C\uFF09\uFF1Alist \u9ED8\u8BA4\u4E0D\u542B\u505C\u7528\u6A21\u677F\uFF1Bshow \u6309 code|id \u4ECD\u53EF\u8BFB\uFF1B\u7528\u505C\u7528\u6A21\u677F\u521B\u5EFA\u4EFB\u52A1\u88AB\u62D2\uFF08409 TEMPLATE_DISABLED\uFF09\u2014\u2014\u9700\u5728 Web \u7BA1\u7406\u53F0\u91CD\u65B0\u542F\u7528\u540E\u518D\u5EFA\u4EFB\u52A1\u3002\u6A21\u677F\u5199\u5165\u4E0E\u6F14\u8FDB\u4E0D\u5728 MCP\uFF1A\u5BFC\u5165\uFF08\u542B\u540C\u540D\u66F4\u65B0/\u9884\u89C8/\u5B8C\u6574\u4F9D\u8D56\u95ED\u5305 bundle\uFF09\u7528 CLI `siming dag template import`\uFF0C\u6A21\u677F\u5347\u7EA7\u9884\u68C0/\u6267\u884C\u7528 CLI `siming dag template upgrade plan/apply`\uFF08bash \u6267\u884C\uFF0C--help \u67E5\u7528\u6CD5\uFF09\u3002",
2028
+ "DAG \u6A21\u677F\u53EA\u8BFB\u67E5\u8BE2\uFF08\u4EFB\u52A1\u521B\u5EFA\u524D\u9009\u6A21\u677F/\u6838\u5BF9\u6A21\u677F\u7ED3\u6784\u7528\uFF1B\u672C\u5DE5\u5177\u65E0\u5199\u64CD\u4F5C\uFF09\u3002action\uFF1Alist=\u6A21\u677F\u5217\u8868\uFF08\u6982\u8981\u6295\u5F71\uFF0C\u542B id/code/name/version/isDefault/projectId/nodeCount/nodes \u6982\u8981/pausePoints/description\uFF0C\u4E0D\u542B\u8282\u70B9 prompt \u5168\u6587\uFF1B\u53EF\u9009 projectId \u8FC7\u6EE4\u9879\u76EE\u57DF\u2014\u2014key|id \u53CC\u5F62\u6001\uFF0C\u901A\u9053\u5C42\u81EA\u52A8\u5F52\u4E00\uFF0C\u7A7A/\u672A\u4F20\u4E0D\u8FC7\u6EE4\uFF1B\u8FD4\u56DE code \u4E3A\u540E\u7EED\u5F15\u7528\u6A21\u677F\u7684\u63A8\u8350\u5F62\u6001\uFF09\uFF1Bshow=\u6A21\u677F\u8BE6\u60C5\uFF08\u542B\u5168\u90E8\u8282\u70B9 prompt\uFF1BtemplateId \u652F\u6301 code|id \u53CC\u5F62\u6001\u2014\u2014code \u4E3A\u4E1A\u52A1\u6807\u8BC6\uFF08\u9879\u76EE\u5185\u552F\u4E00\u3001\u521B\u5EFA\u540E\u4E0D\u53EF\u53D8\u3001kebab-case \u5FC5\u542B\u8FDE\u5B57\u7B26\u4E14\u975E\u7EAF 24-hex \u5F62\u6001\uFF0C\u5982 full-workflow\uFF09\uFF0Ccode \u5F62\u6001\u5BFB\u5740\u987B\u914D projectId \u6307\u5B9A\u9879\u76EE\u57DF\u2014\u2014key|id \u53CC\u5F62\u6001\u81EA\u52A8\u5F52\u4E00\uFF0C\u7F3A\u7701\u6309\u5DE5\u4F5C\u533A defaultProject\uFF08\u5931\u6548\u62A5\u9519\uFF09\uFF0C\u65E0\u914D\u7F6E\u4E0D\u4F20\u7531 server \u63D0\u793A\u8865\u57DF\uFF1B24 \u4F4D\u6570\u636E\u5E93 id \u76F4\u67E5\u517C\u5BB9\uFF0C\u65E0\u9700 projectId\uFF09\u3002\u6A21\u677F\u4E0D\u5B58\u5728\u65F6\u9519\u8BEF\u4FE1\u606F\u542B candidates \u5019\u9009\u6E05\u5355\uFF08\u9879\u76EE\u5185\u76F8\u8FD1\u6A21\u677F\u7684 id/code/name\uFF0C\u6309\u76F8\u5173\u5EA6\u6392\u5E8F\u4E0A\u9650 5 \u6761\uFF09\u2014\u2014\u8F6C\u5F55\u9519\u8BEF\u53EF\u636E\u6E05\u5355\u5F53\u573A\u7EA0\u6B63\u3002\u505C\u7528\u6A21\u677F\uFF08Web \u7BA1\u7406\u53F0\u542F\u505C\uFF09\uFF1Alist \u9ED8\u8BA4\u4E0D\u542B\u505C\u7528\u6A21\u677F\uFF1Bshow \u6309 code|id \u4ECD\u53EF\u8BFB\uFF1B\u7528\u505C\u7528\u6A21\u677F\u521B\u5EFA\u4EFB\u52A1\u88AB\u62D2\uFF08409 TEMPLATE_DISABLED\uFF09\u2014\u2014\u9700\u5728 Web \u7BA1\u7406\u53F0\u91CD\u65B0\u542F\u7528\u540E\u518D\u5EFA\u4EFB\u52A1\u3002\u6A21\u677F\u5199\u5165\u4E0E\u6F14\u8FDB\u4E0D\u5728 MCP\uFF1A\u5BFC\u5165\uFF08\u542B\u540C\u540D\u66F4\u65B0/\u9884\u89C8/\u5B8C\u6574\u4F9D\u8D56\u95ED\u5305 bundle\uFF09\u7528 CLI `siming dag template import`\uFF0C\u6A21\u677F\u5347\u7EA7\u9884\u68C0/\u6267\u884C\u7528 CLI `siming dag template upgrade plan/apply`\uFF08bash \u6267\u884C\uFF0C--help \u67E5\u7528\u6CD5\uFF09\u3002",
1946
2029
  templateArgs,
1947
2030
  async (args) => {
1948
2031
  switch (args.action) {
1949
2032
  case "list": {
1950
- const result = await handleListTemplates(client, args.projectId);
2033
+ let listProjectId;
2034
+ if (args.projectId !== void 0 && args.projectId.trim().length > 0) {
2035
+ const pr = await resolveScopedProject(client, args.projectId, "explicit-only", { channel: "mcp" });
2036
+ if (!pr.success) return mcpContent(pr);
2037
+ listProjectId = pr.data.projectId;
2038
+ }
2039
+ const result = await handleListTemplates(client, listProjectId);
1951
2040
  if (!result.success) return mcpContent(result);
1952
2041
  return mcpContent(ok2(result.data.map(toTemplateSummary)));
1953
2042
  }
1954
2043
  case "show": {
1955
- const { templateId, projectId } = args;
2044
+ const { templateId } = args;
1956
2045
  if (templateId === void 0) return requireError("show", ["templateId"], args);
1957
- return mcpContent(await handleGetTemplate(client, templateId, projectId));
2046
+ let showProjectId;
2047
+ if (!/^[a-f0-9]{24}$/.test(templateId)) {
2048
+ const pr = await resolveScopedProject(client, args.projectId, "ws-default", { channel: "mcp" });
2049
+ if (!pr.success) return mcpContent(pr);
2050
+ showProjectId = pr.data.projectId;
2051
+ }
2052
+ return mcpContent(await handleGetTemplate(client, templateId, showProjectId));
1958
2053
  }
1959
2054
  }
1960
2055
  }
1961
2056
  );
1962
2057
  server.tool(
1963
2058
  "siming_issue",
1964
- `\u95EE\u9898\u6C60\u5DE5\u5177\uFF08T202609150002\uFF09\uFF1A\u5C0F\u95EE\u9898\u4F4E\u6210\u672C\u5165\u6C60\uFF0C\u6C89\u6DC0\u540E\u7EDF\u4E00\u6574\u7406\u8F6C\u4EFB\u52A1\uFF08\u8F6C\u4EFB\u52A1/\u6574\u7406\u91CD\u4EA4\u4E92\u8D70 CLI siming issue convert \u6216 Web\uFF0C\u4E0D\u5728\u672C\u5DE5\u5177\u9762\uFF09\u3002action\uFF1Acreate(title \u5FC5\u586B 1-200 \u5B57\uFF1B\u53EF\u9009 description\u3001projectId\u2014\u2014key|id \u53CC\u5F62\u6001\uFF0C\u901A\u9053\u5C42\u81EA\u52A8\u5F52\u4E00\u4E3A 24-hex id\uFF08hex \u96F6\u7F51\u7EDC\u5F00\u9500\u76F4\u901A\uFF09\uFF1B\u663E\u5F0F\u6307\u5B9A\u89E3\u6790\u5931\u8D25\u62A5\u9519\u4E0D\u515C\u5E95\uFF1B\u7F3A\u7701\u94FE\uFF1A\u672A\u4F20\u6216\u7A7A\u4E32\u65F6\u6309\u5DE5\u4F5C\u533A defaultProject \u89E3\u6790\uFF0C\u65E0\u914D\u7F6E\u6216\u89E3\u6790\u5931\u8D25\u65F6\u6309 key=default\uFF1B\u5F55\u5165\u540E source=mcp)\uFF1Bquery(\u53EF\u9009 view=open|all\u2014\u2014\u7F3A\u7701 open=\u6709\u6548\u672A\u8DDF\u8FDB\u5B8C\uFF0Call=\u5168\u91CF\uFF1Bstatus \u8FC7\u6EE4\u2014\u2014\u663E\u5F0F\u6307\u5B9A\u65F6\u4F18\u5148\u4E8E view\uFF0C\u53EF\u67E5\u5DF2\u53D6\u6D88/\u5DF2\u5B8C\u7ED3\uFF1BtaskId=\u4EFB\u52A1\u53CD\u67E5\uFF1BprojectId/page\u22651/limit 1-500\uFF1B\u54CD\u5E94 items \u542B progress {done,cancelled,total})\u3002\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\uFF1B\u5404 action \u56FA\u5B9A\u5FC5\u586B\u5B57\u6BB5\u65E0\u9700\u5199\u5165 mask\u3002`,
2059
+ `\u95EE\u9898\u6C60\u5DE5\u5177\uFF08T202609150002\uFF09\uFF1A\u5C0F\u95EE\u9898\u4F4E\u6210\u672C\u5165\u6C60\uFF0C\u6C89\u6DC0\u540E\u7EDF\u4E00\u6574\u7406\u8F6C\u4EFB\u52A1\uFF08\u8F6C\u4EFB\u52A1/\u6574\u7406\u91CD\u4EA4\u4E92\u8D70 CLI siming issue convert \u6216 Web\uFF0C\u4E0D\u5728\u672C\u5DE5\u5177\u9762\uFF09\u3002action\uFF1Acreate(title \u5FC5\u586B 1-200 \u5B57\uFF1B\u53EF\u9009 description\u3001projectId\u2014\u2014key|id \u53CC\u5F62\u6001\uFF0C\u901A\u9053\u5C42\u81EA\u52A8\u5F52\u4E00\u4E3A 24-hex id\uFF08hex \u96F6\u7F51\u7EDC\u5F00\u9500\u76F4\u901A\uFF09\uFF1B\u663E\u5F0F\u6307\u5B9A\u89E3\u6790\u5931\u8D25\u62A5\u9519\u4E0D\u515C\u5E95\uFF1B\u7F3A\u7701\u94FE\uFF1A\u672A\u4F20\u6216\u7A7A\u4E32\u65F6\u6309\u5DE5\u4F5C\u533A defaultProject \u89E3\u6790\uFF08\u5931\u6548\u62A5\u9519\uFF09\uFF0C\u65E0\u914D\u7F6E\u65F6\u4E0D\u4F20 projectId \u7531 server \u6309 key=default \u515C\u5E95\uFF1B\u5F55\u5165\u540E source=mcp)\uFF1Bquery(\u53EF\u9009 view=open|all\u2014\u2014\u7F3A\u7701 open=\u6709\u6548\u672A\u8DDF\u8FDB\u5B8C\uFF0Call=\u5168\u91CF\uFF1Bstatus \u8FC7\u6EE4\u2014\u2014\u663E\u5F0F\u6307\u5B9A\u65F6\u4F18\u5148\u4E8E view\uFF0C\u53EF\u67E5\u5DF2\u53D6\u6D88/\u5DF2\u5B8C\u7ED3\uFF1BtaskId=\u4EFB\u52A1\u53CD\u67E5\uFF1BprojectId\u2014\u2014key|id \u53CC\u5F62\u6001\uFF0C\u901A\u9053\u5C42\u81EA\u52A8\u5F52\u4E00\uFF0C\u7A7A/\u672A\u4F20\u4E0D\u8FC7\u6EE4\uFF08\u663E\u5F0F\u89E3\u6790\u5931\u8D25\u62A5\u9519\uFF09\uFF1Bpage\u22651/limit 1-500\uFF1B\u54CD\u5E94 items \u542B progress {done,cancelled,total})\u3002\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\uFF1B\u5404 action \u56FA\u5B9A\u5FC5\u586B\u5B57\u6BB5\u65E0\u9700\u5199\u5165 mask\u3002`,
1965
2060
  issueArgs,
1966
2061
  async (rawArgs) => {
1967
2062
  const masked = applyFieldMask(rawArgs, ISSUE_FIELD_SPECS);
@@ -1973,27 +2068,9 @@ function createMcpServer() {
1973
2068
  if (title === void 0) {
1974
2069
  return requireError("create", ["title"], args);
1975
2070
  }
1976
- let projectId;
1977
- const explicitProject = args.projectId !== void 0 && args.projectId.trim().length > 0 ? args.projectId : void 0;
1978
- if (explicitProject !== void 0) {
1979
- const resolved = await resolveProjectId(client, explicitProject);
1980
- if (!resolved.success) {
1981
- return mcpContent({
1982
- ...resolved,
1983
- error: {
1984
- ...resolved.error,
1985
- hint: "MCP \u8C03\u7528\u8BF7\u4F20 projectId \u5B57\u6BB5\uFF08\u9879\u76EE key \u6216 24-hex id \u53CC\u5F62\u6001\uFF0C\u81EA\u52A8\u5F52\u4E00\uFF09\uFF1B\u53EF\u7528 `siming project list` \u67E5\u8BE2\u53EF\u7528\u9879\u76EE"
1986
- }
1987
- });
1988
- }
1989
- projectId = resolved.data;
1990
- } else {
1991
- const wsDefaultProject = readWorkspaceConfig()?.defaultProject;
1992
- if (wsDefaultProject) {
1993
- const resolved = await resolveProjectId(client, wsDefaultProject);
1994
- if (resolved.success) projectId = resolved.data;
1995
- }
1996
- }
2071
+ const projectR = await resolveScopedProject(client, args.projectId, "ws-default", { channel: "mcp" });
2072
+ if (!projectR.success) return mcpContent(projectR);
2073
+ const projectId = projectR.data.projectId;
1997
2074
  return mcpContent(
1998
2075
  await handleCreateIssue(client, {
1999
2076
  title,
@@ -2009,12 +2086,18 @@ function createMcpServer() {
2009
2086
  if (args.limit !== void 0 && (args.limit < 1 || args.limit > 500)) {
2010
2087
  return localError("action=query \u7684 limit \u5FC5\u987B\u4E3A 1-500 \u7684\u6574\u6570");
2011
2088
  }
2089
+ let issueQueryProjectId;
2090
+ if (args.projectId !== void 0 && args.projectId.trim().length > 0) {
2091
+ const pr = await resolveScopedProject(client, args.projectId, "explicit-only", { channel: "mcp" });
2092
+ if (!pr.success) return mcpContent(pr);
2093
+ issueQueryProjectId = pr.data.projectId;
2094
+ }
2012
2095
  return mcpContent(
2013
2096
  await handleListIssues(client, {
2014
2097
  view: args.view ?? "open",
2015
2098
  ...args.status !== void 0 ? { status: args.status } : {},
2016
2099
  ...args.taskId !== void 0 ? { taskId: args.taskId } : {},
2017
- ...args.projectId !== void 0 ? { projectId: args.projectId } : {},
2100
+ ...issueQueryProjectId !== void 0 ? { projectId: issueQueryProjectId } : {},
2018
2101
  ...args.page !== void 0 ? { page: args.page } : {},
2019
2102
  ...args.limit !== void 0 ? { limit: args.limit } : {}
2020
2103
  })
@@ -2236,18 +2319,19 @@ var PAGE_DEFAULT = 20;
2236
2319
  var PAGE_MAX = 500;
2237
2320
  function createTaskCommand() {
2238
2321
  const task = new Command2("task").description("Task management \u2014 create, advance, approve, pause, resume, cancel, reopen, query");
2239
- withCommonOpts(task.command("list"), "table").option("--status <s>", "filter by status").option("--track <t>", "filter by track").option("--project <key-or-id>", "filter by projectId (key or id)").option("--page <n>", "page number (default 1)", "1").option("--limit <n>", `page size (default ${PAGE_DEFAULT}, max ${PAGE_MAX})`).option("--all", `show all (limit ${PAGE_MAX})`).option("--sort <s>", "sort: progress|createdAt|updatedAt (default progress)").description("List tasks (summary projection: no dagInstance/history payloads)").action(async (opts) => {
2322
+ withCommonOpts(task.command("list"), "table").option("--status <s>", "filter by status").option("--track <t>", "filter by track").option("--project <key|id>", "filter by projectId (key|id)").option("--page <n>", "page number (default 1)", "1").option("--limit <n>", `page size (default ${PAGE_DEFAULT}, max ${PAGE_MAX})`).option("--all", `show all (limit ${PAGE_MAX})`).option("--sort <s>", "sort: progress|createdAt|updatedAt (default progress)").description("List tasks (summary projection: no dagInstance/history payloads)").action(async (opts) => {
2240
2323
  const client = createClient(opts.url);
2241
2324
  const filters = {};
2242
2325
  if (opts.status) filters.status = opts.status;
2243
2326
  if (opts.track) filters.track = opts.track;
2244
- if (opts.project) {
2245
- const r = await resolveProjectId(client, opts.project);
2246
- if (!r.success) {
2247
- renderResult(opts.format, r);
2327
+ if (opts.project !== void 0 && opts.project.trim().length > 0) {
2328
+ const pr = await resolveScopedProject(client, opts.project, "explicit-only");
2329
+ if (!pr.success) {
2330
+ renderResult(opts.format, pr);
2248
2331
  return;
2249
2332
  }
2250
- filters.projectId = r.data;
2333
+ const pid = pr.data.projectId;
2334
+ if (pid !== void 0) filters.projectId = pid;
2251
2335
  }
2252
2336
  if (opts.sort) {
2253
2337
  const r = parseEnum(opts.sort, z5.enum(["progress", "createdAt", "updatedAt"]), "sort");
@@ -2303,7 +2387,7 @@ function createTaskCommand() {
2303
2387
  const result = await handleQueryState(client, taskId);
2304
2388
  renderResult(opts.format, result, { fields: result.success ? taskFields(result.data) : [] });
2305
2389
  });
2306
- 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-or-id>", "projectId (key or id; defaults to workspace defaultProject then template projectId)").action(async (opts) => {
2390
+ 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) => {
2307
2391
  const client = createClient(opts.url);
2308
2392
  let type;
2309
2393
  if (opts.type !== void 0) {
@@ -2318,21 +2402,12 @@ function createTaskCommand() {
2318
2402
  if (opts.skip !== void 0 && opts.skip.length > 0) {
2319
2403
  skipNodes = [...new Set(opts.skip.flatMap((s) => s.split(",")).map((s) => s.trim()).filter((s) => s.length > 0))];
2320
2404
  }
2321
- let projectId;
2322
- if (opts.project) {
2323
- const r = await resolveProjectId(client, opts.project);
2324
- if (!r.success) {
2325
- renderResult("json", r);
2326
- return;
2327
- }
2328
- projectId = r.data;
2329
- } else {
2330
- const wsDefaultProject = readWorkspaceConfig()?.defaultProject;
2331
- if (wsDefaultProject) {
2332
- const r = await resolveProjectId(client, wsDefaultProject);
2333
- if (r.success) projectId = r.data;
2334
- }
2405
+ const projectR = await resolveScopedProject(client, opts.project, "ws-default", { commandLabel: "siming task create" });
2406
+ if (!projectR.success) {
2407
+ renderResult("json", projectR);
2408
+ return;
2335
2409
  }
2410
+ const projectId = projectR.data.projectId;
2336
2411
  let templateRef = opts.template;
2337
2412
  if (!/^[0-9a-f]{24}$/.test(templateRef)) {
2338
2413
  const listR = await handleListTemplates(client, projectId);
@@ -2351,20 +2426,9 @@ function createTaskCommand() {
2351
2426
  ...skipNodes !== void 0 && skipNodes.length > 0 ? { skipNodes } : {},
2352
2427
  ...projectId ? { projectId } : {}
2353
2428
  });
2354
- if (!result.success && !opts.project) {
2355
- const bizCode = result.error.bizCode;
2356
- if (bizCode === "PROJECT_NOT_FOUND") {
2357
- renderResult("json", { ...result, error: { ...result.error, hint: "workspace defaultProject \u6307\u5411\u7684\u9879\u76EE\u4E0D\u5B58\u5728\u2014\u2014run `siming config unset defaultProject` or `siming config set defaultProject <key|id>`" } });
2358
- return;
2359
- }
2360
- if (bizCode === "PROJECT_ARCHIVED") {
2361
- renderResult("json", { ...result, error: { ...result.error, hint: "workspace defaultProject \u6307\u5411\u7684\u9879\u76EE\u5DF2\u5F52\u6863\u2014\u2014run `siming project list --status active` to pick an active project" } });
2362
- return;
2363
- }
2364
- if (bizCode === "TEMPLATE_PROJECT_MISMATCH") {
2365
- renderResult("json", { ...result, error: { ...result.error, hint: "template belongs to another project\u2014\u2014pass --project <key|id> of the template's project" } });
2366
- return;
2367
- }
2429
+ if (!result.success && !opts.project && result.error.bizCode === "TEMPLATE_PROJECT_MISMATCH") {
2430
+ renderResult("json", { ...result, error: { ...result.error, hint: "template belongs to another project\u2014\u2014pass --project <key|id> of the template's project" } });
2431
+ return;
2368
2432
  }
2369
2433
  renderResult("json", result);
2370
2434
  });
@@ -3214,9 +3278,18 @@ async function handleScaffoldSkill(client, input) {
3214
3278
  // src/commands/skill/command.ts
3215
3279
  function createSkillCommand() {
3216
3280
  const skill = new Command3("skill").description("Skill management \u2014 global/project-scoped skills");
3217
- withCommonOpts(skill.command("list"), "table").option("--project <id>", "filter by projectId").description("List skills").action(async (opts) => {
3281
+ withCommonOpts(skill.command("list"), "table").option("--project <key|id>", "filter by projectId (key|id)").description("List skills").action(async (opts) => {
3218
3282
  const client = createClient(opts.url);
3219
- const result = await handleListSkills(client, opts.project);
3283
+ let projectId;
3284
+ if (opts.project !== void 0 && opts.project.trim().length > 0) {
3285
+ const pr = await resolveScopedProject(client, opts.project, "explicit-only");
3286
+ if (!pr.success) {
3287
+ renderResult(opts.format, pr);
3288
+ return;
3289
+ }
3290
+ projectId = pr.data.projectId;
3291
+ }
3292
+ const result = await handleListSkills(client, projectId);
3220
3293
  renderResult(opts.format, result, {
3221
3294
  columns: [
3222
3295
  { key: "name", header: "Name" },
@@ -3228,7 +3301,7 @@ function createSkillCommand() {
3228
3301
  ]
3229
3302
  });
3230
3303
  });
3231
- withCommonOpts(skill.command("show <name>"), "fancy").description("Show skill details").option("--scope <scope>", "global|project (asset addressing; defaults to global)").option("--project-id <hex>", "projectId (required when scope=project)").action(async (name, opts) => {
3304
+ withCommonOpts(skill.command("show <name>"), "fancy").description("Show skill details").option("--scope <scope>", "global|project (asset addressing; defaults to global)").option("--project-id <key|id>", "projectId (scope=project; falls back to workspace/instance default project)").action(async (name, opts) => {
3232
3305
  const client = createClient(opts.url);
3233
3306
  let scope;
3234
3307
  if (opts.scope !== void 0) {
@@ -3239,13 +3312,23 @@ function createSkillCommand() {
3239
3312
  }
3240
3313
  scope = scopeR.data;
3241
3314
  }
3315
+ let projectId;
3316
+ const explicitProject = opts.projectId !== void 0 && opts.projectId.trim().length > 0 ? opts.projectId : void 0;
3317
+ if (explicitProject !== void 0 || scope === "project") {
3318
+ const pr = await resolveScopedProject(client, explicitProject, "instance-default", { commandLabel: "siming skill show" });
3319
+ if (!pr.success) {
3320
+ renderResult(opts.format, pr);
3321
+ return;
3322
+ }
3323
+ projectId = pr.data.projectId;
3324
+ }
3242
3325
  const result = await handleGetSkill(client, name, {
3243
3326
  ...scope !== void 0 ? { scope } : {},
3244
- ...opts.projectId !== void 0 ? { projectId: opts.projectId } : {}
3327
+ ...projectId !== void 0 ? { projectId } : {}
3245
3328
  });
3246
3329
  renderResult(opts.format, result, { fields: result.success ? skillFields(result.data) : [] });
3247
3330
  });
3248
- skill.command("create").description("Create a skill (scope required)").option("--url <url>", "server base URL").requiredOption("--name <name>", "skill name (kebab-case)").requiredOption("--description <text>", "skill description").requiredOption("--content <text>", "skill content (prompt body)").requiredOption("--category <cat>", "process|domain|tooling").requiredOption("--scope <scope>", "global|project").option("--ref <path@file>", "reference doc: <relative path>@<local file> (repeatable)", collectArgs, []).option("--project-id <hex>", "projectId (required when scope=project)").action(async (opts) => {
3331
+ skill.command("create").description("Create a skill (scope required)").option("--url <url>", "server base URL").requiredOption("--name <name>", "skill name (kebab-case)").requiredOption("--description <text>", "skill description").requiredOption("--content <text>", "skill content (prompt body)").requiredOption("--category <cat>", "process|domain|tooling").requiredOption("--scope <scope>", "global|project").option("--ref <path@file>", "reference doc: <relative path>@<local file> (repeatable)", collectArgs, []).option("--project-id <key|id>", "projectId (scope=project; falls back to workspace/instance default project)").action(async (opts) => {
3249
3332
  const categoryR = parseEnum(opts.category, SkillCategorySchema, "category");
3250
3333
  if (!categoryR.success) {
3251
3334
  renderResult("json", categoryR);
@@ -3262,6 +3345,16 @@ function createSkillCommand() {
3262
3345
  return;
3263
3346
  }
3264
3347
  const client = createClient(opts.url);
3348
+ let projectId;
3349
+ const explicitProject = opts.projectId !== void 0 && opts.projectId.trim().length > 0 ? opts.projectId : void 0;
3350
+ if (explicitProject !== void 0 || scopeR.data === "project") {
3351
+ const pr = await resolveScopedProject(client, explicitProject, "instance-default", { commandLabel: "siming skill create" });
3352
+ if (!pr.success) {
3353
+ renderResult("json", pr);
3354
+ return;
3355
+ }
3356
+ projectId = pr.data.projectId;
3357
+ }
3265
3358
  const input = {
3266
3359
  name: opts.name,
3267
3360
  description: opts.description,
@@ -3270,12 +3363,12 @@ function createSkillCommand() {
3270
3363
  scope: scopeR.data,
3271
3364
  version: "1.0.0",
3272
3365
  ...refsR.data.length > 0 ? { references: refsR.data } : {},
3273
- ...opts.projectId ? { projectId: opts.projectId } : {}
3366
+ ...projectId !== void 0 ? { projectId } : {}
3274
3367
  };
3275
3368
  const result = await handleCreateSkill(client, input);
3276
3369
  renderResult("json", result);
3277
3370
  });
3278
- skill.command("update <name>").description("Update a skill (partial; references untouched unless --ref/--clear-refs given)").option("--url <url>", "server base URL").option("--description <text>", "new description").option("--content <text>", "new content").option("--new-version <v>", "new version (note: --version is reserved for the program version)").option("--scope <scope>", "global|project (asset addressing)").option("--ref <path@file>", "replace all reference docs: <relative path>@<local file> (repeatable)", collectArgs, []).option("--clear-refs", "remove all reference docs (mutually exclusive with --ref)").option("--project-id <hex>", "projectId (required when scope=project)").action(async (name, opts) => {
3371
+ skill.command("update <name>").description("Update a skill (partial; references untouched unless --ref/--clear-refs given)").option("--url <url>", "server base URL").option("--description <text>", "new description").option("--content <text>", "new content").option("--new-version <v>", "new version (note: --version is reserved for the program version)").option("--scope <scope>", "global|project (asset addressing)").option("--ref <path@file>", "replace all reference docs: <relative path>@<local file> (repeatable)", collectArgs, []).option("--clear-refs", "remove all reference docs (mutually exclusive with --ref)").option("--project-id <key|id>", "projectId (scope=project; falls back to workspace/instance default project)").action(async (name, opts) => {
3279
3372
  const client = createClient(opts.url);
3280
3373
  let scope;
3281
3374
  if (opts.scope !== void 0) {
@@ -3305,21 +3398,31 @@ function createSkillCommand() {
3305
3398
  }
3306
3399
  references = refsR.data;
3307
3400
  }
3401
+ let projectId;
3402
+ const explicitProject = opts.projectId !== void 0 && opts.projectId.trim().length > 0 ? opts.projectId : void 0;
3403
+ if (explicitProject !== void 0 || scope === "project") {
3404
+ const pr = await resolveScopedProject(client, explicitProject, "instance-default", { commandLabel: "siming skill update" });
3405
+ if (!pr.success) {
3406
+ renderResult("json", pr);
3407
+ return;
3408
+ }
3409
+ projectId = pr.data.projectId;
3410
+ }
3308
3411
  const patch = {
3309
3412
  ...opts.description !== void 0 ? { description: opts.description } : {},
3310
3413
  ...opts.content !== void 0 ? { content: opts.content } : {},
3311
3414
  ...opts.newVersion !== void 0 ? { version: opts.newVersion } : {},
3312
3415
  ...scope !== void 0 ? { scope } : {},
3313
3416
  ...references !== void 0 ? { references } : {},
3314
- ...opts.projectId !== void 0 ? { projectId: opts.projectId } : {}
3417
+ ...projectId !== void 0 ? { projectId } : {}
3315
3418
  };
3316
3419
  const result = await handleUpdateSkill(client, name, patch, {
3317
3420
  ...scope !== void 0 ? { scope } : {},
3318
- ...opts.projectId !== void 0 ? { projectId: opts.projectId } : {}
3421
+ ...projectId !== void 0 ? { projectId } : {}
3319
3422
  });
3320
3423
  renderResult("json", result);
3321
3424
  });
3322
- skill.command("copy <name>").description("Copy a skill to a new name/scope").option("--url <url>", "server base URL").requiredOption("--new-name <name>", "copy name").requiredOption("--new-scope <scope>", "global|project").option("--target-project-id <hex>", "target projectId (required when newScope=project)").option("--scope <scope>", "source asset addressing: global|project (defaults to global)").option("--source-project-id <hex>", "source projectId (required when scope=project)").action(async (name, opts) => {
3425
+ skill.command("copy <name>").description("Copy a skill to a new name/scope").option("--url <url>", "server base URL").requiredOption("--new-name <name>", "copy name").requiredOption("--new-scope <scope>", "global|project").option("--target-project-id <key|id>", "target projectId (newScope=project; falls back to workspace/instance default project)").option("--scope <scope>", "source asset addressing: global|project (defaults to global)").option("--source-project-id <key|id>", "source projectId (scope=project; falls back to workspace/instance default project)").action(async (name, opts) => {
3323
3426
  const scopeR = parseEnum(opts.newScope, SkillScopeSchema, "new-scope");
3324
3427
  if (!scopeR.success) {
3325
3428
  renderResult("json", scopeR);
@@ -3335,22 +3438,42 @@ function createSkillCommand() {
3335
3438
  srcScope = srcR.data;
3336
3439
  }
3337
3440
  const client = createClient(opts.url);
3441
+ let targetProjectId;
3442
+ const explicitTarget = opts.targetProjectId !== void 0 && opts.targetProjectId.trim().length > 0 ? opts.targetProjectId : void 0;
3443
+ if (explicitTarget !== void 0 || scopeR.data === "project") {
3444
+ const pr = await resolveScopedProject(client, explicitTarget, "instance-default", { commandLabel: "siming skill copy (target)" });
3445
+ if (!pr.success) {
3446
+ renderResult("json", pr);
3447
+ return;
3448
+ }
3449
+ targetProjectId = pr.data.projectId;
3450
+ }
3451
+ let sourceProjectId;
3452
+ const explicitSource = opts.sourceProjectId !== void 0 && opts.sourceProjectId.trim().length > 0 ? opts.sourceProjectId : void 0;
3453
+ if (explicitSource !== void 0 || srcScope === "project") {
3454
+ const pr = await resolveScopedProject(client, explicitSource, "instance-default", { commandLabel: "siming skill copy (source)" });
3455
+ if (!pr.success) {
3456
+ renderResult("json", pr);
3457
+ return;
3458
+ }
3459
+ sourceProjectId = pr.data.projectId;
3460
+ }
3338
3461
  const result = await handleCopySkill(
3339
3462
  client,
3340
3463
  name,
3341
3464
  {
3342
3465
  newName: opts.newName,
3343
3466
  newScope: scopeR.data,
3344
- ...opts.targetProjectId ? { targetProjectId: opts.targetProjectId } : {}
3467
+ ...targetProjectId !== void 0 ? { targetProjectId } : {}
3345
3468
  },
3346
3469
  {
3347
3470
  ...srcScope !== void 0 ? { scope: srcScope } : {},
3348
- ...opts.sourceProjectId !== void 0 ? { projectId: opts.sourceProjectId } : {}
3471
+ ...sourceProjectId !== void 0 ? { projectId: sourceProjectId } : {}
3349
3472
  }
3350
3473
  );
3351
3474
  renderResult("json", result);
3352
3475
  });
3353
- withCommonOpts(skill.command("delete <name>"), "fancy").description("Delete a skill").option("--scope <scope>", "global|project (asset addressing; defaults to global)").option("--project-id <hex>", "projectId (required when scope=project)").action(async (name, opts) => {
3476
+ withCommonOpts(skill.command("delete <name>"), "fancy").description("Delete a skill").option("--scope <scope>", "global|project (asset addressing; defaults to global)").option("--project-id <key|id>", "projectId (scope=project; falls back to workspace/instance default project)").action(async (name, opts) => {
3354
3477
  const client = createClient(opts.url);
3355
3478
  let scope;
3356
3479
  if (opts.scope !== void 0) {
@@ -3361,13 +3484,23 @@ function createSkillCommand() {
3361
3484
  }
3362
3485
  scope = scopeR.data;
3363
3486
  }
3487
+ let projectId;
3488
+ const explicitProject = opts.projectId !== void 0 && opts.projectId.trim().length > 0 ? opts.projectId : void 0;
3489
+ if (explicitProject !== void 0 || scope === "project") {
3490
+ const pr = await resolveScopedProject(client, explicitProject, "instance-default", { commandLabel: "siming skill delete" });
3491
+ if (!pr.success) {
3492
+ renderResult("json", pr);
3493
+ return;
3494
+ }
3495
+ projectId = pr.data.projectId;
3496
+ }
3364
3497
  const result = await handleDeleteSkill(client, name, {
3365
3498
  ...scope !== void 0 ? { scope } : {},
3366
- ...opts.projectId !== void 0 ? { projectId: opts.projectId } : {}
3499
+ ...projectId !== void 0 ? { projectId } : {}
3367
3500
  });
3368
3501
  renderResult(opts.format, result, { successMessage: `deleted skill '${name}'` });
3369
3502
  });
3370
- skill.command("enabled <name> <on|off>").description("Enable/disable a skill (asset addressing; defaults to global)").option("--url <url>", "server base URL").option("--format <fmt>", "output format: fancy|table|json", "fancy").option("--scope <scope>", "global|project (asset addressing; defaults to global)").option("--project-id <hex>", "projectId (required when scope=project)").action(async (name, onOff, opts) => {
3503
+ skill.command("enabled <name> <on|off>").description("Enable/disable a skill (asset addressing; defaults to global)").option("--url <url>", "server base URL").option("--format <fmt>", "output format: fancy|table|json", "fancy").option("--scope <scope>", "global|project (asset addressing; defaults to global)").option("--project-id <key|id>", "projectId (scope=project; falls back to workspace/instance default project)").action(async (name, onOff, opts) => {
3371
3504
  const enabledR = parseOnOff(onOff);
3372
3505
  if (!enabledR.success) {
3373
3506
  renderResult(opts.format, enabledR);
@@ -3383,9 +3516,19 @@ function createSkillCommand() {
3383
3516
  }
3384
3517
  scope = scopeR.data;
3385
3518
  }
3519
+ let projectId;
3520
+ const explicitProject = opts.projectId !== void 0 && opts.projectId.trim().length > 0 ? opts.projectId : void 0;
3521
+ if (explicitProject !== void 0 || scope === "project") {
3522
+ const pr = await resolveScopedProject(client, explicitProject, "instance-default", { commandLabel: "siming skill enabled" });
3523
+ if (!pr.success) {
3524
+ renderResult(opts.format, pr);
3525
+ return;
3526
+ }
3527
+ projectId = pr.data.projectId;
3528
+ }
3386
3529
  const result = await handleSetSkillEnabled(client, name, enabledR.data, {
3387
3530
  ...scope !== void 0 ? { scope } : {},
3388
- ...opts.projectId !== void 0 ? { projectId: opts.projectId } : {}
3531
+ ...projectId !== void 0 ? { projectId } : {}
3389
3532
  });
3390
3533
  renderResult(opts.format, result, {
3391
3534
  successMessage: `skill '${name}' ${enabledR.data ? "enabled" : "disabled"}`
@@ -3393,16 +3536,17 @@ function createSkillCommand() {
3393
3536
  });
3394
3537
  skill.command("scaffold <template>").description(
3395
3538
  "Scaffold an official project-scoped skill from the packaged skeleton (task-create entry; same-name conflict refused by default)"
3396
- ).option("--url <url>", "server base URL").requiredOption("--project <key-or-id>", "target project (key or 24-hex id)").option("--overwrite", "explicitly replace an existing same-name project asset (version bumps monotonically; enabled state untouched)").option("--format <fmt>", "output format: fancy|table|json", "fancy").action(async (template, opts) => {
3539
+ ).option("--url <url>", "server base URL").option("--project <key|id>", "target project (key|id; falls back to workspace/instance default project)").option("--overwrite", "explicitly replace an existing same-name project asset (version bumps monotonically; enabled state untouched)").option("--format <fmt>", "output format: fancy|table|json", "fancy").action(async (template, opts) => {
3397
3540
  const client = createClient(opts.url);
3398
- const projectR = await resolveProjectId(client, opts.project);
3541
+ const projectR = await resolveScopedProject(client, opts.project, "instance-default", { commandLabel: "siming skill scaffold" });
3399
3542
  if (!projectR.success) {
3400
3543
  renderResult(opts.format, projectR);
3401
3544
  return;
3402
3545
  }
3403
3546
  const result = await handleScaffoldSkill(client, {
3404
3547
  template,
3405
- projectId: projectR.data,
3548
+ projectId: projectR.data.projectId,
3549
+ // instance-default 成功必含 id
3406
3550
  ...opts.overwrite === true ? { overwrite: true } : {}
3407
3551
  });
3408
3552
  const renderOptions = result.success ? {
@@ -3493,9 +3637,18 @@ async function handleDeleteAgent(client, name, query = {}) {
3493
3637
  // src/commands/agent/command.ts
3494
3638
  function createAgentCommand() {
3495
3639
  const agent = new Command4("agent").description("Agent management \u2014 subagent definitions (global/project scope)");
3496
- withCommonOpts(agent.command("list"), "table").option("--project <id>", "filter by projectId").description("List agents").action(async (opts) => {
3640
+ withCommonOpts(agent.command("list"), "table").option("--project <key|id>", "filter by projectId (key|id)").description("List agents").action(async (opts) => {
3497
3641
  const client = createClient(opts.url);
3498
- const result = await handleListAgents(client, opts.project);
3642
+ let projectId;
3643
+ if (opts.project !== void 0 && opts.project.trim().length > 0) {
3644
+ const pr = await resolveScopedProject(client, opts.project, "explicit-only");
3645
+ if (!pr.success) {
3646
+ renderResult(opts.format, pr);
3647
+ return;
3648
+ }
3649
+ projectId = pr.data.projectId;
3650
+ }
3651
+ const result = await handleListAgents(client, projectId);
3499
3652
  renderResult(opts.format, result, {
3500
3653
  columns: [
3501
3654
  { key: "name", header: "Name" },
@@ -3513,7 +3666,7 @@ function createAgentCommand() {
3513
3666
  const result = await handleGetAgent(client, name);
3514
3667
  renderResult(opts.format, result, { fields: result.success ? agentFields(result.data) : [] });
3515
3668
  });
3516
- agent.command("create").description("Create an agent (scope + system-prompt + model required)").option("--url <url>", "server base URL").requiredOption("--name <name>", "agent name").requiredOption("--description <text>", "agent description").requiredOption("--system-prompt <text>", "system prompt").requiredOption("--model <code>", "model siming-code (kebab-case)").requiredOption("--scope <scope>", "global|project").option("--function <function>", "agent function: reviewer|executor (default executor)").option("--bound-skill <name>", "bound skill name (repeatable)", collectArgs, []).option("--tool <name>", "tool name (repeatable)", collectArgs, []).option("--permission <name>", "permission name (repeatable)", collectArgs, []).option("--ref <path@file>", "reference doc: <relative path>@<local file> (repeatable)", collectArgs, []).option("--project-id <hex>", "projectId (required when scope=project)").action(async (opts) => {
3669
+ agent.command("create").description("Create an agent (scope + system-prompt + model required)").option("--url <url>", "server base URL").requiredOption("--name <name>", "agent name").requiredOption("--description <text>", "agent description").requiredOption("--system-prompt <text>", "system prompt").requiredOption("--model <code>", "model siming-code (kebab-case)").requiredOption("--scope <scope>", "global|project").option("--function <function>", "agent function: reviewer|executor (default executor)").option("--bound-skill <name>", "bound skill name (repeatable)", collectArgs, []).option("--tool <name>", "tool name (repeatable)", collectArgs, []).option("--permission <name>", "permission name (repeatable)", collectArgs, []).option("--ref <path@file>", "reference doc: <relative path>@<local file> (repeatable)", collectArgs, []).option("--project-id <key|id>", "projectId (scope=project; falls back to workspace/instance default project)").action(async (opts) => {
3517
3670
  const scopeR = parseEnum(opts.scope, AgentScopeSchema, "scope");
3518
3671
  if (!scopeR.success) {
3519
3672
  renderResult("json", scopeR);
@@ -3534,6 +3687,16 @@ function createAgentCommand() {
3534
3687
  return;
3535
3688
  }
3536
3689
  const client = createClient(opts.url);
3690
+ let projectId;
3691
+ const explicitProject = opts.projectId !== void 0 && opts.projectId.trim().length > 0 ? opts.projectId : void 0;
3692
+ if (explicitProject !== void 0 || scopeR.data === "project") {
3693
+ const pr = await resolveScopedProject(client, explicitProject, "instance-default", { commandLabel: "siming agent create" });
3694
+ if (!pr.success) {
3695
+ renderResult("json", pr);
3696
+ return;
3697
+ }
3698
+ projectId = pr.data.projectId;
3699
+ }
3537
3700
  const input = {
3538
3701
  name: opts.name,
3539
3702
  description: opts.description,
@@ -3547,12 +3710,12 @@ function createAgentCommand() {
3547
3710
  tools: opts.tool,
3548
3711
  permissions: opts.permission,
3549
3712
  ...refsR.data.length > 0 ? { references: refsR.data } : {},
3550
- ...opts.projectId ? { projectId: opts.projectId } : {}
3713
+ ...projectId !== void 0 ? { projectId } : {}
3551
3714
  };
3552
3715
  const result = await handleCreateAgent(client, input);
3553
3716
  renderResult("json", result);
3554
3717
  });
3555
- agent.command("update <name>").description("Update an agent (partial)").option("--url <url>", "server base URL").option("--description <text>", "new description").option("--system-prompt <text>", "new system prompt").option("--model <code>", "new model siming-code").option("--scope <scope>", "global|project (asset addressing)").option("--function <function>", "new agent function: reviewer|executor").option("--bound-skill <name>", "replace bound skills (repeatable)", collectArgs, []).option("--tool <name>", "replace tools (repeatable)", collectArgs, []).option("--permission <name>", "replace permissions (repeatable)", collectArgs, []).option("--ref <path@file>", "replace all reference docs: <relative path>@<local file> (repeatable)", collectArgs, []).option("--clear-refs", "remove all reference docs (mutually exclusive with --ref)").option("--project-id <hex>", "projectId (required when scope=project)").action(async (name, opts) => {
3718
+ agent.command("update <name>").description("Update an agent (partial)").option("--url <url>", "server base URL").option("--description <text>", "new description").option("--system-prompt <text>", "new system prompt").option("--model <code>", "new model siming-code").option("--scope <scope>", "global|project (asset addressing)").option("--function <function>", "new agent function: reviewer|executor").option("--bound-skill <name>", "replace bound skills (repeatable)", collectArgs, []).option("--tool <name>", "replace tools (repeatable)", collectArgs, []).option("--permission <name>", "replace permissions (repeatable)", collectArgs, []).option("--ref <path@file>", "replace all reference docs: <relative path>@<local file> (repeatable)", collectArgs, []).option("--clear-refs", "remove all reference docs (mutually exclusive with --ref)").option("--project-id <key|id>", "projectId (scope=project; falls back to workspace/instance default project)").action(async (name, opts) => {
3556
3719
  const client = createClient(opts.url);
3557
3720
  let scope;
3558
3721
  if (opts.scope !== void 0) {
@@ -3591,6 +3754,16 @@ function createAgentCommand() {
3591
3754
  }
3592
3755
  references = refsR.data;
3593
3756
  }
3757
+ let projectId;
3758
+ const explicitProject = opts.projectId !== void 0 && opts.projectId.trim().length > 0 ? opts.projectId : void 0;
3759
+ if (explicitProject !== void 0 || scope === "project") {
3760
+ const pr = await resolveScopedProject(client, explicitProject, "instance-default", { commandLabel: "siming agent update" });
3761
+ if (!pr.success) {
3762
+ renderResult("json", pr);
3763
+ return;
3764
+ }
3765
+ projectId = pr.data.projectId;
3766
+ }
3594
3767
  const patch = {
3595
3768
  ...opts.description !== void 0 ? { description: opts.description } : {},
3596
3769
  ...opts.systemPrompt !== void 0 ? { systemPrompt: opts.systemPrompt } : {},
@@ -3601,15 +3774,15 @@ function createAgentCommand() {
3601
3774
  ...opts.tool.length > 0 ? { tools: opts.tool } : {},
3602
3775
  ...opts.permission.length > 0 ? { permissions: opts.permission } : {},
3603
3776
  ...references !== void 0 ? { references } : {},
3604
- ...opts.projectId !== void 0 ? { projectId: opts.projectId } : {}
3777
+ ...projectId !== void 0 ? { projectId } : {}
3605
3778
  };
3606
3779
  const result = await handleUpdateAgent(client, name, patch, {
3607
3780
  ...scope !== void 0 ? { scope } : {},
3608
- ...opts.projectId !== void 0 ? { projectId: opts.projectId } : {}
3781
+ ...projectId !== void 0 ? { projectId } : {}
3609
3782
  });
3610
3783
  renderResult("json", result);
3611
3784
  });
3612
- agent.command("copy <name>").description("Copy an agent to a new name/scope").option("--url <url>", "server base URL").requiredOption("--new-name <name>", "copy name").requiredOption("--new-scope <scope>", "global|project").option("--target-project-id <hex>", "target projectId (required when newScope=project)").option("--scope <scope>", "source asset addressing: global|project (defaults to global)").option("--source-project-id <hex>", "source projectId (required when scope=project)").action(async (name, opts) => {
3785
+ agent.command("copy <name>").description("Copy an agent to a new name/scope").option("--url <url>", "server base URL").requiredOption("--new-name <name>", "copy name").requiredOption("--new-scope <scope>", "global|project").option("--target-project-id <key|id>", "target projectId (newScope=project; falls back to workspace/instance default project)").option("--scope <scope>", "source asset addressing: global|project (defaults to global)").option("--source-project-id <key|id>", "source projectId (scope=project; falls back to workspace/instance default project)").action(async (name, opts) => {
3613
3786
  const scopeR = parseEnum(opts.newScope, AgentScopeSchema, "new-scope");
3614
3787
  if (!scopeR.success) {
3615
3788
  renderResult("json", scopeR);
@@ -3625,22 +3798,42 @@ function createAgentCommand() {
3625
3798
  srcScope = srcR.data;
3626
3799
  }
3627
3800
  const client = createClient(opts.url);
3801
+ let targetProjectId;
3802
+ const explicitTarget = opts.targetProjectId !== void 0 && opts.targetProjectId.trim().length > 0 ? opts.targetProjectId : void 0;
3803
+ if (explicitTarget !== void 0 || scopeR.data === "project") {
3804
+ const pr = await resolveScopedProject(client, explicitTarget, "instance-default", { commandLabel: "siming agent copy (target)" });
3805
+ if (!pr.success) {
3806
+ renderResult("json", pr);
3807
+ return;
3808
+ }
3809
+ targetProjectId = pr.data.projectId;
3810
+ }
3811
+ let sourceProjectId;
3812
+ const explicitSource = opts.sourceProjectId !== void 0 && opts.sourceProjectId.trim().length > 0 ? opts.sourceProjectId : void 0;
3813
+ if (explicitSource !== void 0 || srcScope === "project") {
3814
+ const pr = await resolveScopedProject(client, explicitSource, "instance-default", { commandLabel: "siming agent copy (source)" });
3815
+ if (!pr.success) {
3816
+ renderResult("json", pr);
3817
+ return;
3818
+ }
3819
+ sourceProjectId = pr.data.projectId;
3820
+ }
3628
3821
  const result = await handleCopyAgent(
3629
3822
  client,
3630
3823
  name,
3631
3824
  {
3632
3825
  newName: opts.newName,
3633
3826
  newScope: scopeR.data,
3634
- ...opts.targetProjectId ? { targetProjectId: opts.targetProjectId } : {}
3827
+ ...targetProjectId !== void 0 ? { targetProjectId } : {}
3635
3828
  },
3636
3829
  {
3637
3830
  ...srcScope !== void 0 ? { scope: srcScope } : {},
3638
- ...opts.sourceProjectId !== void 0 ? { projectId: opts.sourceProjectId } : {}
3831
+ ...sourceProjectId !== void 0 ? { projectId: sourceProjectId } : {}
3639
3832
  }
3640
3833
  );
3641
3834
  renderResult("json", result);
3642
3835
  });
3643
- withCommonOpts(agent.command("delete <name>"), "fancy").description("Delete an agent").option("--scope <scope>", "global|project (asset addressing; defaults to global)").option("--project-id <hex>", "projectId (required when scope=project)").action(async (name, opts) => {
3836
+ withCommonOpts(agent.command("delete <name>"), "fancy").description("Delete an agent").option("--scope <scope>", "global|project (asset addressing; defaults to global)").option("--project-id <key|id>", "projectId (scope=project; falls back to workspace/instance default project)").action(async (name, opts) => {
3644
3837
  const client = createClient(opts.url);
3645
3838
  let scope;
3646
3839
  if (opts.scope !== void 0) {
@@ -3651,9 +3844,19 @@ function createAgentCommand() {
3651
3844
  }
3652
3845
  scope = scopeR.data;
3653
3846
  }
3847
+ let projectId;
3848
+ const explicitProject = opts.projectId !== void 0 && opts.projectId.trim().length > 0 ? opts.projectId : void 0;
3849
+ if (explicitProject !== void 0 || scope === "project") {
3850
+ const pr = await resolveScopedProject(client, explicitProject, "instance-default", { commandLabel: "siming agent delete" });
3851
+ if (!pr.success) {
3852
+ renderResult(opts.format, pr);
3853
+ return;
3854
+ }
3855
+ projectId = pr.data.projectId;
3856
+ }
3654
3857
  const result = await handleDeleteAgent(client, name, {
3655
3858
  ...scope !== void 0 ? { scope } : {},
3656
- ...opts.projectId !== void 0 ? { projectId: opts.projectId } : {}
3859
+ ...projectId !== void 0 ? { projectId } : {}
3657
3860
  });
3658
3861
  renderResult(opts.format, result, { successMessage: `deleted agent '${name}'` });
3659
3862
  });
@@ -3684,23 +3887,13 @@ function createDagCommand() {
3684
3887
  const tpl = dag.command("template").description("DAG template management");
3685
3888
  withCommonOpts(tpl.command("list"), "table").option("--project <key|id>", "filter by project (key or id; defaults to workspace defaultProject)").description("List DAG templates (summary projection: node labels only, no prompts \u2014 use `show` for full detail)").action(async (opts) => {
3686
3889
  const client = createClient(opts.url);
3687
- const projectOpt = opts.project ?? readWorkspaceConfig()?.defaultProject;
3688
- let projectId;
3689
- if (projectOpt !== void 0) {
3690
- const r = await resolveProjectId(client, projectOpt);
3691
- if (!r.success) {
3692
- if (opts.project === void 0) {
3693
- renderResult(opts.format, fail({
3694
- ...r.error,
3695
- hint: `workspace defaultProject "${projectOpt}" \u89E3\u6790\u5931\u8D25\u2014\u2014siming config unset defaultProject \u540E\u91CD\u8BD5\uFF0C\u6216\u663E\u5F0F --project <key|id>`
3696
- }));
3697
- } else {
3698
- renderResult(opts.format, r);
3699
- }
3700
- return;
3701
- }
3702
- projectId = r.data;
3890
+ const explicitProject = opts.project !== void 0 && opts.project.trim().length > 0 ? opts.project : void 0;
3891
+ const pr = await resolveScopedProject(client, explicitProject, "ws-default", { commandLabel: "siming dag template list" });
3892
+ if (!pr.success) {
3893
+ renderResult(opts.format, pr);
3894
+ return;
3703
3895
  }
3896
+ const projectId = pr.data.projectId;
3704
3897
  const result = await handleListTemplates(client, projectId);
3705
3898
  if (!result.success) {
3706
3899
  renderResult(opts.format, result);
@@ -3728,15 +3921,13 @@ function createDagCommand() {
3728
3921
  const client = createClient(opts.url);
3729
3922
  let projectId;
3730
3923
  if (!/^[a-f0-9]{24}$/.test(templateRef)) {
3731
- const projectOpt = opts.project ?? readWorkspaceConfig()?.defaultProject;
3732
- if (projectOpt !== void 0) {
3733
- const r = await resolveProjectId(client, projectOpt);
3734
- if (!r.success) {
3735
- renderResult("json", r);
3736
- return;
3737
- }
3738
- projectId = r.data;
3924
+ const explicitProject = opts.project !== void 0 && opts.project.trim().length > 0 ? opts.project : void 0;
3925
+ const pr = await resolveScopedProject(client, explicitProject, "ws-default", { commandLabel: "siming dag template show" });
3926
+ if (!pr.success) {
3927
+ renderResult(opts.format, pr);
3928
+ return;
3739
3929
  }
3930
+ projectId = pr.data.projectId;
3740
3931
  }
3741
3932
  const result = await handleGetTemplate(client, templateRef, projectId);
3742
3933
  renderResult(opts.format, result, { fields: result.success ? templateFields(result.data) : [] });
@@ -3903,13 +4094,15 @@ async function runYamlImport(client, yamlText, opts, jsonParseError2) {
3903
4094
  return;
3904
4095
  }
3905
4096
  let projectId;
3906
- if (opts.project !== void 0) {
3907
- const r = await resolveProjectId(client, opts.project);
4097
+ if (opts.project !== void 0 && opts.project.trim().length > 0) {
4098
+ const r = await resolveScopedProject(client, opts.project, "explicit-only", {
4099
+ commandLabel: "siming dag template import"
4100
+ });
3908
4101
  if (!r.success) {
3909
4102
  renderResult("json", r);
3910
4103
  return;
3911
4104
  }
3912
- projectId = r.data;
4105
+ projectId = r.data.projectId;
3913
4106
  }
3914
4107
  const result = await importTemplateFromYaml(client, yamlText, {
3915
4108
  ...projectId !== void 0 ? { projectId } : {},
@@ -3969,13 +4162,15 @@ async function runBundleImport(client, bundleText, opts) {
3969
4162
  }));
3970
4163
  return;
3971
4164
  }
3972
- const target = await resolveImportTargetProject(client, opts.project);
3973
- if (!target.success) {
3974
- renderResult("json", target);
4165
+ const explicitBundleTarget = opts.project !== void 0 && opts.project.trim().length > 0 ? opts.project : void 0;
4166
+ const pr = await resolveScopedProject(client, explicitBundleTarget, "instance-default", { commandLabel: "siming dag template import" });
4167
+ if (!pr.success) {
4168
+ renderResult("json", pr);
3975
4169
  return;
3976
4170
  }
3977
4171
  const result = await importTemplateBundle(client, bundleText, {
3978
- targetProjectId: target.data,
4172
+ targetProjectId: pr.data.projectId,
4173
+ // instance-default 成功必含 id
3979
4174
  ...opts.overwriteDeps === true ? { overwriteDeps: true } : {},
3980
4175
  ...opts.plan === true ? { planOnly: true } : {}
3981
4176
  });
@@ -3985,31 +4180,6 @@ async function runBundleImport(client, bundleText, opts) {
3985
4180
  }
3986
4181
  renderBundleImportOutcome(result.data, opts.plan === true);
3987
4182
  }
3988
- async function resolveImportTargetProject(client, projectOpt) {
3989
- if (projectOpt !== void 0) return resolveProjectId(client, projectOpt);
3990
- const wsDefault = readWorkspaceConfig()?.defaultProject;
3991
- if (wsDefault !== void 0) {
3992
- const r = await resolveProjectId(client, wsDefault);
3993
- if (!r.success) {
3994
- return fail({
3995
- ...r.error,
3996
- hint: `workspace defaultProject "${wsDefault}" \u89E3\u6790\u5931\u8D25\u2014\u2014siming config unset defaultProject \u540E\u91CD\u8BD5\uFF0C\u6216\u663E\u5F0F --project <key|id>`
3997
- });
3998
- }
3999
- return r;
4000
- }
4001
- const list = await handleListProjects(client);
4002
- if (!list.success) return list;
4003
- const defaultProject = list.data.find((p) => p.key === "default");
4004
- if (defaultProject?.id === void 0) {
4005
- return fail({
4006
- message: "bundle \u5BFC\u5165\u9700\u8981\u76EE\u6807\u9879\u76EE\uFF1A\u672A\u6307\u5B9A --project\uFF0C\u5DE5\u4F5C\u533A\u65E0 defaultProject\uFF0C\u5B9E\u4F8B\u4E2D\u4E5F\u65E0 key=default \u7684\u9879\u76EE",
4007
- httpStatus: 0,
4008
- hint: "pass --project <key|id>\uFF0C\u6216\u5148 siming project create + siming init --project <key>"
4009
- });
4010
- }
4011
- return { success: true, data: defaultProject.id };
4012
- }
4013
4183
  function renderBundleImportOutcome(outcome, planOnly) {
4014
4184
  const t = outcome.plan.template;
4015
4185
  const overwritten = t.willOverwrite && t.currentVersion !== void 0 ? `\u8986\u76D6\u73B0\u6709 v${t.currentVersion} \u2192 ` : "";
@@ -4284,7 +4454,7 @@ ${failures.join("\n")}`,
4284
4454
  // src/commands/node/command.ts
4285
4455
  function createNodeCommand() {
4286
4456
  const node = new Command6("node").description("NodePreset management \u2014 reusable DAG node assets (addressed by unique code)");
4287
- withCommonOpts(node.command("list"), "table").option("--project <id>", "overlay visible set: global + this project").option("--scope <scope>", "exact scope filter: global|project").option("--q <keyword>", "search in code/label").description("List node presets (summary projection: no prompt \u2014 use `show` for full detail)").action(async (opts) => {
4457
+ withCommonOpts(node.command("list"), "table").option("--project <key|id>", "overlay visible set: global + this project (key|id)").option("--scope <scope>", "exact scope filter: global|project").option("--q <keyword>", "search in code/label").description("List node presets (summary projection: no prompt \u2014 use `show` for full detail)").action(async (opts) => {
4288
4458
  let scope;
4289
4459
  if (opts.scope !== void 0) {
4290
4460
  const scopeR = parseEnum(opts.scope, SkillScopeSchema2, "scope");
@@ -4295,8 +4465,17 @@ function createNodeCommand() {
4295
4465
  scope = scopeR.data;
4296
4466
  }
4297
4467
  const client = createClient(opts.url);
4468
+ let projectId;
4469
+ if (opts.project !== void 0 && opts.project.trim().length > 0) {
4470
+ const pr = await resolveScopedProject(client, opts.project, "explicit-only");
4471
+ if (!pr.success) {
4472
+ renderResult(opts.format, pr);
4473
+ return;
4474
+ }
4475
+ projectId = pr.data.projectId;
4476
+ }
4298
4477
  const result = await handleListNodePresets(client, {
4299
- ...opts.project !== void 0 ? { projectId: opts.project } : {},
4478
+ ...projectId !== void 0 ? { projectId } : {},
4300
4479
  ...scope !== void 0 ? { scope } : {},
4301
4480
  ...opts.q !== void 0 ? { q: opts.q } : {}
4302
4481
  });
@@ -4319,7 +4498,7 @@ function createNodeCommand() {
4319
4498
  const result = await handleGetNodePreset(client, code);
4320
4499
  renderResult(opts.format, result, { fields: result.success ? nodeFields2(result.data) : [] });
4321
4500
  });
4322
- node.command("create").description("Create a node preset (code globally unique & immutable; scope required)").option("--url <url>", "server base URL").requiredOption("--code <code>", "unique business code (kebab-case, immutable)").requiredOption("--label <text>", "display label").requiredOption("--node-id <id>", "default node id when assembled into templates ([A-Za-z0-9_-]+)").requiredOption("--phase <phase>", "node phase (e.g. entry|track|test|exit)").requiredOption("--track <track>", "node track (backend|ui|all)").requiredOption("--prompt <text>", "node prompt body").option("--prompt-file <path>", "read prompt from file (overrides --prompt)").option("--skill <name>", "bound skill name (repeatable)", collectArgs, []).option("--agent <name>", "callable agent name (repeatable)", collectArgs, []).option("--description <text>", "asset description").requiredOption("--scope <scope>", "global|project").option("--project-id <hex>", "projectId (required when scope=project)").action(async (opts) => {
4501
+ node.command("create").description("Create a node preset (code globally unique & immutable; scope required)").option("--url <url>", "server base URL").requiredOption("--code <code>", "unique business code (kebab-case, immutable)").requiredOption("--label <text>", "display label").requiredOption("--node-id <id>", "default node id when assembled into templates ([A-Za-z0-9_-]+)").requiredOption("--phase <phase>", "node phase (e.g. entry|track|test|exit)").requiredOption("--track <track>", "node track (backend|ui|all)").requiredOption("--prompt <text>", "node prompt body").option("--prompt-file <path>", "read prompt from file (overrides --prompt)").option("--skill <name>", "bound skill name (repeatable)", collectArgs, []).option("--agent <name>", "callable agent name (repeatable)", collectArgs, []).option("--description <text>", "asset description").requiredOption("--scope <scope>", "global|project").option("--project-id <key|id>", "projectId (scope=project; falls back to workspace/instance default project)").action(async (opts) => {
4323
4502
  const scopeR = parseEnum(opts.scope, SkillScopeSchema2, "scope");
4324
4503
  if (!scopeR.success) {
4325
4504
  renderResult("json", scopeR);
@@ -4342,6 +4521,16 @@ function createNodeCommand() {
4342
4521
  return;
4343
4522
  }
4344
4523
  const client = createClient(opts.url);
4524
+ let projectId;
4525
+ const explicitProject = opts.projectId !== void 0 && opts.projectId.trim().length > 0 ? opts.projectId : void 0;
4526
+ if (explicitProject !== void 0 || scopeR.data === "project") {
4527
+ const pr = await resolveScopedProject(client, explicitProject, "instance-default", { commandLabel: "siming node create" });
4528
+ if (!pr.success) {
4529
+ renderResult("json", pr);
4530
+ return;
4531
+ }
4532
+ projectId = pr.data.projectId;
4533
+ }
4345
4534
  const input = {
4346
4535
  code: opts.code,
4347
4536
  label: opts.label,
@@ -4354,7 +4543,7 @@ function createNodeCommand() {
4354
4543
  scope: scopeR.data,
4355
4544
  version: "1.0.0",
4356
4545
  ...opts.description !== void 0 ? { description: opts.description } : {},
4357
- ...opts.projectId !== void 0 ? { projectId: opts.projectId } : {}
4546
+ ...projectId !== void 0 ? { projectId } : {}
4358
4547
  };
4359
4548
  renderResult("json", await handleCreateNodePreset(client, input));
4360
4549
  });
@@ -4399,17 +4588,27 @@ function createNodeCommand() {
4399
4588
  }
4400
4589
  renderResult("json", await handleUpdateNodePreset(client, code, patch));
4401
4590
  });
4402
- node.command("copy <code>").description("Copy a node preset to a new code/scope (copy version resets 1.0.0)").option("--url <url>", "server base URL").requiredOption("--new-code <code>", "new unique code (kebab-case)").requiredOption("--new-scope <scope>", "global|project").option("--target-project-id <hex>", "target projectId (required when newScope=project)").action(async (code, opts) => {
4591
+ node.command("copy <code>").description("Copy a node preset to a new code/scope (copy version resets 1.0.0)").option("--url <url>", "server base URL").requiredOption("--new-code <code>", "new unique code (kebab-case)").requiredOption("--new-scope <scope>", "global|project").option("--target-project-id <key|id>", "target projectId (newScope=project; falls back to workspace/instance default project)").action(async (code, opts) => {
4403
4592
  const scopeR = parseEnum(opts.newScope, SkillScopeSchema2, "new-scope");
4404
4593
  if (!scopeR.success) {
4405
4594
  renderResult("json", scopeR);
4406
4595
  return;
4407
4596
  }
4408
4597
  const client = createClient(opts.url);
4598
+ let targetProjectId;
4599
+ const explicitTarget = opts.targetProjectId !== void 0 && opts.targetProjectId.trim().length > 0 ? opts.targetProjectId : void 0;
4600
+ if (explicitTarget !== void 0 || scopeR.data === "project") {
4601
+ const pr = await resolveScopedProject(client, explicitTarget, "instance-default", { commandLabel: "siming node copy" });
4602
+ if (!pr.success) {
4603
+ renderResult("json", pr);
4604
+ return;
4605
+ }
4606
+ targetProjectId = pr.data.projectId;
4607
+ }
4409
4608
  renderResult("json", await handleCopyNodePreset(client, code, {
4410
4609
  newCode: opts.newCode,
4411
4610
  newScope: scopeR.data,
4412
- ...opts.targetProjectId !== void 0 ? { targetProjectId: opts.targetProjectId } : {}
4611
+ ...targetProjectId !== void 0 ? { targetProjectId } : {}
4413
4612
  }));
4414
4613
  });
4415
4614
  node.command("enabled <code>").description("Enable/disable a node preset (sole write entry for enabled; disabled presets invisible to list/compose)").option("--url <url>", "server base URL").requiredOption("--value <bool>", "true|false").action(async (code, opts) => {
@@ -4792,26 +4991,22 @@ function createFlowCommand() {
4792
4991
  });
4793
4992
  flow.command("install <pkg-spec>").description(
4794
4993
  "Install a node library package from npm \u2014 validate 1.1 manifest \u2192 plan complete assets \u2192 confirm \u2192 apply dependencies \u2192 nodes \u2192 library"
4795
- ).option("--url <url>", "server base URL").option("--scope <scope>", "install scope: global|project", "global").option("--project <key|id>", "target project (required when scope=project)").option("--registry <url>", "npm registry for pack (e.g. private mirror; default npm config)").option("--yes", "skip interactive confirmation").option("--force", "allow version downgrade; admin may also sync a conflicting model alias display name (realModel is never overwritten)").action(async (pkgSpec, opts) => {
4994
+ ).option("--url <url>", "server base URL").option("--scope <scope>", "install scope: global|project", "global").option("--project <key|id>", "target project (scope=project; falls back to workspace/instance default project)").option("--registry <url>", "npm registry for pack (e.g. private mirror; default npm config)").option("--yes", "skip interactive confirmation").option("--force", "allow version downgrade; admin may also sync a conflicting model alias display name (realModel is never overwritten)").action(async (pkgSpec, opts) => {
4796
4995
  const scopeResult = parseEnum(opts.scope, SkillScopeSchema3, "scope");
4797
4996
  if (!scopeResult.success) {
4798
4997
  renderResult("json", scopeResult);
4799
4998
  return;
4800
4999
  }
4801
5000
  const scope = scopeResult.data;
4802
- if (scope === "project" && opts.project === void 0) {
4803
- renderResult("json", fail({ message: "scope=project \u9700\u8981 --project <key|id>", httpStatus: 0 }));
4804
- return;
4805
- }
4806
5001
  const client = createClient(opts.url);
4807
5002
  let projectId;
4808
5003
  if (scope === "project") {
4809
- const projectResult = await resolveProjectId(client, opts.project);
4810
- if (!projectResult.success) {
4811
- renderResult("json", projectResult);
5004
+ const pr = await resolveScopedProject(client, opts.project, "instance-default", { commandLabel: "siming flow install" });
5005
+ if (!pr.success) {
5006
+ renderResult("json", pr);
4812
5007
  return;
4813
5008
  }
4814
- projectId = projectResult.data;
5009
+ projectId = pr.data.projectId;
4815
5010
  }
4816
5011
  const fetched = await fetchManifest(pkgSpec, opts.registry);
4817
5012
  if (!fetched.success) {
@@ -4855,15 +5050,16 @@ ${conflicts.map((item) => ` ${item.kind}:${item.key} \u2014 ${item.reason ?? "\
4855
5050
  cleanup();
4856
5051
  }
4857
5052
  });
4858
- flow.command("compose <composition>").description("Assemble a DAG template from an installed library composition (value-copy nodes + sourcePreset baseline)").option("--url <url>", "server base URL").requiredOption("--project <key|id>", "target project (template owner)").option("--name <name>", "generated template name (default: composition name)").option("--from <library>", "source library name (required when multiple libraries define the same composition)").action(async (composition, opts) => {
5053
+ flow.command("compose <composition>").description("Assemble a DAG template from an installed library composition (value-copy nodes + sourcePreset baseline)").option("--url <url>", "server base URL").option("--project <key|id>", "target project (template owner; falls back to workspace/instance default project)").option("--name <name>", "generated template name (default: composition name)").option("--from <library>", "source library name (required when multiple libraries define the same composition)").action(async (composition, opts) => {
4859
5054
  const client = createClient(opts.url);
4860
- const projectResult = await resolveProjectId(client, opts.project);
4861
- if (!projectResult.success) {
4862
- renderResult("json", projectResult);
5055
+ const pr = await resolveScopedProject(client, opts.project, "instance-default", { commandLabel: "siming flow compose" });
5056
+ if (!pr.success) {
5057
+ renderResult("json", pr);
4863
5058
  return;
4864
5059
  }
4865
5060
  const result = await composeFlowTemplate(client, composition, {
4866
- projectId: projectResult.data,
5061
+ projectId: pr.data.projectId,
5062
+ // instance-default 成功必含 id
4867
5063
  ...opts.name !== void 0 ? { name: opts.name } : {},
4868
5064
  ...opts.from !== void 0 ? { from: opts.from } : {}
4869
5065
  });
@@ -6933,13 +7129,13 @@ function parseVersion(v) {
6933
7129
  // src/commands/install/command.ts
6934
7130
  function createInstallCommand() {
6935
7131
  const install = new Command12("install").description("Install skills/agents from Siming to local AI platform");
6936
- withCommonOpts(install.command("plan"), "table").option("--scope <s>", "install scope: global|project", "global").option("--project <key-or-id>", "project key or id (required when scope=project)").option("--only <name>", 'filter by asset name (repeatable; use "siming" for the MCP entry)', collectArgs, []).description("Preview install plan (no write)").action(async (opts) => {
7132
+ withCommonOpts(install.command("plan"), "table").option("--scope <s>", "install scope: global|project", "global").option("--project <key|id>", "project key or id (scope=project; falls back to workspace/instance default project)").option("--only <name>", 'filter by asset name (repeatable; use "siming" for the MCP entry)', collectArgs, []).description("Preview install plan (no write)").action(async (opts) => {
6937
7133
  const scope = parseScope(opts.scope, opts.format);
6938
7134
  if (!scope) return;
6939
7135
  const client = createClient(opts.url);
6940
7136
  const projectR = await resolveInstallProject(client, scope, opts.project);
6941
7137
  if (!projectR.ok) {
6942
- renderResult(opts.format, { success: false, error: { message: projectR.error.message, httpStatus: 0, ...projectR.error.hint ? { hint: projectR.error.hint } : {} } });
7138
+ renderResult(opts.format, { success: false, error: { message: projectR.error.message, httpStatus: projectR.error.httpStatus, ...projectR.error.bizCode !== void 0 ? { bizCode: projectR.error.bizCode } : {}, ...projectR.error.hint ? { hint: projectR.error.hint } : {} } });
6943
7139
  return;
6944
7140
  }
6945
7141
  const projectId = projectR.projectId;
@@ -6951,14 +7147,14 @@ function createInstallCommand() {
6951
7147
  const plan = result.data;
6952
7148
  renderInstallPlan2(opts.format, plan, scope, resolveInstallTargets(scope).targets);
6953
7149
  });
6954
- withCommonOpts(install.command("apply"), "json").option("--scope <s>", "install scope: global|project", "global").option("--project <key-or-id>", "project key or id (required when scope=project)").option("--only <name>", 'install only this asset (repeatable; use "siming" for the MCP entry)', collectArgs, []).option("--yes", "skip interactive confirmation").option("--force", "overwrite all selected local assets, including same-version and conflict items").description("Apply install plan (write to local)").action(
7150
+ withCommonOpts(install.command("apply"), "json").option("--scope <s>", "install scope: global|project", "global").option("--project <key|id>", "project key or id (scope=project; falls back to workspace/instance default project)").option("--only <name>", 'install only this asset (repeatable; use "siming" for the MCP entry)', collectArgs, []).option("--yes", "skip interactive confirmation").option("--force", "overwrite all selected local assets, including same-version and conflict items").description("Apply install plan (write to local)").action(
6955
7151
  async (opts) => {
6956
7152
  const scope = parseScope(opts.scope, opts.format);
6957
7153
  if (!scope) return;
6958
7154
  const client = createClient(opts.url);
6959
7155
  const projectR = await resolveInstallProject(client, scope, opts.project);
6960
7156
  if (!projectR.ok) {
6961
- renderResult(opts.format, { success: false, error: { message: projectR.error.message, httpStatus: 0, ...projectR.error.hint ? { hint: projectR.error.hint } : {} } });
7157
+ renderResult(opts.format, { success: false, error: { message: projectR.error.message, httpStatus: projectR.error.httpStatus, ...projectR.error.bizCode !== void 0 ? { bizCode: projectR.error.bizCode } : {}, ...projectR.error.hint ? { hint: projectR.error.hint } : {} } });
6962
7158
  return;
6963
7159
  }
6964
7160
  const projectId = projectR.projectId;
@@ -7034,34 +7230,19 @@ function parseScope(s, format) {
7034
7230
  }
7035
7231
  async function resolveInstallProject(client, scope, projectOpt) {
7036
7232
  if (scope === "global") return { ok: true };
7037
- if (projectOpt) {
7038
- const r = await resolveProjectId(client, projectOpt);
7039
- if (!r.success) {
7040
- return { ok: false, error: { message: r.error.message, ...r.error.hint ? { hint: r.error.hint } : {} } };
7041
- }
7042
- return { ok: true, projectId: r.data };
7043
- }
7044
- const ws = findWorkspaceDir();
7045
- const cfg = ws ? readWorkspaceConfigSafe(ws) : null;
7046
- if (cfg?.defaultProject) {
7047
- const r = await resolveProjectId(client, cfg.defaultProject);
7048
- if (r.success) return { ok: true, projectId: r.data };
7049
- return { ok: false, error: { message: r.error.message, ...r.error.hint ? { hint: r.error.hint } : {} } };
7050
- }
7051
- return {
7052
- ok: false,
7053
- error: {
7054
- message: "scope=project requires --project <key|id> or workspace default project",
7055
- hint: "run `siming config set defaultProject <key|id>` or `siming install --scope project --project <key|id>`"
7056
- }
7057
- };
7058
- }
7059
- function readWorkspaceConfigSafe(ws) {
7060
- try {
7061
- return readWorkspaceConfig(ws);
7062
- } catch {
7063
- return null;
7233
+ const r = await resolveScopedProject(client, projectOpt, "instance-default", { commandLabel: "siming install" });
7234
+ if (!r.success) {
7235
+ return {
7236
+ ok: false,
7237
+ error: {
7238
+ message: r.error.message,
7239
+ httpStatus: r.error.httpStatus,
7240
+ ...r.error.bizCode !== void 0 ? { bizCode: r.error.bizCode } : {},
7241
+ ...r.error.hint ? { hint: r.error.hint } : {}
7242
+ }
7243
+ };
7064
7244
  }
7245
+ return r.data.projectId !== void 0 ? { ok: true, projectId: r.data.projectId } : { ok: true };
7065
7246
  }
7066
7247
  async function buildInstallPlan(client, scope, projectId, only) {
7067
7248
  const listQuery = scope === "global" ? { scope: "global", includeDisabled: true } : { scope: "project", ...projectId ? { projectId } : {}, includeDisabled: true };
@@ -7431,7 +7612,7 @@ async function runInit(client, input) {
7431
7612
  };
7432
7613
  }
7433
7614
  function createInitCommand() {
7434
- const init = new Command13("init").description("Initialize workspace config for Siming (idempotent)").option("--url <url>", "server base URL (also used to resolve project key)").option("--server-url <url>", "server base URL to persist into workspace config").option("--project <key-or-id>", "project key or id to set as workspace default project").option("--install", "run install apply after init (non-interactive; writes to .agents universal dir)").option("--install-scope <scope>", "install scope when --install: global|project (default: global; global also registers mcp.json)").option("--format <fmt>", "output format", "fancy").action(async (opts) => {
7615
+ const init = new Command13("init").description("Initialize workspace config for Siming (idempotent)").option("--url <url>", "server base URL (also used to resolve project key)").option("--server-url <url>", "server base URL to persist into workspace config").option("--project <key|id>", "project key or id to set as workspace default project").option("--install", "run install apply after init (non-interactive; writes to .agents universal dir)").option("--install-scope <scope>", "install scope when --install: global|project (default: global; global also registers mcp.json)").option("--format <fmt>", "output format", "fancy").action(async (opts) => {
7435
7616
  const client = createClient(opts.url);
7436
7617
  const result = await runInit(client, {
7437
7618
  ...opts.serverUrl ? { serverUrl: opts.serverUrl } : {},
@@ -7744,7 +7925,7 @@ ${ROADMAP_TEXT}
7744
7925
  \u9879\u76EE\u6807\u8BC6\u3001\u5FEB\u901F\u901A\u9053\u89C4\u5219\uFF09\uFF0C\u6309\u6E05\u5355\u66FF\u6362\u4E3A\u9879\u76EE\u771F\u5B9E\u7EA6\u5B9A\u540E\u65B9\u53EF\u7528\u4E8E\u521B\u5EFA\u4EFB\u52A1\u3002
7745
7926
  \u540C\u540D\u51B2\u7A81\u4FDD\u62A4\uFF1A\u9879\u76EE\u5185\u5DF2\u6709\u540C\u540D\u8D44\u4EA7\u65F6\u9ED8\u8BA4\u62D2\u7EDD\u4E14\u96F6\u5199\u5165\uFF1B
7746
7927
  \u786E\u8BA4\u66FF\u6362\u52A0 --overwrite\uFF08\u7248\u672C\u5355\u8C03\u9012\u589E\uFF0C\u542F\u505C\u72B6\u6001\u4E0D\u53D8\uFF09\u3002
7747
- \u67E5\u770B\u73B0\u5B58\u8D44\u4EA7\uFF1Asiming skill show task-create --scope project --project-id <id>
7928
+ \u67E5\u770B\u73B0\u5B58\u8D44\u4EA7\uFF1Asiming skill show task-create --scope project --project-id <key|id>
7748
7929
 
7749
7930
  2. siming-arch \u2014\u2014 \u67B6\u6784\u6587\u6863\u7D22\u5F15\uFF1A\u6307\u5411\u672C\u9879\u76EE\u4ED3\u5E93\u67B6\u6784\u6587\u6863\u76EE\u5F55\u7684\u9AA8\u67B6
7750
7931
  \uFF08\u6BCF\u9879\u76EE\u4E00\u4EFD\uFF1B\u67B6\u6784\u6587\u6863\u5B9E\u4F53\u5B58\u9879\u76EE\u4ED3\u5E93\uFF0C\u7D22\u5F15\u53EA\u5B58\u4F4D\u7F6E\u4E0D\u5B58\u5185\u5BB9\uFF09\u3002
@@ -8523,7 +8704,7 @@ function parseDeclarationsMap(spec) {
8523
8704
  }
8524
8705
  function createIssueCommand() {
8525
8706
  const issue = new Command18("issue").description("Issue pool: record \u2192 organize \u2192 convert to tasks");
8526
- withCommonOpts(issue.command("add"), "fancy").description("Record an issue into the pool (source=cli)").argument("[title]", "issue title (or use --title)").option("--title <t>", "issue title (1-200 chars)").option("--description <d>", "issue description (optional)").option("--project <key-or-id>", "projectId (key or id; defaults to workspace defaultProject, then server default project)").action(async (titleArg, opts) => {
8707
+ withCommonOpts(issue.command("add"), "fancy").description("Record an issue into the pool (source=cli)").argument("[title]", "issue title (or use --title)").option("--title <t>", "issue title (1-200 chars)").option("--description <d>", "issue description (optional)").option("--project <key|id>", "projectId (key|id; falls back to workspace defaultProject, then server default project)").action(async (titleArg, opts) => {
8527
8708
  const client = createClient(opts.url);
8528
8709
  const title = opts.title ?? titleArg;
8529
8710
  if (title === void 0 || title.length === 0) {
@@ -8533,21 +8714,12 @@ function createIssueCommand() {
8533
8714
  });
8534
8715
  return;
8535
8716
  }
8536
- let projectId;
8537
- if (opts.project) {
8538
- const r = await resolveProjectId(client, opts.project);
8539
- if (!r.success) {
8540
- renderResult("json", r);
8541
- return;
8542
- }
8543
- projectId = r.data;
8544
- } else {
8545
- const wsDefaultProject = readWorkspaceConfig()?.defaultProject;
8546
- if (wsDefaultProject) {
8547
- const r = await resolveProjectId(client, wsDefaultProject);
8548
- if (r.success) projectId = r.data;
8549
- }
8717
+ const projectR = await resolveScopedProject(client, opts.project, "ws-default", { commandLabel: "siming issue add" });
8718
+ if (!projectR.success) {
8719
+ renderResult(opts.format ?? "fancy", projectR);
8720
+ return;
8550
8721
  }
8722
+ const projectId = projectR.data.projectId;
8551
8723
  const result = await handleCreateIssue(client, {
8552
8724
  title,
8553
8725
  ...opts.description !== void 0 ? { description: opts.description } : {},
@@ -8555,7 +8727,7 @@ function createIssueCommand() {
8555
8727
  });
8556
8728
  renderResult(opts.format ?? "fancy", result);
8557
8729
  });
8558
- withCommonOpts(issue.command("list"), "table").option("--status <s>", "filter by issue status (pending|partial|converted|cancelled)").option("--source <s>", "filter by source channel (mcp|cli|web)").option("--project <key-or-id>", "filter by projectId (key or id)").option("--task <taskId>", "filter by linked task").option("--q <keyword>", "search in title/description").option("--view <v>", "view: all|open (default all; open = \u6709\u6548\u672A\u8DDF\u8FDB\u5B8C)").option("--page <n>", "page number (default 1)", "1").option("--limit <n>", `page size (default ${PAGE_DEFAULT2}, max ${PAGE_MAX2})`).option("--all", `show all (limit ${PAGE_MAX2})`).description("List issues (with progress aggregation done/cancelled/total)").action(async (opts) => {
8730
+ withCommonOpts(issue.command("list"), "table").option("--status <s>", "filter by issue status (pending|partial|converted|cancelled)").option("--source <s>", "filter by source channel (mcp|cli|web)").option("--project <key|id>", "filter by projectId (key|id)").option("--task <taskId>", "filter by linked task").option("--q <keyword>", "search in title/description").option("--view <v>", "view: all|open (default all; open = \u6709\u6548\u672A\u8DDF\u8FDB\u5B8C)").option("--page <n>", "page number (default 1)", "1").option("--limit <n>", `page size (default ${PAGE_DEFAULT2}, max ${PAGE_MAX2})`).option("--all", `show all (limit ${PAGE_MAX2})`).description("List issues (with progress aggregation done/cancelled/total)").action(async (opts) => {
8559
8731
  const client = createClient(opts.url);
8560
8732
  const filters = {};
8561
8733
  if (opts.status) filters.status = opts.status;
@@ -8570,13 +8742,14 @@ function createIssueCommand() {
8570
8742
  }
8571
8743
  filters.view = r.data;
8572
8744
  }
8573
- if (opts.project) {
8574
- const r = await resolveProjectId(client, opts.project);
8575
- if (!r.success) {
8576
- renderResult(opts.format ?? "table", r);
8745
+ if (opts.project !== void 0 && opts.project.trim().length > 0) {
8746
+ const pr = await resolveScopedProject(client, opts.project, "explicit-only");
8747
+ if (!pr.success) {
8748
+ renderResult(opts.format ?? "table", pr);
8577
8749
  return;
8578
8750
  }
8579
- filters.projectId = r.data;
8751
+ const pid = pr.data.projectId;
8752
+ if (pid !== void 0) filters.projectId = pid;
8580
8753
  }
8581
8754
  if (opts.all) {
8582
8755
  filters.limit = PAGE_MAX2;
@@ -8656,7 +8829,7 @@ function createIssueCommand() {
8656
8829
  const result = await handleCancelIssue(client, issueId, opts.reason);
8657
8830
  renderResult(opts.format ?? "fancy", result);
8658
8831
  });
8659
- 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-or-id>", "projectId (key or 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) => {
8832
+ 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) => {
8660
8833
  const client = createClient(opts.url);
8661
8834
  const issueIds = [
8662
8835
  ...new Set((opts.issueIds ?? []).flatMap((s) => s.split(",")).map((s) => s.trim()).filter((s) => s.length > 0))
@@ -8687,13 +8860,13 @@ function createIssueCommand() {
8687
8860
  declarations = Object.fromEntries(issueIds.map((id) => [id, "all"]));
8688
8861
  }
8689
8862
  let projectId;
8690
- if (opts.project) {
8691
- const r = await resolveProjectId(client, opts.project);
8692
- if (!r.success) {
8693
- renderResult(opts.format ?? "fancy", r);
8863
+ if (opts.project !== void 0 && opts.project.trim().length > 0) {
8864
+ const pr = await resolveScopedProject(client, opts.project, "explicit-only");
8865
+ if (!pr.success) {
8866
+ renderResult(opts.format ?? "fancy", pr);
8694
8867
  return;
8695
8868
  }
8696
- projectId = r.data;
8869
+ projectId = pr.data.projectId;
8697
8870
  } else {
8698
8871
  const first = await handleGetIssue(client, issueIds[0]);
8699
8872
  if (!first.success) {