@siming-org/cli 0.6.4 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
|
-
import { Command as
|
|
2
|
+
import { Command as Command20 } from "commander";
|
|
3
3
|
import { VERSION as VERSION5 } from "@siming-org/core";
|
|
4
4
|
|
|
5
5
|
// src/output/fancy.ts
|
|
@@ -522,10 +522,13 @@ function writeGlobalAuthToken(token, path) {
|
|
|
522
522
|
|
|
523
523
|
// src/client/http-client.ts
|
|
524
524
|
var SimingHttpClient = class {
|
|
525
|
-
|
|
525
|
+
/** T202609150002:通道 source 标识(x-siming-source header 单一注入口;Web 通道由 web client 固定携带 web) */
|
|
526
|
+
constructor(baseUrl, source = "cli") {
|
|
526
527
|
this.baseUrl = baseUrl;
|
|
528
|
+
this.source = source;
|
|
527
529
|
}
|
|
528
530
|
baseUrl;
|
|
531
|
+
source;
|
|
529
532
|
/** server base URL(诊断输出用——auth whoami 展示目标地址) */
|
|
530
533
|
get url() {
|
|
531
534
|
return this.baseUrl;
|
|
@@ -534,7 +537,9 @@ var SimingHttpClient = class {
|
|
|
534
537
|
const token = resolveAuthToken();
|
|
535
538
|
const headers = {
|
|
536
539
|
...token !== void 0 ? { Authorization: `Bearer ${token}` } : {},
|
|
537
|
-
...body !== void 0 ? { "Content-Type": "application/json" } : {}
|
|
540
|
+
...body !== void 0 ? { "Content-Type": "application/json" } : {},
|
|
541
|
+
// T202609150002:issue 域通道注入(服务端按 header 判定 source,缺省 web)
|
|
542
|
+
"x-siming-source": this.source
|
|
538
543
|
};
|
|
539
544
|
return fetch(`${this.baseUrl}${path}`, {
|
|
540
545
|
method,
|
|
@@ -628,8 +633,8 @@ function resolveServerUrl(baseUrl) {
|
|
|
628
633
|
url = url ?? readWorkspaceConfig()?.serverUrl ?? getLocalServerUrl();
|
|
629
634
|
return url.replace(/\/$/, "");
|
|
630
635
|
}
|
|
631
|
-
function createClient(baseUrl) {
|
|
632
|
-
return new SimingHttpClient(resolveServerUrl(baseUrl));
|
|
636
|
+
function createClient(baseUrl, source) {
|
|
637
|
+
return new SimingHttpClient(resolveServerUrl(baseUrl), source);
|
|
633
638
|
}
|
|
634
639
|
|
|
635
640
|
// src/commands/healthcheck.ts
|
|
@@ -673,10 +678,11 @@ import {
|
|
|
673
678
|
async function handleCreateTask(client, input) {
|
|
674
679
|
return client.postJson("/api/tasks", input);
|
|
675
680
|
}
|
|
676
|
-
async function handleAdvance(client, taskId, note, summary) {
|
|
681
|
+
async function handleAdvance(client, taskId, note, summary, finalize) {
|
|
677
682
|
return client.postJson(`/api/tasks/${taskId}/advance`, {
|
|
678
683
|
...note !== void 0 ? { note } : {},
|
|
679
|
-
...summary !== void 0 ? { summary } : {}
|
|
684
|
+
...summary !== void 0 ? { summary } : {},
|
|
685
|
+
...finalize ? { finalize: true } : {}
|
|
680
686
|
});
|
|
681
687
|
}
|
|
682
688
|
async function handleApprove(client, taskId, decision, comment) {
|
|
@@ -694,6 +700,9 @@ async function handleResume(client, taskId, decision) {
|
|
|
694
700
|
async function handleCancel(client, taskId, reason) {
|
|
695
701
|
return client.postJson(`/api/tasks/${taskId}/cancel`, reason !== void 0 ? { reason } : {});
|
|
696
702
|
}
|
|
703
|
+
async function handleReopen(client, taskId, reason) {
|
|
704
|
+
return client.postJson(`/api/tasks/${taskId}/reopen`, { reason });
|
|
705
|
+
}
|
|
697
706
|
async function handleListTasks(client, filters) {
|
|
698
707
|
const qs = new URLSearchParams();
|
|
699
708
|
if (filters?.status) qs.set("status", filters.status);
|
|
@@ -1250,6 +1259,40 @@ function readStdinLine(stream) {
|
|
|
1250
1259
|
});
|
|
1251
1260
|
}
|
|
1252
1261
|
|
|
1262
|
+
// src/client/handlers/issue.ts
|
|
1263
|
+
async function handleCreateIssue(client, input) {
|
|
1264
|
+
return client.postJson("/api/issues", input);
|
|
1265
|
+
}
|
|
1266
|
+
async function handleListIssues(client, filters) {
|
|
1267
|
+
const params = new URLSearchParams();
|
|
1268
|
+
if (filters.status) params.set("status", filters.status);
|
|
1269
|
+
if (filters.source) params.set("source", filters.source);
|
|
1270
|
+
if (filters.projectId) params.set("projectId", filters.projectId);
|
|
1271
|
+
if (filters.taskId) params.set("taskId", filters.taskId);
|
|
1272
|
+
if (filters.q) params.set("q", filters.q);
|
|
1273
|
+
if (filters.view) params.set("view", filters.view);
|
|
1274
|
+
if (filters.page !== void 0) params.set("page", String(filters.page));
|
|
1275
|
+
if (filters.limit !== void 0) params.set("limit", String(filters.limit));
|
|
1276
|
+
const qs = params.toString();
|
|
1277
|
+
return client.getJson(`/api/issues${qs ? `?${qs}` : ""}`);
|
|
1278
|
+
}
|
|
1279
|
+
async function handleGetIssue(client, issueId) {
|
|
1280
|
+
return client.getJson(`/api/issues/${issueId}`);
|
|
1281
|
+
}
|
|
1282
|
+
async function handleUpdateIssue(client, issueId, patch) {
|
|
1283
|
+
return client.patchJson(`/api/issues/${issueId}`, patch);
|
|
1284
|
+
}
|
|
1285
|
+
async function handleCancelIssue(client, issueId, reason) {
|
|
1286
|
+
return client.postJson(`/api/issues/${issueId}/cancel`, reason !== void 0 ? { reason } : {});
|
|
1287
|
+
}
|
|
1288
|
+
async function handleConvertIssues(client, input) {
|
|
1289
|
+
const { issueIds, task, ...rest } = input;
|
|
1290
|
+
return client.postJson("/api/issues/convert", {
|
|
1291
|
+
...rest,
|
|
1292
|
+
groups: [{ issueIds, task }]
|
|
1293
|
+
});
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1253
1296
|
// src/mcp/tools.ts
|
|
1254
1297
|
import { z as z3 } from "zod";
|
|
1255
1298
|
import { TASK_TYPES, ARTIFACT_TYPES as ARTIFACT_TYPES2 } from "@siming-org/core";
|
|
@@ -1258,7 +1301,7 @@ function hostNeutralEnum(schema) {
|
|
|
1258
1301
|
}
|
|
1259
1302
|
var taskArgs = {
|
|
1260
1303
|
action: z3.enum([
|
|
1261
|
-
// 任务生命周期(
|
|
1304
|
+
// 任务生命周期(10 机械映射 + query 例外:task list/show 合一)
|
|
1262
1305
|
"create",
|
|
1263
1306
|
"query",
|
|
1264
1307
|
"context",
|
|
@@ -1268,6 +1311,7 @@ var taskArgs = {
|
|
|
1268
1311
|
"pause",
|
|
1269
1312
|
"resume",
|
|
1270
1313
|
"cancel",
|
|
1314
|
+
"reopen",
|
|
1271
1315
|
"history",
|
|
1272
1316
|
// 实例(例外:映射自 dag instance)
|
|
1273
1317
|
"instance",
|
|
@@ -1304,9 +1348,11 @@ var taskArgs = {
|
|
|
1304
1348
|
// context 只认 basic|full,per-action 校验归 mcp/server.ts;非法组合报失败三要素)
|
|
1305
1349
|
view: hostNeutralEnum(z3.enum(["prompt", "skills", "basic", "full"])).optional(),
|
|
1306
1350
|
nodeId: z3.string().optional(),
|
|
1307
|
-
// advance / record-set(note 写 history;summary 写 nodeRecords
|
|
1351
|
+
// advance / record-set(note 写 history;summary 写 nodeRecords,两位独立);
|
|
1352
|
+
// finalize 为 advance 收尾确认(终节点终态化必需,中间节点无副作用——T202609130009)
|
|
1308
1353
|
note: z3.string().optional(),
|
|
1309
1354
|
summary: z3.string().optional(),
|
|
1355
|
+
finalize: z3.boolean().optional(),
|
|
1310
1356
|
// approve
|
|
1311
1357
|
decision: hostNeutralEnum(z3.enum(["approved", "rejected"])).optional(),
|
|
1312
1358
|
comment: z3.string().optional(),
|
|
@@ -1356,6 +1402,23 @@ var templateArgs = {
|
|
|
1356
1402
|
var authArgs = {
|
|
1357
1403
|
action: z3.enum(["whoami"])
|
|
1358
1404
|
};
|
|
1405
|
+
var issueArgs = {
|
|
1406
|
+
action: z3.enum(["create", "query"]),
|
|
1407
|
+
/** 存在时只解释当前 action 列入 mask 的可选字段(模式对齐 taskArgs/applyFieldMask) */
|
|
1408
|
+
fieldMask: z3.array(z3.string()).optional(),
|
|
1409
|
+
// create
|
|
1410
|
+
title: z3.string().optional(),
|
|
1411
|
+
description: z3.string().optional(),
|
|
1412
|
+
// 公共:create 缺省按工作区 defaultProject,无配置时按 key=default / query 过滤(24-hex)
|
|
1413
|
+
projectId: z3.string().optional(),
|
|
1414
|
+
// query:view 缺省 open(有效未跟进完);与 REST 词汇统一(status/taskId 指定时切对应过滤)
|
|
1415
|
+
view: hostNeutralEnum(z3.enum(["open", "all"])).optional(),
|
|
1416
|
+
status: z3.string().optional(),
|
|
1417
|
+
/** query:任务反查(双向追溯 MCP 侧入口) */
|
|
1418
|
+
taskId: z3.string().optional(),
|
|
1419
|
+
page: z3.number().int().optional(),
|
|
1420
|
+
limit: z3.number().int().optional()
|
|
1421
|
+
};
|
|
1359
1422
|
|
|
1360
1423
|
// src/mcp/server.ts
|
|
1361
1424
|
function mcpContent(result) {
|
|
@@ -1453,11 +1516,12 @@ var TASK_FIELD_SPECS = {
|
|
|
1453
1516
|
query: { required: [], optional: ["taskId", "status", "track", "projectId", "page", "limit"] },
|
|
1454
1517
|
context: { required: ["taskId"], optional: ["view"] },
|
|
1455
1518
|
node: { required: ["taskId", "view"], optional: ["nodeId"] },
|
|
1456
|
-
advance: { required: ["taskId"], optional: ["note", "summary"] },
|
|
1519
|
+
advance: { required: ["taskId"], optional: ["note", "summary", "finalize"] },
|
|
1457
1520
|
approve: { required: ["taskId", "decision"], optional: ["comment"] },
|
|
1458
1521
|
pause: { required: ["taskId"], optional: ["reason"] },
|
|
1459
1522
|
resume: { required: ["taskId"], optional: ["resumeNote"] },
|
|
1460
1523
|
cancel: { required: ["taskId"], optional: ["reason"] },
|
|
1524
|
+
reopen: { required: ["taskId", "reason"], optional: [] },
|
|
1461
1525
|
history: { required: ["taskId"], optional: [] },
|
|
1462
1526
|
instance: { required: ["taskId"], optional: [] },
|
|
1463
1527
|
"record-set": { required: ["taskId", "node", "summary"], optional: [] },
|
|
@@ -1481,9 +1545,13 @@ var TASK_FIELD_SPECS = {
|
|
|
1481
1545
|
"doc-non-goal-add": { required: ["taskId"], optional: ["text", "textItems"] },
|
|
1482
1546
|
"archnote-add": { required: ["taskId"], optional: ["text", "textItems"] }
|
|
1483
1547
|
};
|
|
1548
|
+
var ISSUE_FIELD_SPECS = {
|
|
1549
|
+
create: { required: ["title"], optional: ["description", "projectId"] },
|
|
1550
|
+
query: { required: [], optional: ["view", "status", "taskId", "projectId", "page", "limit"] }
|
|
1551
|
+
};
|
|
1484
1552
|
function createMcpServer() {
|
|
1485
1553
|
const server = new McpServer({ name: "siming", version: VERSION });
|
|
1486
|
-
const client = createClient();
|
|
1554
|
+
const client = createClient(void 0, "mcp");
|
|
1487
1555
|
server.tool(
|
|
1488
1556
|
"siming_task",
|
|
1489
1557
|
"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",
|
|
@@ -1566,7 +1634,7 @@ function createMcpServer() {
|
|
|
1566
1634
|
case "advance": {
|
|
1567
1635
|
const { taskId } = args;
|
|
1568
1636
|
if (taskId === void 0) return requireError("advance", ["taskId"], args);
|
|
1569
|
-
return mcpContent(await handleAdvance(client, taskId, args.note, args.summary));
|
|
1637
|
+
return mcpContent(await handleAdvance(client, taskId, args.note, args.summary, args.finalize === true));
|
|
1570
1638
|
}
|
|
1571
1639
|
case "approve": {
|
|
1572
1640
|
const { taskId, decision } = args;
|
|
@@ -1590,6 +1658,13 @@ function createMcpServer() {
|
|
|
1590
1658
|
if (taskId === void 0) return requireError("cancel", ["taskId"], args);
|
|
1591
1659
|
return mcpContent(await handleCancel(client, taskId, args.reason));
|
|
1592
1660
|
}
|
|
1661
|
+
case "reopen": {
|
|
1662
|
+
const { taskId, reason } = args;
|
|
1663
|
+
if (taskId === void 0 || reason === void 0) {
|
|
1664
|
+
return requireError("reopen", ["taskId", "reason"], args);
|
|
1665
|
+
}
|
|
1666
|
+
return mcpContent(await handleReopen(client, taskId, reason));
|
|
1667
|
+
}
|
|
1593
1668
|
case "history": {
|
|
1594
1669
|
const { taskId } = args;
|
|
1595
1670
|
if (taskId === void 0) return requireError("history", ["taskId"], args);
|
|
@@ -1830,6 +1905,56 @@ function createMcpServer() {
|
|
|
1830
1905
|
}
|
|
1831
1906
|
}
|
|
1832
1907
|
);
|
|
1908
|
+
server.tool(
|
|
1909
|
+
"siming_issue",
|
|
1910
|
+
`\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\u2014\u7F3A\u7701\u6309\u5DE5\u4F5C\u533A defaultProject\uFF0C\u65E0\u914D\u7F6E\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`,
|
|
1911
|
+
issueArgs,
|
|
1912
|
+
async (rawArgs) => {
|
|
1913
|
+
const masked = applyFieldMask(rawArgs, ISSUE_FIELD_SPECS);
|
|
1914
|
+
if (!masked.success) return masked.response;
|
|
1915
|
+
const args = masked.args;
|
|
1916
|
+
switch (args.action) {
|
|
1917
|
+
case "create": {
|
|
1918
|
+
const { title } = args;
|
|
1919
|
+
if (title === void 0) {
|
|
1920
|
+
return requireError("create", ["title"], args);
|
|
1921
|
+
}
|
|
1922
|
+
let projectId;
|
|
1923
|
+
if (args.projectId !== void 0) {
|
|
1924
|
+
projectId = args.projectId;
|
|
1925
|
+
} else {
|
|
1926
|
+
const wsDefaultProject = readWorkspaceConfig()?.defaultProject;
|
|
1927
|
+
if (wsDefaultProject) projectId = wsDefaultProject;
|
|
1928
|
+
}
|
|
1929
|
+
return mcpContent(
|
|
1930
|
+
await handleCreateIssue(client, {
|
|
1931
|
+
title,
|
|
1932
|
+
...args.description !== void 0 ? { description: args.description } : {},
|
|
1933
|
+
...projectId !== void 0 ? { projectId } : {}
|
|
1934
|
+
})
|
|
1935
|
+
);
|
|
1936
|
+
}
|
|
1937
|
+
case "query": {
|
|
1938
|
+
if (args.page !== void 0 && args.page < 1) {
|
|
1939
|
+
return localError("action=query \u7684 page \u5FC5\u987B\u4E3A\u5927\u4E8E\u7B49\u4E8E 1 \u7684\u6574\u6570");
|
|
1940
|
+
}
|
|
1941
|
+
if (args.limit !== void 0 && (args.limit < 1 || args.limit > 500)) {
|
|
1942
|
+
return localError("action=query \u7684 limit \u5FC5\u987B\u4E3A 1-500 \u7684\u6574\u6570");
|
|
1943
|
+
}
|
|
1944
|
+
return mcpContent(
|
|
1945
|
+
await handleListIssues(client, {
|
|
1946
|
+
view: args.view ?? "open",
|
|
1947
|
+
...args.status !== void 0 ? { status: args.status } : {},
|
|
1948
|
+
...args.taskId !== void 0 ? { taskId: args.taskId } : {},
|
|
1949
|
+
...args.projectId !== void 0 ? { projectId: args.projectId } : {},
|
|
1950
|
+
...args.page !== void 0 ? { page: args.page } : {},
|
|
1951
|
+
...args.limit !== void 0 ? { limit: args.limit } : {}
|
|
1952
|
+
})
|
|
1953
|
+
);
|
|
1954
|
+
}
|
|
1955
|
+
}
|
|
1956
|
+
}
|
|
1957
|
+
);
|
|
1833
1958
|
server.tool(
|
|
1834
1959
|
"siming_auth",
|
|
1835
1960
|
`\u8EAB\u4EFD\u67E5\u8BE2\uFF08\u6743\u9650\u8FB9\u754C\u81EA\u68C0\uFF09\u3002action\uFF1Awhoami=\u8FD4\u56DE\u5F53\u524D\u8EAB\u4EFD\u56DB\u5143\u7EC4\u2014\u2014identity\uFF08admin=\u7BA1\u7406\u5458\u7EA7\u5168\u9879\u76EE\u5168\u5185\u5BB9 / project=\u9879\u76EE\u7EA7\u4EC5\u7ED1\u5B9A\u9879\u76EE\u8BFB\u5199+\u5168\u5C40\u8D44\u4EA7\u53EA\u8BFB / none=\u672A\u914D\u7F6E\u51ED\u8BC1\u6216\u76EE\u6807 server \u9274\u6743\u672A\u5F00\u542F\uFF09+ project\uFF08\u4EC5 project \u8EAB\u4EFD\uFF1A\u7ED1\u5B9A\u9879\u76EE id/key/name\uFF09+ authEnabled\uFF08\u76EE\u6807 server \u9274\u6743\u5F00\u5173\uFF09+ server.url\u3002\u9644\u5E26\u672C\u5730\u51ED\u8BC1\u8BCA\u65AD\uFF1AlocalToken\uFF08\u751F\u6548 Token \u7EA7\u522B\uFF1Aadmin/project/none\uFF09+ localTokenSource\uFF08\u751F\u6548\u6765\u6E90\u5C42\uFF1Aworkspace=\u5DE5\u4F5C\u533A .siming/dev.json / global=\u7528\u6237\u7EA7\u5168\u5C40 ~/.siming/auth.json / env=SIMING_TOKEN \u73AF\u5883\u53D8\u91CF / none=\u672A\u914D\u7F6E\uFF1B\u4F18\u5148\u7EA7 workspace > global > env\uFF09\u3002\u7528\u4E8E AI \u5224\u65AD\u81EA\u8EAB\u6743\u9650\u8FB9\u754C\uFF1Aproject \u8EAB\u4EFD\u4E0D\u5F97\u64CD\u4F5C\u5176\u4ED6\u9879\u76EE\u4E0E\u5168\u5C40\u8D44\u4EA7\u5199\u3001admin \u8EAB\u4EFD\u5168\u6743\u3001none \u4E14 authEnabled=true \u65F6\u4E00\u5207\u6570\u636E\u64CD\u4F5C\u5C06 401\u3002\u672C\u5DE5\u5177\u4E0D\u8FD4\u56DE Token \u672C\u8EAB\uFF1BToken \u7531\u7528\u6237\u914D\u7F6E\uFF08\u4F18\u5148 siming auth token set --global \u672C\u673A\u4E00\u6B21\u5168\u5DE5\u4F5C\u533A/\u5BBF\u4E3B\u5F62\u6001\u590D\u7528\uFF0C\u6216\u5DE5\u4F5C\u533A siming auth token set\uFF09\uFF0C\u5BA2\u6237\u7AEF\u81EA\u52A8\u643A\u5E26\u3002\u4FEE\u590D\u6307\u5F15\uFF1AWeb \u7BA1\u7406\u53F0\u751F\u6210 Token \u540E\u7531\u7528\u6237\u6267\u884C\u4E0A\u8FF0\u547D\u4EE4\u914D\u7F6E\u3002`,
|
|
@@ -2096,7 +2221,7 @@ function parseRefFlags(refs, mainDocName) {
|
|
|
2096
2221
|
var PAGE_DEFAULT = 20;
|
|
2097
2222
|
var PAGE_MAX = 500;
|
|
2098
2223
|
function createTaskCommand() {
|
|
2099
|
-
const task = new Command2("task").description("Task management \u2014 create, advance, approve, pause, resume, cancel, query");
|
|
2224
|
+
const task = new Command2("task").description("Task management \u2014 create, advance, approve, pause, resume, cancel, reopen, query");
|
|
2100
2225
|
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) => {
|
|
2101
2226
|
const client = createClient(opts.url);
|
|
2102
2227
|
const filters = {};
|
|
@@ -2229,9 +2354,9 @@ function createTaskCommand() {
|
|
|
2229
2354
|
}
|
|
2230
2355
|
renderResult("json", result);
|
|
2231
2356
|
});
|
|
2232
|
-
task.command("advance <taskId>").description("Advance a task to the next node (record contents already written via `task record/doc`; this is the light finish)").option("--url <url>", "server base URL").option("--format <fmt>", "output format", "json").option("--note <text>", "advance note recorded in history").option("--summary <text>", "finishing summary written to nodeRecords.<node>.summary (equivalent to a final `record set --summary`)").action(async (taskId, opts) => {
|
|
2357
|
+
task.command("advance <taskId>").description("Advance a task to the next node (record contents already written via `task record/doc`; this is the light finish). At the final node the advance is rejected unless --finalize is passed (completion confirmation)").option("--url <url>", "server base URL").option("--format <fmt>", "output format", "json").option("--note <text>", "advance note recorded in history").option("--summary <text>", "finishing summary written to nodeRecords.<node>.summary (equivalent to a final `record set --summary`)").option("--finalize", "completion confirmation: finalize the task at its final node (required there; ignored mid-flow)").action(async (taskId, opts) => {
|
|
2233
2358
|
const client = createClient(opts.url);
|
|
2234
|
-
const result = await handleAdvance(client, taskId, opts.note, opts.summary);
|
|
2359
|
+
const result = await handleAdvance(client, taskId, opts.note, opts.summary, opts.finalize === true);
|
|
2235
2360
|
renderResult(opts.format, result);
|
|
2236
2361
|
});
|
|
2237
2362
|
task.command("approve <taskId>").description("Approve or reject a task paused at a human_approval pause point").option("--url <url>", "server base URL").option("--format <fmt>", "output format", "json").requiredOption("--decision <d>", "decision: approved|rejected").option("--comment <text>", "decision comment recorded in history").action(async (taskId, opts) => {
|
|
@@ -2339,11 +2464,16 @@ function createTaskCommand() {
|
|
|
2339
2464
|
const result = await handleResume(client, taskId, opts.decision);
|
|
2340
2465
|
renderResult("json", result);
|
|
2341
2466
|
});
|
|
2342
|
-
task.command("cancel <taskId>").description("Cancel a task (active/paused \u2192 cancelled terminal state
|
|
2467
|
+
task.command("cancel <taskId>").description("Cancel a task (active/paused \u2192 cancelled terminal state; can be reopened)").option("--url <url>", "server base URL").option("--reason <text>", "cancel reason (1-500 chars)").action(async (taskId, opts) => {
|
|
2343
2468
|
const client = createClient(opts.url);
|
|
2344
2469
|
const result = await handleCancel(client, taskId, opts.reason);
|
|
2345
2470
|
renderResult("json", result);
|
|
2346
2471
|
});
|
|
2472
|
+
task.command("reopen <taskId>").description("Reopen a terminated task (completed/cancelled \u2192 restore pre-termination state; all records preserved). At a pause-point pause the task returns to pending-approval").option("--url <url>", "server base URL").requiredOption("--reason <text>", "reopen reason (1-500 chars, recorded in history)").action(async (taskId, opts) => {
|
|
2473
|
+
const client = createClient(opts.url);
|
|
2474
|
+
const result = await handleReopen(client, taskId, opts.reason);
|
|
2475
|
+
renderResult("json", result);
|
|
2476
|
+
});
|
|
2347
2477
|
task.command("history <taskId>").description("Show task node history").option("--url <url>", "server base URL").option("--format <fmt>", "output format", "table").action(async (taskId, opts) => {
|
|
2348
2478
|
const client = createClient(opts.url);
|
|
2349
2479
|
const result = await handleGetHistory(client, taskId);
|
|
@@ -6646,6 +6776,7 @@ function permissionsToMatrix(permissions) {
|
|
|
6646
6776
|
var AGENT_INFO_BOUNDARY = "\u4EFB\u52A1\u4F9D\u636E\u9650\u4E8E\u9879\u76EE\u4EE3\u7801\u3001\u8BBE\u8BA1\u6587\u6863/\u6267\u884C\u62A5\u544A\u53CA\u4EFB\u52A1\u4E0A\u4E0B\u6587\uFF08\u542B\u4EFB\u52A1\u4FE1\u606F\u3001\u63D0\u793A\u8BCD\u3001\u59D4\u6D3E\u6750\u6599\uFF09\uFF1B\u7981\u6B62\u81EA\u884C\u8BFB\u53D6\u65E5\u5FD7\u3001\u4E34\u65F6\u6587\u4EF6\u7B49\u8FC7\u7A0B\u4EA7\u7269\uFF0C\u7981\u6B62\u81EA\u884C\u6267\u884C\u6D4B\u8BD5\u3001\u547D\u4EE4\u6216\u5176\u4ED6\u64CD\u4F5C\uFF0C\u59D4\u6D3E\u4EFB\u52A1\u660E\u786E\u8981\u6C42\u65F6\u9664\u5916\u3002";
|
|
6647
6777
|
function agentToMarkdown(agent, realModel) {
|
|
6648
6778
|
const fm = {
|
|
6779
|
+
name: agent.name,
|
|
6649
6780
|
description: agent.description,
|
|
6650
6781
|
mode: "subagent",
|
|
6651
6782
|
model: realModel,
|
|
@@ -7119,7 +7250,7 @@ function buildInstallGuidance(scope, targets) {
|
|
|
7119
7250
|
if (targets.mcpConfigPath) {
|
|
7120
7251
|
lines.push(` - MCP \u6CE8\u518C: ${targets.mcpConfigPath}\uFF08\u9876\u5C42 mcpServers.siming \u2192 stdio \u547D\u4EE4 "siming mcp-serve"\uFF09`);
|
|
7121
7252
|
}
|
|
7122
|
-
lines.push("[2] \u5F15\u7528\u65B9\u5F0F\uFF1Askill = \u5B50\u76EE\u5F55\u5185 SKILL.md\uFF08frontmatter name/description\uFF09\uFF1Bagent = \u5B50\u76EE\u5F55\u5185 agent.md\uFF08frontmatter description/model/skills\uFF0C\u6B63\u6587\u542B\u7ED1\u5B9A Skill \u52A0\u8F7D\u6307\u4EE4\uFF09\uFF1B\u5E26\u5F15\u7528\u6587\u6863\u7684\u8D44\u4EA7\uFF0C\u4E3B\u6587\u6863\u4E2D\u7684\u76F8\u5BF9\u8DEF\u5F84\u5F15\u7528\u5728\u5B50\u76EE\u5F55\u5185\u76F4\u63A5\u53EF\u8FBE\u3002");
|
|
7253
|
+
lines.push("[2] \u5F15\u7528\u65B9\u5F0F\uFF1Askill = \u5B50\u76EE\u5F55\u5185 SKILL.md\uFF08frontmatter name/description\uFF09\uFF1Bagent = \u5B50\u76EE\u5F55\u5185 agent.md\uFF08frontmatter name/description/model/skills\uFF0C\u6B63\u6587\u542B\u7ED1\u5B9A Skill \u52A0\u8F7D\u6307\u4EE4\uFF09\uFF1B\u5E26\u5F15\u7528\u6587\u6863\u7684\u8D44\u4EA7\uFF0C\u4E3B\u6587\u6863\u4E2D\u7684\u76F8\u5BF9\u8DEF\u5F84\u5F15\u7528\u5728\u5B50\u76EE\u5F55\u5185\u76F4\u63A5\u53EF\u8FBE\u3002");
|
|
7123
7254
|
const mcpPart = targets.mcpConfigPath ? "\uFF1B\u628A mcpServers.siming \u6761\u76EE\u5408\u5E76\u8FDB\u672C\u5DE5\u5177\u7684 MCP \u914D\u7F6E" : "\uFF08\u9879\u76EE\u7EA7\u5B89\u88C5\u4E0D\u542B MCP \u6CE8\u518C\uFF0C\u9700\u8981\u65F6\u53E6\u884C\u6267\u884C\u7528\u6237\u7EA7 install\uFF09";
|
|
7124
7255
|
lines.push(`[3] \u6CE8\u518C\u9014\u5F84\uFF08\u5F53\u524D\u7F16\u7A0B\u5DE5\u5177\u4F1A\u8BDD\u4E2D\u7684 AI \u53EF\u76F4\u63A5\u6267\u884C\uFF09\uFF1A\u628A skills \u5B50\u76EE\u5F55\u52A0\u5165\u672C\u5DE5\u5177\u7684 skill \u641C\u7D22\u8DEF\u5F84\uFF1B\u628A agent \u5B50\u76EE\u5F55\u6CE8\u518C\u8FDB\u672C\u5DE5\u5177\u7684 subagent \u914D\u7F6E${mcpPart}\u3002`);
|
|
7125
7256
|
if (targets.mcpConfigPath) {
|
|
@@ -8332,10 +8463,259 @@ function reportPortConflict(port) {
|
|
|
8332
8463
|
);
|
|
8333
8464
|
}
|
|
8334
8465
|
|
|
8335
|
-
// src/commands/
|
|
8466
|
+
// src/commands/issue/command.ts
|
|
8336
8467
|
import { Command as Command18 } from "commander";
|
|
8468
|
+
import { z as z7 } from "zod";
|
|
8469
|
+
import { TASK_TYPES as TASK_TYPES3 } from "@siming-org/core";
|
|
8470
|
+
var PAGE_DEFAULT2 = 20;
|
|
8471
|
+
var PAGE_MAX2 = 500;
|
|
8472
|
+
function renderProgress(row) {
|
|
8473
|
+
if (row.progress.total === 0) return "\u2014";
|
|
8474
|
+
return `${String(row.progress.done)}/${String(row.progress.cancelled)}/${String(row.progress.total)}`;
|
|
8475
|
+
}
|
|
8476
|
+
function parseDeclarationsMap(spec) {
|
|
8477
|
+
const out = {};
|
|
8478
|
+
for (const part of spec.split(",")) {
|
|
8479
|
+
const trimmed = part.trim();
|
|
8480
|
+
if (trimmed.length === 0) continue;
|
|
8481
|
+
const at = trimmed.indexOf(":");
|
|
8482
|
+
if (at <= 0 || at === trimmed.length - 1) {
|
|
8483
|
+
return { error: `--declarations \u6761\u76EE "${trimmed}" \u975E\u6CD5\uFF08\u683C\u5F0F id1:all,id2:partial\uFF09` };
|
|
8484
|
+
}
|
|
8485
|
+
const issueId = trimmed.slice(0, at);
|
|
8486
|
+
const mode = trimmed.slice(at + 1);
|
|
8487
|
+
if (mode !== "all" && mode !== "partial") {
|
|
8488
|
+
return { error: `--declarations \u58F0\u660E\u503C "${mode}" \u975E\u6CD5\uFF08\u5408\u6CD5\u503C\uFF1Aall|partial\uFF09` };
|
|
8489
|
+
}
|
|
8490
|
+
out[issueId] = mode;
|
|
8491
|
+
}
|
|
8492
|
+
return out;
|
|
8493
|
+
}
|
|
8494
|
+
function createIssueCommand() {
|
|
8495
|
+
const issue = new Command18("issue").description("Issue pool: record \u2192 organize \u2192 convert to tasks");
|
|
8496
|
+
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) => {
|
|
8497
|
+
const client = createClient(opts.url);
|
|
8498
|
+
const title = opts.title ?? titleArg;
|
|
8499
|
+
if (title === void 0 || title.length === 0) {
|
|
8500
|
+
renderResult("json", {
|
|
8501
|
+
success: false,
|
|
8502
|
+
error: { message: "issue add \u9700\u8981\u6807\u9898\uFF08\u4F4D\u7F6E\u53C2\u6570\u6216 --title\uFF09", httpStatus: 0 }
|
|
8503
|
+
});
|
|
8504
|
+
return;
|
|
8505
|
+
}
|
|
8506
|
+
let projectId;
|
|
8507
|
+
if (opts.project) {
|
|
8508
|
+
const r = await resolveProjectId(client, opts.project);
|
|
8509
|
+
if (!r.success) {
|
|
8510
|
+
renderResult("json", r);
|
|
8511
|
+
return;
|
|
8512
|
+
}
|
|
8513
|
+
projectId = r.data;
|
|
8514
|
+
} else {
|
|
8515
|
+
const wsDefaultProject = readWorkspaceConfig()?.defaultProject;
|
|
8516
|
+
if (wsDefaultProject) {
|
|
8517
|
+
const r = await resolveProjectId(client, wsDefaultProject);
|
|
8518
|
+
if (r.success) projectId = r.data;
|
|
8519
|
+
}
|
|
8520
|
+
}
|
|
8521
|
+
const result = await handleCreateIssue(client, {
|
|
8522
|
+
title,
|
|
8523
|
+
...opts.description !== void 0 ? { description: opts.description } : {},
|
|
8524
|
+
...projectId !== void 0 ? { projectId } : {}
|
|
8525
|
+
});
|
|
8526
|
+
renderResult(opts.format ?? "fancy", result);
|
|
8527
|
+
});
|
|
8528
|
+
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) => {
|
|
8529
|
+
const client = createClient(opts.url);
|
|
8530
|
+
const filters = {};
|
|
8531
|
+
if (opts.status) filters.status = opts.status;
|
|
8532
|
+
if (opts.source) filters.source = opts.source;
|
|
8533
|
+
if (opts.task) filters.taskId = opts.task;
|
|
8534
|
+
if (opts.q) filters.q = opts.q;
|
|
8535
|
+
if (opts.view) {
|
|
8536
|
+
const r = parseEnum(opts.view, z7.enum(["all", "open"]), "view");
|
|
8537
|
+
if (!r.success) {
|
|
8538
|
+
renderResult(opts.format ?? "table", r);
|
|
8539
|
+
return;
|
|
8540
|
+
}
|
|
8541
|
+
filters.view = r.data;
|
|
8542
|
+
}
|
|
8543
|
+
if (opts.project) {
|
|
8544
|
+
const r = await resolveProjectId(client, opts.project);
|
|
8545
|
+
if (!r.success) {
|
|
8546
|
+
renderResult(opts.format ?? "table", r);
|
|
8547
|
+
return;
|
|
8548
|
+
}
|
|
8549
|
+
filters.projectId = r.data;
|
|
8550
|
+
}
|
|
8551
|
+
if (opts.all) {
|
|
8552
|
+
filters.limit = PAGE_MAX2;
|
|
8553
|
+
} else {
|
|
8554
|
+
const pageR = parseEnum(opts.page ?? "1", z7.coerce.number().int().min(1), "page");
|
|
8555
|
+
if (!pageR.success) {
|
|
8556
|
+
renderResult(opts.format ?? "table", pageR);
|
|
8557
|
+
return;
|
|
8558
|
+
}
|
|
8559
|
+
filters.page = pageR.data;
|
|
8560
|
+
const limitR = parseEnum(opts.limit ?? String(PAGE_DEFAULT2), z7.coerce.number().int().min(1).max(PAGE_MAX2), "limit");
|
|
8561
|
+
if (!limitR.success) {
|
|
8562
|
+
renderResult(opts.format ?? "table", limitR);
|
|
8563
|
+
return;
|
|
8564
|
+
}
|
|
8565
|
+
filters.limit = limitR.data;
|
|
8566
|
+
}
|
|
8567
|
+
const result = await handleListIssues(client, filters);
|
|
8568
|
+
if (!result.success) {
|
|
8569
|
+
renderResult(opts.format ?? "table", result);
|
|
8570
|
+
return;
|
|
8571
|
+
}
|
|
8572
|
+
if (opts.format === "json") {
|
|
8573
|
+
renderResult("json", result, {});
|
|
8574
|
+
} else {
|
|
8575
|
+
renderResult(opts.format ?? "table", { success: true, data: result.data.items }, {
|
|
8576
|
+
columns: [
|
|
8577
|
+
{ key: "issueId", header: "Issue ID" },
|
|
8578
|
+
{ key: "title", header: "Title", maxWidth: 32 },
|
|
8579
|
+
{ key: "status", header: "Status" },
|
|
8580
|
+
{ key: "source", header: "Source" },
|
|
8581
|
+
{
|
|
8582
|
+
key: "taskLinks",
|
|
8583
|
+
header: "Tasks",
|
|
8584
|
+
render: (row) => String(row.taskLinks.length)
|
|
8585
|
+
},
|
|
8586
|
+
{
|
|
8587
|
+
key: "progress",
|
|
8588
|
+
header: "Progress (done/cancelled/total)",
|
|
8589
|
+
render: (row) => renderProgress(row)
|
|
8590
|
+
},
|
|
8591
|
+
{
|
|
8592
|
+
key: "updatedAt",
|
|
8593
|
+
header: "Updated",
|
|
8594
|
+
render: (row) => {
|
|
8595
|
+
const at = row.updatedAt;
|
|
8596
|
+
return at === void 0 ? "\u2014" : new Date(at).toLocaleString();
|
|
8597
|
+
}
|
|
8598
|
+
}
|
|
8599
|
+
]
|
|
8600
|
+
});
|
|
8601
|
+
console.log(`total: ${String(result.data.total)}\uFF08page ${String(result.data.page)}, limit ${String(result.data.limit)}\uFF09`);
|
|
8602
|
+
}
|
|
8603
|
+
});
|
|
8604
|
+
withCommonOpts(issue.command("show"), "fancy").argument("<issueId>", "issue id (I-prefixed)").description("Show issue detail (progress + linked task snapshots + history)").action(async (issueId, opts) => {
|
|
8605
|
+
const client = createClient(opts.url);
|
|
8606
|
+
const result = await handleGetIssue(client, issueId);
|
|
8607
|
+
renderResult(opts.format ?? "fancy", result);
|
|
8608
|
+
});
|
|
8609
|
+
withCommonOpts(issue.command("update"), "fancy").argument("<issueId>", "issue id").option("--title <t>", "new title").option("--description <d>", "new description").description("Update issue title/description (allowed in any status)").action(async (issueId, opts) => {
|
|
8610
|
+
const client = createClient(opts.url);
|
|
8611
|
+
if (opts.title === void 0 && opts.description === void 0) {
|
|
8612
|
+
renderResult("json", {
|
|
8613
|
+
success: false,
|
|
8614
|
+
error: { message: "issue update \u9700\u8981\u81F3\u5C11\u4E00\u4E2A\u53EF\u66F4\u65B0\u5B57\u6BB5\uFF08--title / --description\uFF09", httpStatus: 0 }
|
|
8615
|
+
});
|
|
8616
|
+
return;
|
|
8617
|
+
}
|
|
8618
|
+
const result = await handleUpdateIssue(client, issueId, {
|
|
8619
|
+
...opts.title !== void 0 ? { title: opts.title } : {},
|
|
8620
|
+
...opts.description !== void 0 ? { description: opts.description } : {}
|
|
8621
|
+
});
|
|
8622
|
+
renderResult(opts.format ?? "fancy", result);
|
|
8623
|
+
});
|
|
8624
|
+
withCommonOpts(issue.command("cancel"), "fancy").argument("<issueId>", "issue id").option("--reason <r>", "cancel reason (optional, \u2264500 chars)").description("Cancel an issue (terminal state; active links recorded in history)").action(async (issueId, opts) => {
|
|
8625
|
+
const client = createClient(opts.url);
|
|
8626
|
+
const result = await handleCancelIssue(client, issueId, opts.reason);
|
|
8627
|
+
renderResult(opts.format ?? "fancy", result);
|
|
8628
|
+
});
|
|
8629
|
+
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) => {
|
|
8630
|
+
const client = createClient(opts.url);
|
|
8631
|
+
const issueIds = [
|
|
8632
|
+
...new Set((opts.issueIds ?? []).flatMap((s) => s.split(",")).map((s) => s.trim()).filter((s) => s.length > 0))
|
|
8633
|
+
];
|
|
8634
|
+
if (issueIds.length === 0) {
|
|
8635
|
+
renderResult("json", {
|
|
8636
|
+
success: false,
|
|
8637
|
+
error: { message: "issue convert \u9700\u8981 --issue-ids\uFF08\u9017\u53F7\u5206\u9694\u7684\u95EE\u9898 id \u6E05\u5355\uFF09", httpStatus: 0 }
|
|
8638
|
+
});
|
|
8639
|
+
return;
|
|
8640
|
+
}
|
|
8641
|
+
let declarations = {};
|
|
8642
|
+
if (opts.declarations) {
|
|
8643
|
+
const parsed = parseDeclarationsMap(opts.declarations);
|
|
8644
|
+
if ("error" in parsed) {
|
|
8645
|
+
renderResult("json", { success: false, error: { message: parsed.error, httpStatus: 0 } });
|
|
8646
|
+
return;
|
|
8647
|
+
}
|
|
8648
|
+
declarations = parsed;
|
|
8649
|
+
} else if (opts.declaration) {
|
|
8650
|
+
const r = parseEnum(opts.declaration, z7.enum(["all", "partial"]), "declaration");
|
|
8651
|
+
if (!r.success) {
|
|
8652
|
+
renderResult(opts.format ?? "fancy", r);
|
|
8653
|
+
return;
|
|
8654
|
+
}
|
|
8655
|
+
declarations = Object.fromEntries(issueIds.map((id) => [id, r.data]));
|
|
8656
|
+
} else {
|
|
8657
|
+
declarations = Object.fromEntries(issueIds.map((id) => [id, "all"]));
|
|
8658
|
+
}
|
|
8659
|
+
let projectId;
|
|
8660
|
+
if (opts.project) {
|
|
8661
|
+
const r = await resolveProjectId(client, opts.project);
|
|
8662
|
+
if (!r.success) {
|
|
8663
|
+
renderResult(opts.format ?? "fancy", r);
|
|
8664
|
+
return;
|
|
8665
|
+
}
|
|
8666
|
+
projectId = r.data;
|
|
8667
|
+
} else {
|
|
8668
|
+
const first = await handleGetIssue(client, issueIds[0]);
|
|
8669
|
+
if (!first.success) {
|
|
8670
|
+
renderResult(opts.format ?? "fancy", first);
|
|
8671
|
+
return;
|
|
8672
|
+
}
|
|
8673
|
+
projectId = first.data.projectId;
|
|
8674
|
+
}
|
|
8675
|
+
let type;
|
|
8676
|
+
if (opts.type !== void 0) {
|
|
8677
|
+
const r = parseEnum(opts.type, z7.enum(TASK_TYPES3), "type");
|
|
8678
|
+
if (!r.success) {
|
|
8679
|
+
renderResult(opts.format ?? "fancy", r);
|
|
8680
|
+
return;
|
|
8681
|
+
}
|
|
8682
|
+
type = r.data;
|
|
8683
|
+
}
|
|
8684
|
+
let skipNodes;
|
|
8685
|
+
if (opts.skip !== void 0 && opts.skip.length > 0) {
|
|
8686
|
+
skipNodes = [...new Set(opts.skip.flatMap((s) => s.split(",")).map((s) => s.trim()).filter((s) => s.length > 0))];
|
|
8687
|
+
}
|
|
8688
|
+
let templateRef = opts.template;
|
|
8689
|
+
if (!/^[0-9a-f]{24}$/.test(templateRef)) {
|
|
8690
|
+
const listR = await handleListTemplates(client, projectId);
|
|
8691
|
+
if (!listR.success) {
|
|
8692
|
+
renderResult(opts.format ?? "fancy", listR);
|
|
8693
|
+
return;
|
|
8694
|
+
}
|
|
8695
|
+
const hit = listR.data.find((t) => t.code === templateRef) ?? listR.data.find((t) => t.name === templateRef);
|
|
8696
|
+
templateRef = hit?.id ?? templateRef;
|
|
8697
|
+
}
|
|
8698
|
+
const result = await handleConvertIssues(client, {
|
|
8699
|
+
projectId,
|
|
8700
|
+
declarations,
|
|
8701
|
+
issueIds,
|
|
8702
|
+
task: {
|
|
8703
|
+
title: opts.title,
|
|
8704
|
+
track: opts.track,
|
|
8705
|
+
dagTemplateId: templateRef,
|
|
8706
|
+
...skipNodes !== void 0 && skipNodes.length > 0 ? { skipNodes } : {},
|
|
8707
|
+
...type !== void 0 ? { type } : {}
|
|
8708
|
+
}
|
|
8709
|
+
});
|
|
8710
|
+
renderResult(opts.format ?? "fancy", result);
|
|
8711
|
+
});
|
|
8712
|
+
return issue;
|
|
8713
|
+
}
|
|
8714
|
+
|
|
8715
|
+
// src/commands/auth/command.ts
|
|
8716
|
+
import { Command as Command19 } from "commander";
|
|
8337
8717
|
function createAuthCommand() {
|
|
8338
|
-
const cmd = new
|
|
8718
|
+
const cmd = new Command19("auth").description("\u8EAB\u4EFD\u67E5\u8BE2\u4E0E\u672C\u5730 Token \u914D\u7F6E\uFF08AI \u51ED\u6B64\u5224\u65AD\u6743\u9650\u8FB9\u754C\uFF1BToken \u503C\u4E0D\u56DE\u663E\uFF09");
|
|
8339
8719
|
withCommonOpts(
|
|
8340
8720
|
cmd.command("whoami").description("\u67E5\u8BE2\u5F53\u524D\u8EAB\u4EFD\uFF08admin / project:<\u9879\u76EE> / \u672A\u914D\u7F6E\uFF09+ \u76EE\u6807 server \u9274\u6743\u5F00\u5173\u72B6\u6001"),
|
|
8341
8721
|
"fancy"
|
|
@@ -8399,7 +8779,7 @@ function tokenSourceLabel(source) {
|
|
|
8399
8779
|
}
|
|
8400
8780
|
|
|
8401
8781
|
// src/index.ts
|
|
8402
|
-
var program = new
|
|
8782
|
+
var program = new Command20();
|
|
8403
8783
|
program.name("siming").description("\u53F8\u547D \xB7 Siming \u2014 AI coding workflow management platform").version(VERSION5);
|
|
8404
8784
|
program.command("healthcheck").description("Check if the siming server is reachable").option("--url <url>", "server base URL").action(async (opts) => {
|
|
8405
8785
|
await healthcheckCommand(opts);
|
|
@@ -8408,6 +8788,7 @@ program.command("mcp-serve").description("Start MCP server over stdio (for AI ag
|
|
|
8408
8788
|
await mcpServeCommand();
|
|
8409
8789
|
});
|
|
8410
8790
|
program.addCommand(createTaskCommand());
|
|
8791
|
+
program.addCommand(createIssueCommand());
|
|
8411
8792
|
program.addCommand(createSkillCommand());
|
|
8412
8793
|
program.addCommand(createAgentCommand());
|
|
8413
8794
|
program.addCommand(createDagCommand());
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@siming-org/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Wuchao",
|
|
6
6
|
"engines": {
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
"picocolors": "^1.1.1",
|
|
28
28
|
"yaml": "^2.6.0",
|
|
29
29
|
"zod": "^4.4.3",
|
|
30
|
-
"@siming-org/
|
|
31
|
-
"@siming-org/
|
|
30
|
+
"@siming-org/core": "0.7.0",
|
|
31
|
+
"@siming-org/server": "0.7.0"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"tsup": "^8.3.5",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"exportFormatVersion": "1.0",
|
|
3
|
-
"exportedAt": "2026-09-
|
|
3
|
+
"exportedAt": "2026-09-15T08:13:01.500Z",
|
|
4
4
|
"warnings": [],
|
|
5
5
|
"template": {
|
|
6
6
|
"name": "full_workflow",
|
|
@@ -138,7 +138,7 @@
|
|
|
138
138
|
"label": "视觉验证",
|
|
139
139
|
"phase": "track",
|
|
140
140
|
"track": "ui",
|
|
141
|
-
"prompt": "# 视觉验证\n\n## 节点职责\n\n运行当前界面并通过浏览器完成验收路径,验证功能结果、采集视觉证据,再根据独立 `visual-reviewer` 的评审结果完成修复和回归。本节点负责运行、操作、采证和流程收敛,不代替 Agent 判断视觉质量。\n\n## 依赖信息\n\n先检查当前任务上下文,读取需求、验收标准、技术方案、前端实现记录,以及项目和所属模块的提示词。存在交互契约产物时,读取契约并将其自检清单与验收点作为验证清单的底座;无契约时以验收标准为底座。加载 `workflow-discipline`,调用独立 `visual-reviewer` 评审视觉证据。\n\n根据需求整理待验证页面、用户路径、需要呈现的状态和代表性视口。缺少运行方式、访问地址、认证或数据准备信息时,先从项目脚本、配置和现有环境中查找;仍无法运行当前实现时,说明缺失信息并暂停。\n\n## 执行流程\n\n1. 按项目声明启动当前实现及其依赖服务,确认页面对应本次代码。\n2. 使用浏览器自动化能力执行需求涉及的真实用户路径,验证操作后的页面结果、请求结果、反馈、错误处理和持久化后的重新加载结果。\n3. 检查浏览器控制台中的新增错误、失败请求和其他运行异常。\n4. 按验收范围触发适用的加载、空、错误、成功和关键交互状态,并在代表性视口采集截图、视频或等价原始证据;有交互契约时按契约条款逐项触发与核对,证据覆盖契约验收点;不在本节点预判视觉结论。\n5. 将需求、设计规范、场景说明、视口信息和原始证据交给 `visual-reviewer
|
|
141
|
+
"prompt": "# 视觉验证\n\n## 节点职责\n\n运行当前界面并通过浏览器完成验收路径,验证功能结果、采集视觉证据,再根据独立 `visual-reviewer` 的评审结果完成修复和回归。本节点负责运行、操作、采证和流程收敛,不代替 Agent 判断视觉质量。\n\n## 依赖信息\n\n先检查当前任务上下文,读取需求、验收标准、技术方案、前端实现记录,以及项目和所属模块的提示词。存在交互契约产物时,读取契约并将其自检清单与验收点作为验证清单的底座;无契约时以验收标准为底座。加载 `workflow-discipline`,调用独立 `visual-reviewer` 评审视觉证据。\n\n根据需求整理待验证页面、用户路径、需要呈现的状态和代表性视口。缺少运行方式、访问地址、认证或数据准备信息时,先从项目脚本、配置和现有环境中查找;仍无法运行当前实现时,说明缺失信息并暂停。\n\n## 执行流程\n\n1. 按项目声明启动当前实现及其依赖服务,确认页面对应本次代码。\n2. 使用浏览器自动化能力执行需求涉及的真实用户路径,验证操作后的页面结果、请求结果、反馈、错误处理和持久化后的重新加载结果。\n3. 检查浏览器控制台中的新增错误、失败请求和其他运行异常。\n4. 按验收范围触发适用的加载、空、错误、成功和关键交互状态,并在代表性视口采集截图、视频或等价原始证据;有交互契约时按契约条款逐项触发与核对,证据覆盖契约验收点;不在本节点预判视觉结论。\n5. 将需求、设计规范、场景说明、视口信息和原始证据交给 `visual-reviewer`;交互契约(如有)随需求与设计规范一并作为评审材料移交,不提供实现者结论或预期缺陷。\n6. 修复功能验证失败项以及 `visual-reviewer` 报告的 BLOCKER、HIGH Findings,然后重新执行受影响路径、采集同场景证据并再次评审,直至功能验证通过且视觉评审为 PASS。MEDIUM、LOW 逐项处理或记录保留理由。\n7. 清理本次创建的临时数据和运行资源,不删除非本次创建的数据。\n\n## 产出与检查\n\n推进前确认:\n\n- 需求涉及的用户路径已通过真实浏览器操作验证,并观察到最终结果;\n- 页面结果、请求、反馈、错误处理、持久化和控制台均无未解决的严重问题;\n- 验收所需状态与视口已呈现,原始证据对应当前实现且可追溯;\n- `visual-reviewer` 最终结论为 PASS,所有 Findings 均已处理或说明;\n- 修复后的受影响路径已重新验证并重新采证;\n- 临时数据和运行资源已按项目规则清理。\n\n## 任务差异处理\n\n根据需求和页面能力选择用户路径、状态、视口与证据,不套用固定 CRUD 或截图数量。某项不适用时说明理由,不得静默跳过。完全无法运行当前实现,或修复需要改变已确认需求、设计方向、公开契约或引入新依赖时,说明影响并暂停;验证与修订轮次按 `workflow-discipline` 处理。\n\n## 节点记录与推进\n\n将功能验证结论、已覆盖的用户路径、状态与视口、请求和控制台结果、原始证据引用、缺陷修复、未适用项及理由、`visual-reviewer` 结论与 Findings 处理情况写入当前节点记录。完成上述检查后推进下一节点。",
|
|
142
142
|
"skills": [
|
|
143
143
|
"workflow-discipline"
|
|
144
144
|
],
|
|
@@ -147,8 +147,8 @@
|
|
|
147
147
|
],
|
|
148
148
|
"sourcePreset": {
|
|
149
149
|
"code": "verify-visual",
|
|
150
|
-
"version": "1.4.
|
|
151
|
-
"contentHash": "
|
|
150
|
+
"version": "1.4.1",
|
|
151
|
+
"contentHash": "a959a6617abf83fb",
|
|
152
152
|
"agents": [
|
|
153
153
|
"visual-reviewer"
|
|
154
154
|
]
|
|
@@ -159,7 +159,7 @@
|
|
|
159
159
|
"label": "单元测试设计",
|
|
160
160
|
"phase": "test",
|
|
161
161
|
"track": "backend",
|
|
162
|
-
"prompt": "# 单元测试设计\n\n## 节点职责\n\n为本次生产代码设计可执行的单元测试计划,明确测什么、为什么测以及预期什么。本节点只产出测试设计,不编写或执行测试代码,并通过独立 `test-reviewer` 评审设计质量。\n\n## 依赖信息\n\n先检查当前任务上下文,读取需求、验收标准、非目标、技术方案、生产代码变更、编码决策,以及项目和所属模块的测试约束。加载 `workflow-discipline`,调用独立 `test-reviewer` 评审测试设计。\n\n读取现有测试目录、配置和相关用例,确认测试框架、命名、替身边界、覆盖要求及与其他测试层级的分工。信息缺失时先从仓库现状推导;仍无法确定关键行为或测试边界时,说明缺失信息并暂停。\n\n## 执行流程\n\n1. 从需求、技术方案和生产代码整理本次需要验证的行为单元,明确输入、输出、状态变化、错误和副作用。\n2. 为每个行为单元设计正常、边界和失败场景,并按实际行为补充状态恢复、幂等、重试、权限、并发或资源生命周期场景;不适用项无需制造用例。\n3. 为每个用例写明优先级、前置条件、输入、替身或数据准备、操作、观察点、预期结果及覆盖的行为或分支,使后续实现者无需猜测测试意图。\n4. 明确哪些依赖使用真实实现、替身或受控环境,避免过度 Mock 掩盖业务行为,也避免把跨系统路径误当单元测试。\n5.
|
|
162
|
+
"prompt": "# 单元测试设计\n\n## 节点职责\n\n为本次生产代码设计可执行的单元测试计划,明确测什么、为什么测以及预期什么。本节点只产出测试设计,不编写或执行测试代码,并通过独立 `test-reviewer` 评审设计质量。\n\n## 依赖信息\n\n先检查当前任务上下文,读取需求、验收标准、非目标、技术方案、生产代码变更、编码决策,以及项目和所属模块的测试约束。加载 `workflow-discipline`,调用独立 `test-reviewer` 评审测试设计。\n\n读取现有测试目录、配置和相关用例,确认测试框架、命名、替身边界、覆盖要求及与其他测试层级的分工。信息缺失时先从仓库现状推导;仍无法确定关键行为或测试边界时,说明缺失信息并暂停。\n\n## 执行流程\n\n1. 从需求、技术方案和生产代码整理本次需要验证的行为单元,明确输入、输出、状态变化、错误和副作用。\n2. 为每个行为单元设计正常、边界和失败场景,并按实际行为补充状态恢复、幂等、重试、权限、并发或资源生命周期场景;不适用项无需制造用例。\n3. 为每个用例写明优先级、前置条件、输入、替身或数据准备、操作、观察点、预期结果及覆盖的行为或分支,使后续实现者无需猜测测试意图。\n4. 明确哪些依赖使用真实实现、替身或受控环境,避免过度 Mock 掩盖业务行为,也避免把跨系统路径误当单元测试。\n5. 逐项核对现有测试。标记为复用时,指出具体用例及其已覆盖的本次行为;需要调整或新增时明确差异,不用「已有覆盖」笼统跳过。\n6. 形成最终测试设计,包含范围与策略、行为单元、逐项用例、覆盖目标、测试层级边界、风险和不适用说明,以及需求→用例映射表(每条验收标准对应至少一个用例 ID);不得包含可执行测试函数、断言代码或完整 fixture。\n7. 将测试设计连同映射表交给 `test-reviewer`,不提供设计者结论或预期结果。委派材料按「契约 + 路标 + 已验锚点」组装:项目测试约束以节选直接置入委派 prompt;需求、生产代码、现有测试给路径路标;非首轮重审随附上轮已验锚点清单。\n8. 修复 BLOCKER、HIGH Findings 后重新评审:reviewer 只重验本轮修订触及的条目与受影响锚点,未触及项沿用上轮结论,但每轮报告保持全量 Findings 快照——已解决的标记关闭,不允许静默丢弃,是否处理由主会话决策;评审至多 3 轮,第 3 轮仍未 PASS 时保留在当前节点并请用户裁定,附双方分歧清单。MEDIUM、LOW 逐项处理或记录保留理由。Findings 处理记录写入节点记录,禁止回写被评审文档——测试设计文档只保留设计本体。\n\n## 产出与检查\n\n推进前确认:\n\n- 生产变更与被测行为已逐项对应;\n- 每个行为单元都有明确场景、观察点和预期结果;\n- 需求→用例映射表完整,每条验收标准至少对应一个用例;\n- 关键边界、失败路径和副作用已覆盖,不适用项已有理由;\n- 替身、数据准备和测试层级边界合理;\n- 现有测试的复用、调整与新增判断均有具体依据;\n- 最终设计不包含可执行测试代码,也不包含评审处理记录;\n- `test-reviewer` 最终结论为 PASS(或按 3 轮上界经用户裁定通过),所有 Findings 均已处理或说明;\n- 测试设计已形成完整产物,登记值携带全文(超限时为路径引用且已说明理由)。\n\n## 任务差异处理\n\n根据被测行为选择覆盖维度,不机械套用固定方法或为不适用场景制造用例。纯文档、配置或其他不存在可单元验证行为的变更,应说明判断依据和后续适用的验证层级,不得静默产出空设计。测试设计文档超过约 400 行时先按行为单元拆分再送审。评审修订与执行障碍按 `workflow-discipline` 处理。\n\n## 节点记录与推进\n\n将测试设计结论、范围、覆盖维度、现有测试复用判断、测试层级边界、风险与不适用项、设计产物(登记携带全文,超限时为路径引用且已说明理由)、`test-reviewer` 结论与各轮 Findings 处理记录写入当前节点记录——处理记录只进节点记录,被评审文档保持设计本体。完成上述检查后推进下一节点。",
|
|
163
163
|
"skills": [
|
|
164
164
|
"workflow-discipline"
|
|
165
165
|
],
|
|
@@ -168,8 +168,8 @@
|
|
|
168
168
|
],
|
|
169
169
|
"sourcePreset": {
|
|
170
170
|
"code": "test-unit-design",
|
|
171
|
-
"version": "1.
|
|
172
|
-
"contentHash": "
|
|
171
|
+
"version": "1.5.0",
|
|
172
|
+
"contentHash": "d030a84ed2273c99",
|
|
173
173
|
"agents": [
|
|
174
174
|
"test-reviewer"
|
|
175
175
|
]
|
|
@@ -204,7 +204,7 @@
|
|
|
204
204
|
"label": "端到端测试设计",
|
|
205
205
|
"phase": "test",
|
|
206
206
|
"track": "backend",
|
|
207
|
-
"prompt": "# 端到端测试设计\n\n## 节点职责\n\n判断项目是否存在适用的端到端测试体系;适用时为本次变更设计跨真实系统边界的可执行场景,不适用时记录依据。本节点只产出测试设计,不编写或执行测试代码,并通过独立 `test-reviewer` 评审设计质量。\n\n## 依赖信息\n\n先检查当前任务上下文,读取需求、验收标准、非目标、技术方案、生产代码与单元测试变更、前序决策,以及项目和所属模块的测试约束。加载 `workflow-discipline`,调用独立 `test-reviewer` 评审测试设计或不适用判断。\n\n读取项目提示词、测试说明、E2E 目录、配置、执行入口和现有用例,确认项目是否定义了 E2E 对象、边界、框架、环境和数据规则。缺少信息时先从仓库现状补齐,不凭通用惯例新建测试体系。\n\n## 执行流程\n\n1. 记录已检索的项目声明、目录、配置和现有用例,判断项目是否存在可用的 E2E 体系。\n2. 项目未定义 E2E 时,说明检索范围、判断依据及不引入新体系的结论,形成 N/A 产物后进入独立评审。\n3. 项目已定义 E2E 时,从需求和变更中识别必须跨真实边界验证的用户或系统路径,结合风险、现有覆盖和低层测试确定纳入与排除范围。\n4. 为每个场景写明标识、目标、优先级、前置条件、步骤、观察点、预期结果、数据准备、隔离和清理要求。场景应验证最终可观察结果,不只验证请求成功或调用发生。\n5.
|
|
207
|
+
"prompt": "# 端到端测试设计\n\n## 节点职责\n\n判断项目是否存在适用的端到端测试体系;适用时为本次变更设计跨真实系统边界的可执行场景,不适用时记录依据。本节点只产出测试设计,不编写或执行测试代码,并通过独立 `test-reviewer` 评审设计质量。\n\n## 依赖信息\n\n先检查当前任务上下文,读取需求、验收标准、非目标、技术方案、生产代码与单元测试变更、前序决策,以及项目和所属模块的测试约束。加载 `workflow-discipline`,调用独立 `test-reviewer` 评审测试设计或不适用判断。\n\n读取项目提示词、测试说明、E2E 目录、配置、执行入口和现有用例,确认项目是否定义了 E2E 对象、边界、框架、环境和数据规则。缺少信息时先从仓库现状补齐,不凭通用惯例新建测试体系。\n\n## 执行流程\n\n1. 记录已检索的项目声明、目录、配置和现有用例,判断项目是否存在可用的 E2E 体系。\n2. 项目未定义 E2E 时,说明检索范围、判断依据及不引入新体系的结论,形成 N/A 产物后进入独立评审。\n3. 项目已定义 E2E 时,从需求和变更中识别必须跨真实边界验证的用户或系统路径,结合风险、现有覆盖和低层测试确定纳入与排除范围。\n4. 为每个场景写明标识、目标、优先级、前置条件、步骤、观察点、预期结果、数据准备、隔离和清理要求。场景应验证最终可观察结果,不只验证请求成功或调用发生。\n5. 覆盖正常、失败、权限、恢复、状态或兼容场景中的适用部分,并说明哪些行为已由单元或其他测试层级可靠覆盖,避免重复和遗漏;形成跨边界行为→场景映射表(每条须跨边界验证的行为对应至少一个场景 ID)。\n6. 形成最终设计,不包含测试函数、可执行 fixture、请求代码或浏览器操作代码。\n7. 将测试设计连同映射表交给 `test-reviewer`,不提供设计者结论或预期结果。委派材料按「契约 + 路标 + 已验锚点」组装:项目 E2E 约束以节选直接置入委派 prompt;需求、生产变更、现有用例给路径路标;非首轮重审随附上轮已验锚点清单。N/A 判断评审时提供检索范围与证据路标。\n8. 适用时修复 BLOCKER、HIGH Findings 后重新评审:reviewer 只重验本轮修订触及的条目与受影响锚点,未触及项沿用上轮结论,但每轮报告保持全量 Findings 快照——已解决的标记关闭,不允许静默丢弃,是否处理由主会话决策;评审至多 3 轮,第 3 轮仍未 PASS 时保留在当前节点并请用户裁定,附双方分歧清单。MEDIUM、LOW 逐项处理或记录保留理由。Findings 处理记录写入节点记录,禁止回写被评审文档——测试设计文档只保留设计本体。\n\n## 产出与检查\n\n推进前确认:\n\n- 项目 E2E 体系的适用性已有仓库证据;\n- N/A 时已记录检索范围和判断依据,未擅自新建框架、目录或入口;\n- 适用时,覆盖范围与本次跨边界行为逐项对应,纳入和排除均有理由;跨边界行为→场景映射表完整;\n- 每个场景的前置条件、步骤、观察点、预期结果和数据清理可供后续实现;\n- 与其他测试层级的边界明确,设计不含可执行测试代码,也不含评审处理记录;\n- `test-reviewer` 最终结论为 PASS(或按 3 轮上界经用户裁定通过),所有 Findings 均已处理或说明;\n- E2E 设计或 N/A 结论已形成完整产物,登记值携带全文(超限时为路径引用且已说明理由)。\n\n## 任务差异处理\n\n不默认逐接口覆盖,也不默认只测关键旅程;根据项目现有 E2E 体系、需求风险和低层覆盖确定范围。项目未定义 E2E 时不把本节点变成测试基础设施建设;若任务明确要求新建 E2E 体系,应将其作为范围与技术决策单独确认。E2E 设计文档超过约 400 行时先按场景分组拆分再送审。执行障碍和评审修订按 `workflow-discipline` 处理。\n\n## 节点记录与推进\n\n将 E2E 适用性、检索范围与依据、覆盖范围、场景设计、测试层级边界、数据与清理策略、不适用项及理由、设计产物(登记携带全文,超限时为路径引用且已说明理由)、`test-reviewer` 结论与各轮 Findings 处理记录写入当前节点记录——处理记录只进节点记录,被评审文档保持设计本体。完成上述检查后推进下一节点。",
|
|
208
208
|
"skills": [
|
|
209
209
|
"workflow-discipline"
|
|
210
210
|
],
|
|
@@ -213,8 +213,8 @@
|
|
|
213
213
|
],
|
|
214
214
|
"sourcePreset": {
|
|
215
215
|
"code": "test-e2e-design",
|
|
216
|
-
"version": "1.
|
|
217
|
-
"contentHash": "
|
|
216
|
+
"version": "1.5.0",
|
|
217
|
+
"contentHash": "f1d0e86615f305a3",
|
|
218
218
|
"agents": [
|
|
219
219
|
"test-reviewer"
|
|
220
220
|
]
|
|
@@ -249,7 +249,7 @@
|
|
|
249
249
|
"label": "集成验证",
|
|
250
250
|
"phase": "test",
|
|
251
251
|
"track": "all",
|
|
252
|
-
"prompt": "# 集成验证\n\n## 节点职责\n\n将远程主线最新状态整合到任务分支,并在最终集成态执行适用回归,形成绑定明确版本的验证结论。版本控制与范围判断由当前执行者负责——范围判断是严肃决策,跑与不跑都必须有证据支撑,全量是须举证的选项而非默认值。测试命令交给独立 `test-executor` 执行;若产生代码修复,再交给独立 `code-reviewer` 评审。\n\n## 依赖信息\n\n先检查当前任务上下文,读取需求、技术方案、实现与测试记录、`align-branch` 的基础分支与合并记录,以及项目的分支策略、测试体系和所属模块提示词。加载 `workflow-discipline`,调用 `test-executor` 执行回归;发生代码修复时调用 `code-reviewer`。测试失败且根因不明确时,再加载 `bugfix-root-cause-verification`。\n\n优先使用 `align-branch` 已记录的基础分支;记录缺失时,按与该节点相同的规则从任务上下文或项目提示词解析,例如 `main`、`master` 或 `dev`。仍无法解析时询问用户是否需要合并某个分支的远程代码,不根据版本历史猜测基础分支。\n\n## 执行流程\n\n1. 获取远程状态,优先读取 `align-branch` 记录的基础分支;记录缺失时从任务上下文或项目提示词解析,仍无法解析则询问用户。记录当前任务版本、基础分支、远程版本及判断依据。\n2. 用户明确表示无需合并时记录该决定;否则按项目策略整合基础分支的远程最新代码。发生冲突时理解双方意图后逐项融合并验证结果,不盲目选择任一侧;无法可靠解决时说明冲突与缺失决策并暂停。\n3. 汇总任务改动和主线整合改动,读取项目测试目录、配置、脚本与现有用例,列出适用的测试层级和执行入口;项目未定义的层级记录 N/A。\n4. 回归执行决策由「是否执行」与「执行什么」两半构成,每一半都必须由证据支撑,禁止无分析的保守回退:\n - 零差异不重跑:某层级相对既有已验证版本(绑定明确版本标识、全绿证据在案)覆盖面差异为空时,该层级禁止重复执行,记录绑定证据替代重跑;\n - 有差异走判断链:a) 变更清单——汇总任务改动、主线整合改动与集成期修复,落到具体文件和对外可见的符号、契约、配置;b) 依赖分析——逐变更点查明引用方与波及面(导入、调用、共享契约、构建配置),得出受影响模块清单;c) 测试映射——把受影响模块映射到具体用例(既有用例位置、任务新增或修改的用例、所属层级与执行入口);d) 最小充分决策——按定向用例、受影响模块、整层级的顺序逐级扩大,每次扩大都指出上一级不充分的具体证据;\n - 全量须举证:仅当判断链证据表明影响面确实覆盖整个层级(如横切基础设施、共享契约、构建配置变更)才执行全量。宣称「无法判断影响范围」前必须已完成 a)–c) 分析;分析后仍存在的盲区逐条列明(哪个变更点、查了什么、缺什么信息),把盲区对应的补充用例并入执行范围并留痕。未做分析就宣称无法判断、或以「保险起见」跳过判断直接全量,均判定为范围决策失败。\n5. 将明确的命令、顺序、范围和通过标准交给 `test-executor` 执行——委派命令的覆盖范围必须与第 4 条判断链结论一致,判了定向就执行定向入口,不得委派时顺手扩大。依据事实报告核对各层级统计、失败、跳过和日志。\n6. 测试失败时读取完整证据。根因明确则做最小正确修复;根因不明确则按需加载 `bugfix-root-cause-verification`,确认根因后再修改代码、测试或环境。\n7. 每次修复后重新执行原失败范围和受影响回归。不得通过删除有效测试、skip/only、缩小应执行范围、放宽正确断言、吞异常或硬编码结果制造通过。\n8. 检查新增 skip/only
|
|
252
|
+
"prompt": "# 集成验证\n\n## 节点职责\n\n将远程主线最新状态整合到任务分支,并在最终集成态执行适用回归,形成绑定明确版本的验证结论。版本控制与范围判断由当前执行者负责——范围判断是严肃决策,跑与不跑都必须有证据支撑,全量是须举证的选项而非默认值。测试命令交给独立 `test-executor` 执行;若产生代码修复,再交给独立 `code-reviewer` 评审。\n\n## 依赖信息\n\n先检查当前任务上下文,读取需求、技术方案、实现与测试记录、`align-branch` 的基础分支与合并记录,以及项目的分支策略、测试体系和所属模块提示词。加载 `workflow-discipline`,调用 `test-executor` 执行回归;发生代码修复时调用 `code-reviewer`。测试失败且根因不明确时,再加载 `bugfix-root-cause-verification`。\n\n优先使用 `align-branch` 已记录的基础分支;记录缺失时,按与该节点相同的规则从任务上下文或项目提示词解析,例如 `main`、`master` 或 `dev`。仍无法解析时询问用户是否需要合并某个分支的远程代码,不根据版本历史猜测基础分支。\n\n## 执行流程\n\n1. 获取远程状态,优先读取 `align-branch` 记录的基础分支;记录缺失时从任务上下文或项目提示词解析,仍无法解析则询问用户。记录当前任务版本、基础分支、远程版本及判断依据。\n2. 用户明确表示无需合并时记录该决定;否则按项目策略整合基础分支的远程最新代码。发生冲突时理解双方意图后逐项融合并验证结果,不盲目选择任一侧;无法可靠解决时说明冲突与缺失决策并暂停。\n3. 汇总任务改动和主线整合改动,读取项目测试目录、配置、脚本与现有用例,列出适用的测试层级和执行入口;项目未定义的层级记录 N/A。\n4. 回归执行决策由「是否执行」与「执行什么」两半构成,每一半都必须由证据支撑,禁止无分析的保守回退:\n - 零差异不重跑:某层级相对既有已验证版本(绑定明确版本标识、全绿证据在案)覆盖面差异为空时,该层级禁止重复执行,记录绑定证据替代重跑;\n - 有差异走判断链:a) 变更清单——汇总任务改动、主线整合改动与集成期修复,落到具体文件和对外可见的符号、契约、配置;b) 依赖分析——逐变更点查明引用方与波及面(导入、调用、共享契约、构建配置),得出受影响模块清单;c) 测试映射——把受影响模块映射到具体用例(既有用例位置、任务新增或修改的用例、所属层级与执行入口);d) 最小充分决策——按定向用例、受影响模块、整层级的顺序逐级扩大,每次扩大都指出上一级不充分的具体证据;\n - 全量须举证:仅当判断链证据表明影响面确实覆盖整个层级(如横切基础设施、共享契约、构建配置变更)才执行全量。宣称「无法判断影响范围」前必须已完成 a)–c) 分析;分析后仍存在的盲区逐条列明(哪个变更点、查了什么、缺什么信息),把盲区对应的补充用例并入执行范围并留痕。未做分析就宣称无法判断、或以「保险起见」跳过判断直接全量,均判定为范围决策失败。\n5. 将明确的命令、顺序、范围和通过标准交给 `test-executor` 执行——委派命令的覆盖范围必须与第 4 条判断链结论一致,判了定向就执行定向入口,不得委派时顺手扩大。依据事实报告核对各层级统计、失败、跳过和日志。\n6. 测试失败时读取完整证据。根因明确则做最小正确修复;根因不明确则按需加载 `bugfix-root-cause-verification`,确认根因后再修改代码、测试或环境。\n7. 每次修复后重新执行原失败范围和受影响回归。不得通过删除有效测试、skip/only、缩小应执行范围、放宽正确断言、吞异常或硬编码结果制造通过。\n8. 检查新增 skip/only、测试删除、未执行的适用层级、范围遗漏和统计对账。发生代码修复时,将评审目标与材料(变更位置与相关任务信息)交给 `code-reviewer`;修复 BLOCKER、HIGH Findings 后重跑受影响测试并复审,直至测试通过且评审为 PASS。\n9. 记录最终同步状态、实际回归范围、测试结果和已验证的提交或等价版本标识,确保后续能够判断证据是否仍有效。\n\n## 产出与检查\n\n推进前确认:\n\n- 基础分支沿用 `align-branch` 记录,或已按相同规则重新解析并留痕;\n- 基础分支的远程状态已获取并完成整合,或用户已明确表示无需合并;\n- 所有冲突均已理解并正确融合;\n- 项目适用测试层级与执行入口已识别,N/A 有具体依据;\n- 回归范围由完整判断链支撑(变更清单 → 依赖分析 → 测试映射 → 逐级扩大决策),每个执行范围都能指认其覆盖的变更点;零差异层级以绑定证据替代重跑;全量执行附有影响面覆盖整个层级的具体证据;不存在无分析的全量兜底;\n- `test-executor` 报告所有适用回归通过,失败为 0,未授权跳过为 0;\n- 所有失败均在根因明确后修复,没有制造假绿;\n- 发生代码修复时,`code-reviewer` 最终结论为 PASS;\n- 集成结论绑定明确版本,日志和报告可追溯。\n\n## 任务差异处理\n\n基础分支没有新提交时无需制造合并提交;回归是否执行、执行什么,一律按第 4 条的零差异判定与判断链决定——集成态与已验证版本一致且证据在案时以证据绑定替代重跑,集成态有新增内容时按判断链定范围。用户明确表示无需合并时保留决定,验证决策同样按第 4 条执行。根据项目实际体系选择测试层级和命令,不擅自引入未定义的测试类型。远程状态不可获取、冲突无法可靠解决,或修复涉及破坏性契约、新依赖和真实范围扩张时,说明证据与影响并暂停;同一问题多轮不收敛时按 `workflow-discipline` 处理。\n\n## 节点记录与推进\n\n将基础分支来源、同步策略与结果、任务和远程版本、冲突处理、适用测试层级、回归范围判断链(变更清单、依赖分析、测试映射、逐级扩大证据、零差异证据绑定)及结论、实际命令与统计、失败根因和修复、完整性检查、代码评审结果、日志与报告引用、最终已验证版本写入当前节点记录。完成上述检查后推进下一节点。\n",
|
|
253
253
|
"skills": [
|
|
254
254
|
"workflow-discipline"
|
|
255
255
|
],
|
|
@@ -259,8 +259,8 @@
|
|
|
259
259
|
],
|
|
260
260
|
"sourcePreset": {
|
|
261
261
|
"code": "test-integrate",
|
|
262
|
-
"version": "1.4.
|
|
263
|
-
"contentHash": "
|
|
262
|
+
"version": "1.4.1",
|
|
263
|
+
"contentHash": "0f25ef16474fb990",
|
|
264
264
|
"agents": [
|
|
265
265
|
"test-executor",
|
|
266
266
|
"code-reviewer"
|
|
@@ -457,16 +457,16 @@
|
|
|
457
457
|
}
|
|
458
458
|
},
|
|
459
459
|
"isDefault": false,
|
|
460
|
-
"version": "3.5.
|
|
460
|
+
"version": "3.5.2"
|
|
461
461
|
},
|
|
462
462
|
"dependencies": {
|
|
463
463
|
"skills": [
|
|
464
464
|
{
|
|
465
465
|
"name": "workflow-discipline",
|
|
466
466
|
"description": "DAG 节点执行、角色分离、授权、暂停点与任务边界纪律",
|
|
467
|
-
"content": "# workflow-discipline\n\n保证所有 DAG 节点以一致方式确定工作边界、分离执行与验证、处理授权与暂停点,并在完成判定满足后安全推进。\n\n## 适用边界\n\n- 所有节点执行者都应用本 Skill;任务简单、用户催促或改动很小,不改变节点步骤、质量门和完成标准。\n- 本 Skill规定跨节点通用纪律,不替代当前节点提示词中的职责、产出、检查项和具体执行方法。\n- 当前节点提示词与本 Skill共同生效;发现冲突时不得自行忽略任一约束,应先按权限和任务边界判断,无法收敛再向用户呈现冲突。\n\n## 节点执行流程\n\n1. **确认当前边界**:读取任务上下文、当前节点职责、所需产出、完成判定、暂停点和项目约束。执行 git 操作前确认当前分支及项目声明的分支模型。\n2. **确定执行角色**:设计文档和编码由主会话完成;测试命令由 `test-executor` 执行;节点要求独立审查时,由不同 session 的只读 Verifier 执行。\n3. **完成节点工作**:只实施当前节点和已确认任务范围内的工作。发现死代码删留、顺手重构、范围扩张或其他范围外动作时,将其作为独立决策呈现给用户,不自行纳入。\n4. **执行独立验证**:Worker 与 Verifier 必须分离。Verifier
|
|
467
|
+
"content": "# workflow-discipline\n\n保证所有 DAG 节点以一致方式确定工作边界、分离执行与验证、处理授权与暂停点,并在完成判定满足后安全推进。\n\n## 铁律\n\n本 Skill 是保障 siming 流程正确执行的基础资产。执行会话加载本 Skill 后,任何上下文压缩操作一律不得压缩本 Skill 正文——它是后续所有节点判定与推进的准绳,必须完整留存在上下文中。\n\n执行会话只专注当前任务本身,不关注执行效率等其他因素;节点提示词、skill、委派 brief 中不得出现任何让 AI 转移任务注意力的描述。\n\n## 适用边界\n\n- 所有节点执行者都应用本 Skill;任务简单、用户催促或改动很小,不改变节点步骤、质量门和完成标准。\n- 本 Skill规定跨节点通用纪律,不替代当前节点提示词中的职责、产出、检查项和具体执行方法。\n- 当前节点提示词与本 Skill共同生效;发现冲突时不得自行忽略任一约束,应先按权限和任务边界判断,无法收敛再向用户呈现冲突。\n\n## 节点执行流程\n\n1. **确认当前边界**:读取任务上下文、当前节点职责、所需产出、完成判定、暂停点和项目约束。执行 git 操作前确认当前分支及项目声明的分支模型。\n2. **确定执行角色**:设计文档和编码由主会话完成;测试命令由 `test-executor` 执行;节点要求独立审查时,由不同 session 的只读 Verifier 执行。\n3. **完成节点工作**:只实施当前节点和已确认任务范围内的工作。发现死代码删留、顺手重构、范围扩张或其他范围外动作时,将其作为独立决策呈现给用户,不自行纳入。\n4. **执行独立验证**:Worker 与 Verifier 必须分离。Verifier 只接收评审目标与材料(评审对象路径、参照位置、已认定非问题的历史事项),不接收设计结论、决策理由或“用户已确认”等预设结论。\n5. **处理审查结果**:审查是否通过,以 Verifier 本次输出为准。逐条修复 finding,或记录不修复理由;修复阻塞问题后重新审查。交互式审查最多 3 轮,连续 3 轮仍未通过时,保留在当前节点并请用户决定。\n6. **检查并记录**:逐项核对当前节点的完成判定,记录实际产出、检查结果、评审结论与轮次、关键决定、不适用项及其理由。\n7. **提交节点成果**:完成判定全部满足后、推进节点前,检查工作树和 diff。存在本节点产生的应提交改动时,只纳入当前任务与当前节点范围内的代码、测试、文档等成果并创建 git commit;不得混入无关改动,也不得用空提交代替成果提交。提交失败或本节点应提交改动仍有遗漏时,留在当前节点处理。\n8. **推进节点**:确认完成判定全部满足,且本节点应提交成果已经提交后,才按节点规定推进或进入暂停点。没有应提交改动的纯审查、纯审批节点直接推进,不制造空提交。\n\n## 执行与质量边界\n\n- Track 编码节点只修改生产代码,不修改测试或其他验证代码;测试节点不得以“现有测试已经覆盖”代替逐项验证。\n- 本任务改动导致的测试失败必须完成根因调查并处理,不得标记为“既有问题”后拒绝处理,也不得通过删除测试、放宽断言或添加 skip 制造通过。\n- 预算或时间不足是暂停并上升决策的理由,不是降低质量门的理由。\n- 已知问题必须逐条判断是否影响功能完整性;影响验收的,在任务结束前处理。只有用户明确接受风险并留下原文记录,才可作为例外。\n- 增量测试或增量评审只能缩小经过证据证明的受影响范围,不得降低原有测试、审查和通过标准。\n\n## 委派纪律\n\n- Worker 与 Verifier 使用不同 session;Verifier 只读,不修改代码或文档,不接管主会话协调。\n- 增量复审聚焦本轮改动及其影响面,但沿用完整审查标准。\n- 委派 prompt 只提供评审目标与原始材料:目标 = 评什么、不评什么、主会话已认定不属于问题的历史事项;材料 = 原始需求、技术方案、代码等任务信息与信息地址(路径 / 命令 / 文档位置),怎么使用由 subagent 自行决策。目标必须精准——该评的项必须列全(不缺),不得把无关或大范围扫描类目标并入本次委派(不扩散);评估范围由目标层锁定,评审不自行扩张到目标之外。\n- 执行策略全部由 subagent 自行决策——如何分析、如何组织报告、按什么步骤工作、何时结束,均不在 brief 中指定;主会话不设预算、轮次、时限,不给检索范围限制,不指定评估方式、不追加取证要求、不扩张评估范围;发现 agent 定义有缺陷时修正定义本身,不以委派限制替代。\n- 需要评估时按角色选择对应 reviewer,不以主会话自评替代独立评估;确无匹配 agent 时上升用户。\n- 主会话与 reviewer 结论出现明显问题或冲突时,上升人类决策;流程本身有问题时,通知人类调整流程。\n- subagent 完成指定产出后立即结束;审查修订、重新委派和多轮协调由主会话负责。\n\n## 授权与暂停点\n\n- **决策授权**只覆盖具体方案或风险选择,不自动跳过审查、复审、测试或其他流程步骤。\n- **流程授权**只覆盖用户明确指名跳过的步骤,不得扩展到其他质量门。\n- “跳过人工审批”只跳过对应的用户暂停点,不等于跳过自动审查或验证。\n- 暂停点只有用户明确肯定当前待确认内容时才算通过,并记录用户原文。用户的提问、评估、条件句或新诉求不是确认;应先回应并继续等待明确结论。\n\n## 任务完成边界\n\n- 当前节点全部完成判定满足,且本节点产生的应提交成果已经提交后,才能推进到下一节点;单项测试通过、核心代码完成、存在未提交成果或分支合并,都不能代替节点完成。没有应提交改动的节点不制造空提交。\n- 节点完成不等于任务完成。架构信息归档完成,或该步骤经用户明确授权跳过并留下记录后,任务才进入终态。\n- 任务终止前,不推荐、不询问、不切换到下一个任务;终止后再输出完整任务总结。",
|
|
468
468
|
"category": "process",
|
|
469
|
-
"version": "1.
|
|
469
|
+
"version": "1.3.0",
|
|
470
470
|
"references": [],
|
|
471
471
|
"scope": "global"
|
|
472
472
|
},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"exportFormatVersion": "1.0",
|
|
3
|
-
"exportedAt": "2026-09-
|
|
3
|
+
"exportedAt": "2026-09-15T08:13:01.507Z",
|
|
4
4
|
"warnings": [],
|
|
5
5
|
"template": {
|
|
6
6
|
"name": "quick_workflow",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"label": "快速设计",
|
|
29
29
|
"phase": "entry",
|
|
30
30
|
"track": "all",
|
|
31
|
-
"prompt": "# 快速设计\n\n## 节点职责\n\n将用户描述的小型改动直接整理为最小技术方案——改动点、影响面、验证方式——经一次独立 AI 评审和用户人工确认后进入编码。本流程不设独立需求节点:用户描述与任务上下文就是需求源头。本节点只产出方案,不编写生产代码或测试代码。\n\n## 依赖信息\n\n先检查当前任务上下文:用户需求描述、验收标准、非目标、已有决策,以及项目和所属模块的提示词。加载 `workflow-discipline`;调用独立 `arch-reviewer` 完成方案评审。\n\n直接阅读相关代码和文档,确认真实改动位置、调用关系、依赖方与影响。缺少会改变方案的关键信息时先从仓库现状补齐;仍存在歧义时集中向用户说明并确认,不凭猜测设计。\n\n## 正向执行流程\n\n1. 从用户描述提炼目标行为、保持不变的行为和非目标,整理为可核对的改动点清单。\n2. 逐项定位改动点涉及的模块、调用关系与依赖方,说明对接口、数据、配置、兼容性和用户行为的影响。\n3. 形成最小技术方案,必含:背景与目标、改动点清单(位置+目标行为)、影响面、架构图与核心功能流程图、验证方式、非目标、必要决策;验证方式须能对应验收标准。两张图用可渲染的图形语法表达(项目未约定时用 Mermaid),示意级别即可,不使用文字罗列代替;图中模块、步骤、分支与正文互相有对应说明。\n4. 检查复杂度红线:跨多个边界模块、新增公开接口或数据契约、数据迁移、新依赖、破坏性变更、需要多路线取舍。命中时说明快速流程为何不足,建议改走完整流程;用户明确接受风险坚持快速路径时,记录确认原文。\n5.
|
|
31
|
+
"prompt": "# 快速设计\n\n## 节点职责\n\n将用户描述的小型改动直接整理为最小技术方案——改动点、影响面、验证方式——经一次独立 AI 评审和用户人工确认后进入编码。本流程不设独立需求节点:用户描述与任务上下文就是需求源头。本节点只产出方案,不编写生产代码或测试代码。\n\n## 依赖信息\n\n先检查当前任务上下文:用户需求描述、验收标准、非目标、已有决策,以及项目和所属模块的提示词。加载 `workflow-discipline`;调用独立 `arch-reviewer` 完成方案评审。\n\n直接阅读相关代码和文档,确认真实改动位置、调用关系、依赖方与影响。缺少会改变方案的关键信息时先从仓库现状补齐;仍存在歧义时集中向用户说明并确认,不凭猜测设计。\n\n## 正向执行流程\n\n1. 从用户描述提炼目标行为、保持不变的行为和非目标,整理为可核对的改动点清单。\n2. 逐项定位改动点涉及的模块、调用关系与依赖方,说明对接口、数据、配置、兼容性和用户行为的影响。\n3. 形成最小技术方案,必含:背景与目标、改动点清单(位置+目标行为)、影响面、架构图与核心功能流程图、验证方式、非目标、必要决策;验证方式须能对应验收标准。两张图用可渲染的图形语法表达(项目未约定时用 Mermaid),示意级别即可,不使用文字罗列代替;图中模块、步骤、分支与正文互相有对应说明。\n4. 检查复杂度红线:跨多个边界模块、新增公开接口或数据契约、数据迁移、新依赖、破坏性变更、需要多路线取舍。命中时说明快速流程为何不足,建议改走完整流程;用户明确接受风险坚持快速路径时,记录确认原文。\n5. 将方案全文与评审目标、材料(用户描述、验收标准、参照代码位置)交给 `arch-reviewer` 单轮独立评审,不提供主会话的设计结论。存在 BLOCKER 或 HIGH 时修复后重新发起评审;MEDIUM、LOW 逐项处理或记录保留理由,直至评审 PASS。\n6. 评审通过后先把方案全文落盘为可独立阅读的文档(项目正式文档路径;尚未确定时写临时草稿并注明),再向用户呈现该文档的可读位置、改动点清单、影响面、验证方式、AI 评审结论与红线判断,等待人工确认——确认前用户必须能打开完整方案。\n7. 用户确认后:把已呈现的方案文档按项目文档约定保存为正式文档并登记任务产物(携带全文;超限时路径引用须说明理由),已落盘的草稿直接转为正式文档,不重写内容;按项目分支策略创建任务分支并记录关联。若预判改动可能无可自动验证行为,在方案中显式声明——该声明进入编码节点测试范围判定与本次确认范围。\n\n## 产出与检查\n\n推进前确认:每个改动点有位置、目标行为与影响说明;验证方式对应验收标准;方案含架构图与核心功能流程图,以可渲染的图形呈现且与正文一致(确实不适用时已写明对象与理由);复杂度红线已检查,命中项已升级或取得用户风险确认;`arch-reviewer` 最终 PASS 且 Findings 处理留痕;用户明确确认且原文已记录;方案全文已保存登记;任务分支已就绪;呈现给用户的方案文档可独立打开阅读,且与确认的版本一致。\n\n## 任务差异处理\n\n纯文档、配置类改动可裁剪方案章节,但改动点、影响面、架构图与核心功能流程图、验证方式、非目标不得缺失。信息不足以形成方案时保留在本节点补齐,不推进。\n\n## 节点记录与推进\n\n将方案要点、改动点、影响面、验证方式、红线判断、AI 评审结论与轮次、用户确认原文、方案产物与分支信息写入节点记录,推进编码节点。",
|
|
32
32
|
"skills": [
|
|
33
33
|
"workflow-discipline"
|
|
34
34
|
],
|
|
@@ -37,8 +37,8 @@
|
|
|
37
37
|
],
|
|
38
38
|
"sourcePreset": {
|
|
39
39
|
"code": "quick-design",
|
|
40
|
-
"version": "1.1.
|
|
41
|
-
"contentHash": "
|
|
40
|
+
"version": "1.1.1",
|
|
41
|
+
"contentHash": "aa8eb7b9eefb8cbd",
|
|
42
42
|
"agents": [
|
|
43
43
|
"arch-reviewer"
|
|
44
44
|
]
|
|
@@ -99,7 +99,7 @@
|
|
|
99
99
|
"label": "集成验证",
|
|
100
100
|
"phase": "test",
|
|
101
101
|
"track": "all",
|
|
102
|
-
"prompt": "# 集成验证\n\n## 节点职责\n\n将远程主线最新状态整合到任务分支,并在最终集成态执行适用回归,形成绑定明确版本的验证结论。版本控制与范围判断由当前执行者负责——范围判断是严肃决策,跑与不跑都必须有证据支撑,全量是须举证的选项而非默认值。测试命令交给独立 `test-executor` 执行;若产生代码修复,再交给独立 `code-reviewer` 评审。\n\n## 依赖信息\n\n先检查当前任务上下文,读取需求、技术方案、实现与测试记录、`align-branch` 的基础分支与合并记录,以及项目的分支策略、测试体系和所属模块提示词。加载 `workflow-discipline`,调用 `test-executor` 执行回归;发生代码修复时调用 `code-reviewer`。测试失败且根因不明确时,再加载 `bugfix-root-cause-verification`。\n\n优先使用 `align-branch` 已记录的基础分支;记录缺失时,按与该节点相同的规则从任务上下文或项目提示词解析,例如 `main`、`master` 或 `dev`。仍无法解析时询问用户是否需要合并某个分支的远程代码,不根据版本历史猜测基础分支。\n\n## 执行流程\n\n1. 获取远程状态,优先读取 `align-branch` 记录的基础分支;记录缺失时从任务上下文或项目提示词解析,仍无法解析则询问用户。记录当前任务版本、基础分支、远程版本及判断依据。\n2. 用户明确表示无需合并时记录该决定;否则按项目策略整合基础分支的远程最新代码。发生冲突时理解双方意图后逐项融合并验证结果,不盲目选择任一侧;无法可靠解决时说明冲突与缺失决策并暂停。\n3. 汇总任务改动和主线整合改动,读取项目测试目录、配置、脚本与现有用例,列出适用的测试层级和执行入口;项目未定义的层级记录 N/A。\n4. 回归执行决策由「是否执行」与「执行什么」两半构成,每一半都必须由证据支撑,禁止无分析的保守回退:\n - 零差异不重跑:某层级相对既有已验证版本(绑定明确版本标识、全绿证据在案)覆盖面差异为空时,该层级禁止重复执行,记录绑定证据替代重跑;\n - 有差异走判断链:a) 变更清单——汇总任务改动、主线整合改动与集成期修复,落到具体文件和对外可见的符号、契约、配置;b) 依赖分析——逐变更点查明引用方与波及面(导入、调用、共享契约、构建配置),得出受影响模块清单;c) 测试映射——把受影响模块映射到具体用例(既有用例位置、任务新增或修改的用例、所属层级与执行入口);d) 最小充分决策——按定向用例、受影响模块、整层级的顺序逐级扩大,每次扩大都指出上一级不充分的具体证据;\n - 全量须举证:仅当判断链证据表明影响面确实覆盖整个层级(如横切基础设施、共享契约、构建配置变更)才执行全量。宣称「无法判断影响范围」前必须已完成 a)–c) 分析;分析后仍存在的盲区逐条列明(哪个变更点、查了什么、缺什么信息),把盲区对应的补充用例并入执行范围并留痕。未做分析就宣称无法判断、或以「保险起见」跳过判断直接全量,均判定为范围决策失败。\n5. 将明确的命令、顺序、范围和通过标准交给 `test-executor` 执行——委派命令的覆盖范围必须与第 4 条判断链结论一致,判了定向就执行定向入口,不得委派时顺手扩大。依据事实报告核对各层级统计、失败、跳过和日志。\n6. 测试失败时读取完整证据。根因明确则做最小正确修复;根因不明确则按需加载 `bugfix-root-cause-verification`,确认根因后再修改代码、测试或环境。\n7. 每次修复后重新执行原失败范围和受影响回归。不得通过删除有效测试、skip/only、缩小应执行范围、放宽正确断言、吞异常或硬编码结果制造通过。\n8. 检查新增 skip/only
|
|
102
|
+
"prompt": "# 集成验证\n\n## 节点职责\n\n将远程主线最新状态整合到任务分支,并在最终集成态执行适用回归,形成绑定明确版本的验证结论。版本控制与范围判断由当前执行者负责——范围判断是严肃决策,跑与不跑都必须有证据支撑,全量是须举证的选项而非默认值。测试命令交给独立 `test-executor` 执行;若产生代码修复,再交给独立 `code-reviewer` 评审。\n\n## 依赖信息\n\n先检查当前任务上下文,读取需求、技术方案、实现与测试记录、`align-branch` 的基础分支与合并记录,以及项目的分支策略、测试体系和所属模块提示词。加载 `workflow-discipline`,调用 `test-executor` 执行回归;发生代码修复时调用 `code-reviewer`。测试失败且根因不明确时,再加载 `bugfix-root-cause-verification`。\n\n优先使用 `align-branch` 已记录的基础分支;记录缺失时,按与该节点相同的规则从任务上下文或项目提示词解析,例如 `main`、`master` 或 `dev`。仍无法解析时询问用户是否需要合并某个分支的远程代码,不根据版本历史猜测基础分支。\n\n## 执行流程\n\n1. 获取远程状态,优先读取 `align-branch` 记录的基础分支;记录缺失时从任务上下文或项目提示词解析,仍无法解析则询问用户。记录当前任务版本、基础分支、远程版本及判断依据。\n2. 用户明确表示无需合并时记录该决定;否则按项目策略整合基础分支的远程最新代码。发生冲突时理解双方意图后逐项融合并验证结果,不盲目选择任一侧;无法可靠解决时说明冲突与缺失决策并暂停。\n3. 汇总任务改动和主线整合改动,读取项目测试目录、配置、脚本与现有用例,列出适用的测试层级和执行入口;项目未定义的层级记录 N/A。\n4. 回归执行决策由「是否执行」与「执行什么」两半构成,每一半都必须由证据支撑,禁止无分析的保守回退:\n - 零差异不重跑:某层级相对既有已验证版本(绑定明确版本标识、全绿证据在案)覆盖面差异为空时,该层级禁止重复执行,记录绑定证据替代重跑;\n - 有差异走判断链:a) 变更清单——汇总任务改动、主线整合改动与集成期修复,落到具体文件和对外可见的符号、契约、配置;b) 依赖分析——逐变更点查明引用方与波及面(导入、调用、共享契约、构建配置),得出受影响模块清单;c) 测试映射——把受影响模块映射到具体用例(既有用例位置、任务新增或修改的用例、所属层级与执行入口);d) 最小充分决策——按定向用例、受影响模块、整层级的顺序逐级扩大,每次扩大都指出上一级不充分的具体证据;\n - 全量须举证:仅当判断链证据表明影响面确实覆盖整个层级(如横切基础设施、共享契约、构建配置变更)才执行全量。宣称「无法判断影响范围」前必须已完成 a)–c) 分析;分析后仍存在的盲区逐条列明(哪个变更点、查了什么、缺什么信息),把盲区对应的补充用例并入执行范围并留痕。未做分析就宣称无法判断、或以「保险起见」跳过判断直接全量,均判定为范围决策失败。\n5. 将明确的命令、顺序、范围和通过标准交给 `test-executor` 执行——委派命令的覆盖范围必须与第 4 条判断链结论一致,判了定向就执行定向入口,不得委派时顺手扩大。依据事实报告核对各层级统计、失败、跳过和日志。\n6. 测试失败时读取完整证据。根因明确则做最小正确修复;根因不明确则按需加载 `bugfix-root-cause-verification`,确认根因后再修改代码、测试或环境。\n7. 每次修复后重新执行原失败范围和受影响回归。不得通过删除有效测试、skip/only、缩小应执行范围、放宽正确断言、吞异常或硬编码结果制造通过。\n8. 检查新增 skip/only、测试删除、未执行的适用层级、范围遗漏和统计对账。发生代码修复时,将评审目标与材料(变更位置与相关任务信息)交给 `code-reviewer`;修复 BLOCKER、HIGH Findings 后重跑受影响测试并复审,直至测试通过且评审为 PASS。\n9. 记录最终同步状态、实际回归范围、测试结果和已验证的提交或等价版本标识,确保后续能够判断证据是否仍有效。\n\n## 产出与检查\n\n推进前确认:\n\n- 基础分支沿用 `align-branch` 记录,或已按相同规则重新解析并留痕;\n- 基础分支的远程状态已获取并完成整合,或用户已明确表示无需合并;\n- 所有冲突均已理解并正确融合;\n- 项目适用测试层级与执行入口已识别,N/A 有具体依据;\n- 回归范围由完整判断链支撑(变更清单 → 依赖分析 → 测试映射 → 逐级扩大决策),每个执行范围都能指认其覆盖的变更点;零差异层级以绑定证据替代重跑;全量执行附有影响面覆盖整个层级的具体证据;不存在无分析的全量兜底;\n- `test-executor` 报告所有适用回归通过,失败为 0,未授权跳过为 0;\n- 所有失败均在根因明确后修复,没有制造假绿;\n- 发生代码修复时,`code-reviewer` 最终结论为 PASS;\n- 集成结论绑定明确版本,日志和报告可追溯。\n\n## 任务差异处理\n\n基础分支没有新提交时无需制造合并提交;回归是否执行、执行什么,一律按第 4 条的零差异判定与判断链决定——集成态与已验证版本一致且证据在案时以证据绑定替代重跑,集成态有新增内容时按判断链定范围。用户明确表示无需合并时保留决定,验证决策同样按第 4 条执行。根据项目实际体系选择测试层级和命令,不擅自引入未定义的测试类型。远程状态不可获取、冲突无法可靠解决,或修复涉及破坏性契约、新依赖和真实范围扩张时,说明证据与影响并暂停;同一问题多轮不收敛时按 `workflow-discipline` 处理。\n\n## 节点记录与推进\n\n将基础分支来源、同步策略与结果、任务和远程版本、冲突处理、适用测试层级、回归范围判断链(变更清单、依赖分析、测试映射、逐级扩大证据、零差异证据绑定)及结论、实际命令与统计、失败根因和修复、完整性检查、代码评审结果、日志与报告引用、最终已验证版本写入当前节点记录。完成上述检查后推进下一节点。\n",
|
|
103
103
|
"skills": [
|
|
104
104
|
"workflow-discipline"
|
|
105
105
|
],
|
|
@@ -109,8 +109,8 @@
|
|
|
109
109
|
],
|
|
110
110
|
"sourcePreset": {
|
|
111
111
|
"code": "test-integrate",
|
|
112
|
-
"version": "1.4.
|
|
113
|
-
"contentHash": "
|
|
112
|
+
"version": "1.4.1",
|
|
113
|
+
"contentHash": "0f25ef16474fb990",
|
|
114
114
|
"agents": [
|
|
115
115
|
"test-executor",
|
|
116
116
|
"code-reviewer"
|
|
@@ -176,16 +176,16 @@
|
|
|
176
176
|
}
|
|
177
177
|
],
|
|
178
178
|
"isDefault": false,
|
|
179
|
-
"version": "2.0.
|
|
179
|
+
"version": "2.0.3"
|
|
180
180
|
},
|
|
181
181
|
"dependencies": {
|
|
182
182
|
"skills": [
|
|
183
183
|
{
|
|
184
184
|
"name": "workflow-discipline",
|
|
185
185
|
"description": "DAG 节点执行、角色分离、授权、暂停点与任务边界纪律",
|
|
186
|
-
"content": "# workflow-discipline\n\n保证所有 DAG 节点以一致方式确定工作边界、分离执行与验证、处理授权与暂停点,并在完成判定满足后安全推进。\n\n## 适用边界\n\n- 所有节点执行者都应用本 Skill;任务简单、用户催促或改动很小,不改变节点步骤、质量门和完成标准。\n- 本 Skill规定跨节点通用纪律,不替代当前节点提示词中的职责、产出、检查项和具体执行方法。\n- 当前节点提示词与本 Skill共同生效;发现冲突时不得自行忽略任一约束,应先按权限和任务边界判断,无法收敛再向用户呈现冲突。\n\n## 节点执行流程\n\n1. **确认当前边界**:读取任务上下文、当前节点职责、所需产出、完成判定、暂停点和项目约束。执行 git 操作前确认当前分支及项目声明的分支模型。\n2. **确定执行角色**:设计文档和编码由主会话完成;测试命令由 `test-executor` 执行;节点要求独立审查时,由不同 session 的只读 Verifier 执行。\n3. **完成节点工作**:只实施当前节点和已确认任务范围内的工作。发现死代码删留、顺手重构、范围扩张或其他范围外动作时,将其作为独立决策呈现给用户,不自行纳入。\n4. **执行独立验证**:Worker 与 Verifier 必须分离。Verifier
|
|
186
|
+
"content": "# workflow-discipline\n\n保证所有 DAG 节点以一致方式确定工作边界、分离执行与验证、处理授权与暂停点,并在完成判定满足后安全推进。\n\n## 铁律\n\n本 Skill 是保障 siming 流程正确执行的基础资产。执行会话加载本 Skill 后,任何上下文压缩操作一律不得压缩本 Skill 正文——它是后续所有节点判定与推进的准绳,必须完整留存在上下文中。\n\n执行会话只专注当前任务本身,不关注执行效率等其他因素;节点提示词、skill、委派 brief 中不得出现任何让 AI 转移任务注意力的描述。\n\n## 适用边界\n\n- 所有节点执行者都应用本 Skill;任务简单、用户催促或改动很小,不改变节点步骤、质量门和完成标准。\n- 本 Skill规定跨节点通用纪律,不替代当前节点提示词中的职责、产出、检查项和具体执行方法。\n- 当前节点提示词与本 Skill共同生效;发现冲突时不得自行忽略任一约束,应先按权限和任务边界判断,无法收敛再向用户呈现冲突。\n\n## 节点执行流程\n\n1. **确认当前边界**:读取任务上下文、当前节点职责、所需产出、完成判定、暂停点和项目约束。执行 git 操作前确认当前分支及项目声明的分支模型。\n2. **确定执行角色**:设计文档和编码由主会话完成;测试命令由 `test-executor` 执行;节点要求独立审查时,由不同 session 的只读 Verifier 执行。\n3. **完成节点工作**:只实施当前节点和已确认任务范围内的工作。发现死代码删留、顺手重构、范围扩张或其他范围外动作时,将其作为独立决策呈现给用户,不自行纳入。\n4. **执行独立验证**:Worker 与 Verifier 必须分离。Verifier 只接收评审目标与材料(评审对象路径、参照位置、已认定非问题的历史事项),不接收设计结论、决策理由或“用户已确认”等预设结论。\n5. **处理审查结果**:审查是否通过,以 Verifier 本次输出为准。逐条修复 finding,或记录不修复理由;修复阻塞问题后重新审查。交互式审查最多 3 轮,连续 3 轮仍未通过时,保留在当前节点并请用户决定。\n6. **检查并记录**:逐项核对当前节点的完成判定,记录实际产出、检查结果、评审结论与轮次、关键决定、不适用项及其理由。\n7. **提交节点成果**:完成判定全部满足后、推进节点前,检查工作树和 diff。存在本节点产生的应提交改动时,只纳入当前任务与当前节点范围内的代码、测试、文档等成果并创建 git commit;不得混入无关改动,也不得用空提交代替成果提交。提交失败或本节点应提交改动仍有遗漏时,留在当前节点处理。\n8. **推进节点**:确认完成判定全部满足,且本节点应提交成果已经提交后,才按节点规定推进或进入暂停点。没有应提交改动的纯审查、纯审批节点直接推进,不制造空提交。\n\n## 执行与质量边界\n\n- Track 编码节点只修改生产代码,不修改测试或其他验证代码;测试节点不得以“现有测试已经覆盖”代替逐项验证。\n- 本任务改动导致的测试失败必须完成根因调查并处理,不得标记为“既有问题”后拒绝处理,也不得通过删除测试、放宽断言或添加 skip 制造通过。\n- 预算或时间不足是暂停并上升决策的理由,不是降低质量门的理由。\n- 已知问题必须逐条判断是否影响功能完整性;影响验收的,在任务结束前处理。只有用户明确接受风险并留下原文记录,才可作为例外。\n- 增量测试或增量评审只能缩小经过证据证明的受影响范围,不得降低原有测试、审查和通过标准。\n\n## 委派纪律\n\n- Worker 与 Verifier 使用不同 session;Verifier 只读,不修改代码或文档,不接管主会话协调。\n- 增量复审聚焦本轮改动及其影响面,但沿用完整审查标准。\n- 委派 prompt 只提供评审目标与原始材料:目标 = 评什么、不评什么、主会话已认定不属于问题的历史事项;材料 = 原始需求、技术方案、代码等任务信息与信息地址(路径 / 命令 / 文档位置),怎么使用由 subagent 自行决策。目标必须精准——该评的项必须列全(不缺),不得把无关或大范围扫描类目标并入本次委派(不扩散);评估范围由目标层锁定,评审不自行扩张到目标之外。\n- 执行策略全部由 subagent 自行决策——如何分析、如何组织报告、按什么步骤工作、何时结束,均不在 brief 中指定;主会话不设预算、轮次、时限,不给检索范围限制,不指定评估方式、不追加取证要求、不扩张评估范围;发现 agent 定义有缺陷时修正定义本身,不以委派限制替代。\n- 需要评估时按角色选择对应 reviewer,不以主会话自评替代独立评估;确无匹配 agent 时上升用户。\n- 主会话与 reviewer 结论出现明显问题或冲突时,上升人类决策;流程本身有问题时,通知人类调整流程。\n- subagent 完成指定产出后立即结束;审查修订、重新委派和多轮协调由主会话负责。\n\n## 授权与暂停点\n\n- **决策授权**只覆盖具体方案或风险选择,不自动跳过审查、复审、测试或其他流程步骤。\n- **流程授权**只覆盖用户明确指名跳过的步骤,不得扩展到其他质量门。\n- “跳过人工审批”只跳过对应的用户暂停点,不等于跳过自动审查或验证。\n- 暂停点只有用户明确肯定当前待确认内容时才算通过,并记录用户原文。用户的提问、评估、条件句或新诉求不是确认;应先回应并继续等待明确结论。\n\n## 任务完成边界\n\n- 当前节点全部完成判定满足,且本节点产生的应提交成果已经提交后,才能推进到下一节点;单项测试通过、核心代码完成、存在未提交成果或分支合并,都不能代替节点完成。没有应提交改动的节点不制造空提交。\n- 节点完成不等于任务完成。架构信息归档完成,或该步骤经用户明确授权跳过并留下记录后,任务才进入终态。\n- 任务终止前,不推荐、不询问、不切换到下一个任务;终止后再输出完整任务总结。",
|
|
187
187
|
"category": "process",
|
|
188
|
-
"version": "1.
|
|
188
|
+
"version": "1.3.0",
|
|
189
189
|
"references": [],
|
|
190
190
|
"scope": "global"
|
|
191
191
|
},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"exportFormatVersion": "1.0",
|
|
3
|
-
"exportedAt": "2026-09-
|
|
3
|
+
"exportedAt": "2026-09-15T08:13:01.505Z",
|
|
4
4
|
"warnings": [],
|
|
5
5
|
"template": {
|
|
6
6
|
"name": "research_workflow",
|
|
@@ -95,9 +95,9 @@
|
|
|
95
95
|
{
|
|
96
96
|
"name": "workflow-discipline",
|
|
97
97
|
"description": "DAG 节点执行、角色分离、授权、暂停点与任务边界纪律",
|
|
98
|
-
"content": "# workflow-discipline\n\n保证所有 DAG 节点以一致方式确定工作边界、分离执行与验证、处理授权与暂停点,并在完成判定满足后安全推进。\n\n## 适用边界\n\n- 所有节点执行者都应用本 Skill;任务简单、用户催促或改动很小,不改变节点步骤、质量门和完成标准。\n- 本 Skill规定跨节点通用纪律,不替代当前节点提示词中的职责、产出、检查项和具体执行方法。\n- 当前节点提示词与本 Skill共同生效;发现冲突时不得自行忽略任一约束,应先按权限和任务边界判断,无法收敛再向用户呈现冲突。\n\n## 节点执行流程\n\n1. **确认当前边界**:读取任务上下文、当前节点职责、所需产出、完成判定、暂停点和项目约束。执行 git 操作前确认当前分支及项目声明的分支模型。\n2. **确定执行角色**:设计文档和编码由主会话完成;测试命令由 `test-executor` 执行;节点要求独立审查时,由不同 session 的只读 Verifier 执行。\n3. **完成节点工作**:只实施当前节点和已确认任务范围内的工作。发现死代码删留、顺手重构、范围扩张或其他范围外动作时,将其作为独立决策呈现给用户,不自行纳入。\n4. **执行独立验证**:Worker 与 Verifier 必须分离。Verifier
|
|
98
|
+
"content": "# workflow-discipline\n\n保证所有 DAG 节点以一致方式确定工作边界、分离执行与验证、处理授权与暂停点,并在完成判定满足后安全推进。\n\n## 铁律\n\n本 Skill 是保障 siming 流程正确执行的基础资产。执行会话加载本 Skill 后,任何上下文压缩操作一律不得压缩本 Skill 正文——它是后续所有节点判定与推进的准绳,必须完整留存在上下文中。\n\n执行会话只专注当前任务本身,不关注执行效率等其他因素;节点提示词、skill、委派 brief 中不得出现任何让 AI 转移任务注意力的描述。\n\n## 适用边界\n\n- 所有节点执行者都应用本 Skill;任务简单、用户催促或改动很小,不改变节点步骤、质量门和完成标准。\n- 本 Skill规定跨节点通用纪律,不替代当前节点提示词中的职责、产出、检查项和具体执行方法。\n- 当前节点提示词与本 Skill共同生效;发现冲突时不得自行忽略任一约束,应先按权限和任务边界判断,无法收敛再向用户呈现冲突。\n\n## 节点执行流程\n\n1. **确认当前边界**:读取任务上下文、当前节点职责、所需产出、完成判定、暂停点和项目约束。执行 git 操作前确认当前分支及项目声明的分支模型。\n2. **确定执行角色**:设计文档和编码由主会话完成;测试命令由 `test-executor` 执行;节点要求独立审查时,由不同 session 的只读 Verifier 执行。\n3. **完成节点工作**:只实施当前节点和已确认任务范围内的工作。发现死代码删留、顺手重构、范围扩张或其他范围外动作时,将其作为独立决策呈现给用户,不自行纳入。\n4. **执行独立验证**:Worker 与 Verifier 必须分离。Verifier 只接收评审目标与材料(评审对象路径、参照位置、已认定非问题的历史事项),不接收设计结论、决策理由或“用户已确认”等预设结论。\n5. **处理审查结果**:审查是否通过,以 Verifier 本次输出为准。逐条修复 finding,或记录不修复理由;修复阻塞问题后重新审查。交互式审查最多 3 轮,连续 3 轮仍未通过时,保留在当前节点并请用户决定。\n6. **检查并记录**:逐项核对当前节点的完成判定,记录实际产出、检查结果、评审结论与轮次、关键决定、不适用项及其理由。\n7. **提交节点成果**:完成判定全部满足后、推进节点前,检查工作树和 diff。存在本节点产生的应提交改动时,只纳入当前任务与当前节点范围内的代码、测试、文档等成果并创建 git commit;不得混入无关改动,也不得用空提交代替成果提交。提交失败或本节点应提交改动仍有遗漏时,留在当前节点处理。\n8. **推进节点**:确认完成判定全部满足,且本节点应提交成果已经提交后,才按节点规定推进或进入暂停点。没有应提交改动的纯审查、纯审批节点直接推进,不制造空提交。\n\n## 执行与质量边界\n\n- Track 编码节点只修改生产代码,不修改测试或其他验证代码;测试节点不得以“现有测试已经覆盖”代替逐项验证。\n- 本任务改动导致的测试失败必须完成根因调查并处理,不得标记为“既有问题”后拒绝处理,也不得通过删除测试、放宽断言或添加 skip 制造通过。\n- 预算或时间不足是暂停并上升决策的理由,不是降低质量门的理由。\n- 已知问题必须逐条判断是否影响功能完整性;影响验收的,在任务结束前处理。只有用户明确接受风险并留下原文记录,才可作为例外。\n- 增量测试或增量评审只能缩小经过证据证明的受影响范围,不得降低原有测试、审查和通过标准。\n\n## 委派纪律\n\n- Worker 与 Verifier 使用不同 session;Verifier 只读,不修改代码或文档,不接管主会话协调。\n- 增量复审聚焦本轮改动及其影响面,但沿用完整审查标准。\n- 委派 prompt 只提供评审目标与原始材料:目标 = 评什么、不评什么、主会话已认定不属于问题的历史事项;材料 = 原始需求、技术方案、代码等任务信息与信息地址(路径 / 命令 / 文档位置),怎么使用由 subagent 自行决策。目标必须精准——该评的项必须列全(不缺),不得把无关或大范围扫描类目标并入本次委派(不扩散);评估范围由目标层锁定,评审不自行扩张到目标之外。\n- 执行策略全部由 subagent 自行决策——如何分析、如何组织报告、按什么步骤工作、何时结束,均不在 brief 中指定;主会话不设预算、轮次、时限,不给检索范围限制,不指定评估方式、不追加取证要求、不扩张评估范围;发现 agent 定义有缺陷时修正定义本身,不以委派限制替代。\n- 需要评估时按角色选择对应 reviewer,不以主会话自评替代独立评估;确无匹配 agent 时上升用户。\n- 主会话与 reviewer 结论出现明显问题或冲突时,上升人类决策;流程本身有问题时,通知人类调整流程。\n- subagent 完成指定产出后立即结束;审查修订、重新委派和多轮协调由主会话负责。\n\n## 授权与暂停点\n\n- **决策授权**只覆盖具体方案或风险选择,不自动跳过审查、复审、测试或其他流程步骤。\n- **流程授权**只覆盖用户明确指名跳过的步骤,不得扩展到其他质量门。\n- “跳过人工审批”只跳过对应的用户暂停点,不等于跳过自动审查或验证。\n- 暂停点只有用户明确肯定当前待确认内容时才算通过,并记录用户原文。用户的提问、评估、条件句或新诉求不是确认;应先回应并继续等待明确结论。\n\n## 任务完成边界\n\n- 当前节点全部完成判定满足,且本节点产生的应提交成果已经提交后,才能推进到下一节点;单项测试通过、核心代码完成、存在未提交成果或分支合并,都不能代替节点完成。没有应提交改动的节点不制造空提交。\n- 节点完成不等于任务完成。架构信息归档完成,或该步骤经用户明确授权跳过并留下记录后,任务才进入终态。\n- 任务终止前,不推荐、不询问、不切换到下一个任务;终止后再输出完整任务总结。",
|
|
99
99
|
"category": "process",
|
|
100
|
-
"version": "1.
|
|
100
|
+
"version": "1.3.0",
|
|
101
101
|
"references": [],
|
|
102
102
|
"scope": "global"
|
|
103
103
|
}
|