@siming-org/cli 0.8.5 → 0.8.7
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
|
@@ -80,6 +80,12 @@ function userConfigPath() {
|
|
|
80
80
|
}
|
|
81
81
|
var SIMING_NO_CONFIG_FILES_ENV = "SIMING_NO_CONFIG_FILES";
|
|
82
82
|
var immunityNotified = false;
|
|
83
|
+
var warnedInvalidPortOnce = /* @__PURE__ */ new Set();
|
|
84
|
+
function warnInvalidPortOnce(kind, message) {
|
|
85
|
+
if (warnedInvalidPortOnce.has(kind)) return;
|
|
86
|
+
warnedInvalidPortOnce.add(kind);
|
|
87
|
+
console.error(message);
|
|
88
|
+
}
|
|
83
89
|
var SOURCE_FORM_MARK = "/packages/cli/";
|
|
84
90
|
var NODE_MODULES_MARK = "/node_modules/";
|
|
85
91
|
function notifyImmunityOnce() {
|
|
@@ -231,7 +237,7 @@ function resolveLocalSimingPort(env = process.env, paths) {
|
|
|
231
237
|
if (portEnv !== void 0) {
|
|
232
238
|
const n = Number(portEnv);
|
|
233
239
|
if (Number.isInteger(n) && n >= 1 && n <= 65535) return n;
|
|
234
|
-
|
|
240
|
+
warnInvalidPortOnce("invalid-port-env", `[siming] \u5FFD\u7565\u975E\u6CD5 PORT="${portEnv}"\uFF08\u5E94\u4E3A 1-65535 \u6574\u6570\uFF09`);
|
|
235
241
|
}
|
|
236
242
|
const userPath = paths?.user ?? userConfigPath();
|
|
237
243
|
const systemPath = paths?.system ?? SYSTEM_CONFIG_PATH;
|
|
@@ -242,7 +248,7 @@ function resolveLocalSimingPort(env = process.env, paths) {
|
|
|
242
248
|
if (raw === void 0) continue;
|
|
243
249
|
const n = typeof raw === "number" ? raw : Number(raw);
|
|
244
250
|
if (Number.isInteger(n) && n >= 1 && n <= 65535) return n;
|
|
245
|
-
|
|
251
|
+
warnInvalidPortOnce(`invalid-port-file:${absPath}`, `[siming] \u5FFD\u7565 ${absPath} \u4E2D\u975E\u6CD5 port="${String(raw)}"`);
|
|
246
252
|
}
|
|
247
253
|
}
|
|
248
254
|
return 7777;
|
|
@@ -254,6 +260,12 @@ function maskMongoUri(uri) {
|
|
|
254
260
|
// src/config/local-config.ts
|
|
255
261
|
var CONFIG_DIR = join2(homedir2(), ".siming");
|
|
256
262
|
var CONFIG_PATH = join2(CONFIG_DIR, "config.json");
|
|
263
|
+
var warnedOnce = /* @__PURE__ */ new Set();
|
|
264
|
+
function warnOnce(kind, message) {
|
|
265
|
+
if (warnedOnce.has(kind)) return;
|
|
266
|
+
warnedOnce.add(kind);
|
|
267
|
+
console.error(message);
|
|
268
|
+
}
|
|
257
269
|
var ServerUrlSchema = z.string().regex(/^https?:\/\/\S+$/, "must be an http(s):// URL");
|
|
258
270
|
function readLocalConfig(env = process.env, opts = {}) {
|
|
259
271
|
if (opts.ignoreImmunity !== true && shouldSkipConfigFiles(env)) return null;
|
|
@@ -263,12 +275,12 @@ function readLocalConfig(env = process.env, opts = {}) {
|
|
|
263
275
|
if (typeof parsed.serverUrl !== "string" || parsed.serverUrl.length === 0) return null;
|
|
264
276
|
const r = ServerUrlSchema.safeParse(parsed.serverUrl);
|
|
265
277
|
if (!r.success) {
|
|
266
|
-
|
|
278
|
+
warnOnce("local-invalid-serverurl", `[siming] \u5FFD\u7565\u975E\u6CD5 config.json serverUrl="${parsed.serverUrl}"\uFF0C\u964D\u7EA7\u5230\u9ED8\u8BA4`);
|
|
267
279
|
return null;
|
|
268
280
|
}
|
|
269
281
|
return { serverUrl: parsed.serverUrl };
|
|
270
282
|
} catch (e) {
|
|
271
|
-
|
|
283
|
+
warnOnce("local-read-failed", `[siming] \u8BFB\u53D6 ~/.siming/config.json \u5931\u8D25: ${e instanceof Error ? e.message : String(e)}`);
|
|
272
284
|
return null;
|
|
273
285
|
}
|
|
274
286
|
}
|
|
@@ -290,16 +302,42 @@ function getLocalServerUrl() {
|
|
|
290
302
|
}
|
|
291
303
|
|
|
292
304
|
// src/config/workspace-config.ts
|
|
293
|
-
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2, rmSync, renameSync } from "fs";
|
|
294
|
-
import { join as join3, dirname } from "path";
|
|
305
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync3, statSync, writeFileSync as writeFileSync2, rmSync, renameSync } from "fs";
|
|
306
|
+
import { join as join3, dirname, resolve as resolve2 } from "path";
|
|
295
307
|
import { z as z2 } from "zod";
|
|
296
308
|
var WORKSPACE_DIR_NAME = ".siming";
|
|
297
309
|
var CONFIG_FILE = "config.json";
|
|
310
|
+
var warnedOnce2 = /* @__PURE__ */ new Set();
|
|
311
|
+
function warnOnce2(kind, message) {
|
|
312
|
+
if (warnedOnce2.has(kind)) return;
|
|
313
|
+
warnedOnce2.add(kind);
|
|
314
|
+
console.error(message);
|
|
315
|
+
}
|
|
298
316
|
var DefaultProjectSchema = z2.string().regex(/^(?![a-f0-9]{24}$)[a-z0-9][a-z0-9-]{1,30}$/, "must be a project key (kebab-case, 2-31 chars; not a MongoDB id)");
|
|
317
|
+
function mainRepoRootOf(dir) {
|
|
318
|
+
try {
|
|
319
|
+
const st = statSync(join3(dir, ".git"));
|
|
320
|
+
if (!st.isFile()) return null;
|
|
321
|
+
} catch {
|
|
322
|
+
return null;
|
|
323
|
+
}
|
|
324
|
+
try {
|
|
325
|
+
const gitLine = readFileSync3(join3(dir, ".git"), "utf-8").trim();
|
|
326
|
+
if (!gitLine.startsWith("gitdir:")) return null;
|
|
327
|
+
const gitdir = resolve2(dir, gitLine.slice("gitdir:".length).trim());
|
|
328
|
+
const commondir = readFileSync3(join3(gitdir, "commondir"), "utf-8").trim();
|
|
329
|
+
if (commondir.length === 0) return null;
|
|
330
|
+
return dirname(resolve2(gitdir, commondir));
|
|
331
|
+
} catch {
|
|
332
|
+
return null;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
299
335
|
function findWorkspaceDir(start) {
|
|
300
336
|
let dir = start !== void 0 && start.length > 0 ? start : process.cwd();
|
|
301
337
|
for (; ; ) {
|
|
302
338
|
if (existsSync3(join3(dir, WORKSPACE_DIR_NAME))) return dir;
|
|
339
|
+
const mainRoot = mainRepoRootOf(dir);
|
|
340
|
+
if (mainRoot !== null && existsSync3(join3(mainRoot, WORKSPACE_DIR_NAME))) return mainRoot;
|
|
303
341
|
const parent = dirname(dir);
|
|
304
342
|
if (parent === dir) return null;
|
|
305
343
|
dir = parent;
|
|
@@ -319,16 +357,16 @@ function readWorkspaceConfig(workspaceDir) {
|
|
|
319
357
|
if (typeof parsed.serverUrl === "string" && parsed.serverUrl.length > 0) {
|
|
320
358
|
const r = ServerUrlSchema.safeParse(parsed.serverUrl);
|
|
321
359
|
if (r.success) cfg.serverUrl = r.data;
|
|
322
|
-
else
|
|
360
|
+
else warnOnce2("workspace-invalid-serverurl", `[siming] \u5FFD\u7565\u975E\u6CD5 .siming/config.json serverUrl="${parsed.serverUrl}"`);
|
|
323
361
|
}
|
|
324
362
|
if (typeof parsed.defaultProject === "string" && parsed.defaultProject.length > 0) {
|
|
325
363
|
const r = DefaultProjectSchema.safeParse(parsed.defaultProject);
|
|
326
364
|
if (r.success) cfg.defaultProject = r.data;
|
|
327
|
-
else
|
|
365
|
+
else warnOnce2("workspace-invalid-defaultproject", `[siming] \u5FFD\u7565\u975E\u6CD5 .siming/config.json defaultProject="${parsed.defaultProject}"`);
|
|
328
366
|
}
|
|
329
367
|
return Object.keys(cfg).length > 0 ? cfg : null;
|
|
330
368
|
} catch (e) {
|
|
331
|
-
|
|
369
|
+
warnOnce2("workspace-read-failed", `[siming] \u8BFB\u53D6\u5DE5\u4F5C\u533A\u914D\u7F6E\u5931\u8D25: ${e instanceof Error ? e.message : String(e)}`);
|
|
332
370
|
return null;
|
|
333
371
|
}
|
|
334
372
|
}
|
|
@@ -522,18 +560,23 @@ function writeGlobalAuthToken(token, path) {
|
|
|
522
560
|
|
|
523
561
|
// src/client/http-client.ts
|
|
524
562
|
var SimingHttpClient = class {
|
|
525
|
-
/** T202609150002:通道 source 标识(x-siming-source header 单一注入口;Web 通道由 web client 固定携带 web
|
|
563
|
+
/** T202609150002:通道 source 标识(x-siming-source header 单一注入口;Web 通道由 web client 固定携带 web)。
|
|
564
|
+
* baseUrl 可传常量或 resolver(T202610150001):长驻进程(mcp-serve)传 resolver 每请求现解析——
|
|
565
|
+
* 与 token 每请求解析(request() 内 resolveAuthToken)同策略,配置补齐/变更后自愈,无需重启。 */
|
|
526
566
|
constructor(baseUrl, source = "cli") {
|
|
527
567
|
this.baseUrl = baseUrl;
|
|
528
568
|
this.source = source;
|
|
529
569
|
}
|
|
530
570
|
baseUrl;
|
|
531
571
|
source;
|
|
532
|
-
|
|
572
|
+
resolveBase() {
|
|
573
|
+
return typeof this.baseUrl === "string" ? this.baseUrl : this.baseUrl();
|
|
574
|
+
}
|
|
575
|
+
/** server base URL(诊断输出用——auth whoami 展示目标地址);每访问现解析 */
|
|
533
576
|
get url() {
|
|
534
|
-
return this.
|
|
577
|
+
return this.resolveBase();
|
|
535
578
|
}
|
|
536
|
-
async request(method, path, body) {
|
|
579
|
+
async request(method, path, body, baseOverride) {
|
|
537
580
|
const token = resolveAuthToken();
|
|
538
581
|
const headers = {
|
|
539
582
|
...token !== void 0 ? { Authorization: `Bearer ${token}` } : {},
|
|
@@ -541,7 +584,8 @@ var SimingHttpClient = class {
|
|
|
541
584
|
// T202609150002:issue 域通道注入(服务端按 header 判定 source,缺省 web)
|
|
542
585
|
"x-siming-source": this.source
|
|
543
586
|
};
|
|
544
|
-
|
|
587
|
+
const base = baseOverride ?? this.resolveBase();
|
|
588
|
+
return fetch(`${base}${path}`, {
|
|
545
589
|
method,
|
|
546
590
|
headers,
|
|
547
591
|
...body !== void 0 ? { body: JSON.stringify(body) } : {}
|
|
@@ -561,25 +605,27 @@ var SimingHttpClient = class {
|
|
|
561
605
|
}
|
|
562
606
|
/** DELETE 返回 204 无 body,成功即 ok(void) */
|
|
563
607
|
async delete(path) {
|
|
608
|
+
const base = this.resolveBase();
|
|
564
609
|
try {
|
|
565
|
-
const res = await this.request("DELETE", path);
|
|
610
|
+
const res = await this.request("DELETE", path, void 0, base);
|
|
566
611
|
if (res.ok) return ok2(void 0);
|
|
567
612
|
const body = await res.json().catch(() => void 0);
|
|
568
613
|
return fail(extractError(res, body));
|
|
569
614
|
} catch (e) {
|
|
570
|
-
return fail(networkError(e));
|
|
615
|
+
return fail(networkError(e, `${base}${path}`));
|
|
571
616
|
}
|
|
572
617
|
}
|
|
573
618
|
async json(method, path, body) {
|
|
619
|
+
const base = this.resolveBase();
|
|
574
620
|
try {
|
|
575
|
-
const res = await this.request(method, path, body);
|
|
621
|
+
const res = await this.request(method, path, body, base);
|
|
576
622
|
const data = await res.json().catch(() => void 0);
|
|
577
623
|
if (!res.ok) {
|
|
578
624
|
return fail(extractError(res, data));
|
|
579
625
|
}
|
|
580
626
|
return ok2(data);
|
|
581
627
|
} catch (e) {
|
|
582
|
-
return fail(networkError(e));
|
|
628
|
+
return fail(networkError(e, `${base}${path}`));
|
|
583
629
|
}
|
|
584
630
|
}
|
|
585
631
|
};
|
|
@@ -614,31 +660,55 @@ function extractError(res, body) {
|
|
|
614
660
|
}
|
|
615
661
|
return error;
|
|
616
662
|
}
|
|
617
|
-
|
|
618
|
-
|
|
663
|
+
var warnedOnce3 = /* @__PURE__ */ new Set();
|
|
664
|
+
function warnOnce3(kind, message) {
|
|
665
|
+
if (warnedOnce3.has(kind)) return;
|
|
666
|
+
warnedOnce3.add(kind);
|
|
667
|
+
console.error(message);
|
|
668
|
+
}
|
|
669
|
+
function networkError(e, target) {
|
|
670
|
+
const base = e instanceof Error ? e.message : String(e);
|
|
671
|
+
let message = base;
|
|
672
|
+
if (e instanceof Error && e.cause !== void 0 && e.cause !== null) {
|
|
673
|
+
const cause = e.cause;
|
|
674
|
+
const code = cause !== null && typeof cause === "object" && "code" in cause ? cause.code : void 0;
|
|
675
|
+
const causeMsg = typeof code === "string" && code.length > 0 ? code : cause instanceof Error ? cause.message : String(cause);
|
|
676
|
+
message = `${base}\uFF08${causeMsg}\uFF09`;
|
|
677
|
+
}
|
|
678
|
+
if (target !== void 0) message = `${message} [${target}]`;
|
|
679
|
+
return { message, httpStatus: 0 };
|
|
680
|
+
}
|
|
681
|
+
function resolveServerUrlDetailed(baseUrl) {
|
|
682
|
+
if (baseUrl !== void 0) return { url: baseUrl.replace(/\/$/, ""), source: "flag" };
|
|
683
|
+
const envUrl = process.env.SIMING_SERVER_URL;
|
|
684
|
+
if (envUrl !== void 0) {
|
|
685
|
+
const r = ServerUrlSchema.safeParse(envUrl);
|
|
686
|
+
if (r.success) return { url: r.data.replace(/\/$/, ""), source: "env" };
|
|
687
|
+
warnOnce3("invalid-env-serverurl", `[siming] \u5FFD\u7565\u975E\u6CD5 SIMING_SERVER_URL="${envUrl}"\uFF0C\u964D\u7EA7\u5230\u672C\u5730\u914D\u7F6E/\u9ED8\u8BA4`);
|
|
688
|
+
}
|
|
689
|
+
const workspaceUrl = readWorkspaceConfig()?.serverUrl;
|
|
690
|
+
if (workspaceUrl !== void 0) return { url: workspaceUrl.replace(/\/$/, ""), source: "workspace" };
|
|
691
|
+
const local = readLocalConfig();
|
|
692
|
+
if (local !== null) return { url: local.serverUrl.replace(/\/$/, ""), source: "global" };
|
|
693
|
+
return { url: `http://localhost:${resolveLocalSimingPort()}`, source: "default" };
|
|
619
694
|
}
|
|
620
695
|
function resolveServerUrl(baseUrl) {
|
|
621
|
-
|
|
622
|
-
if (url === void 0) {
|
|
623
|
-
const envUrl = process.env.SIMING_SERVER_URL;
|
|
624
|
-
if (envUrl !== void 0) {
|
|
625
|
-
const r = ServerUrlSchema.safeParse(envUrl);
|
|
626
|
-
if (r.success) {
|
|
627
|
-
url = r.data;
|
|
628
|
-
} else {
|
|
629
|
-
console.error(`[siming] \u5FFD\u7565\u975E\u6CD5 SIMING_SERVER_URL="${envUrl}"\uFF0C\u964D\u7EA7\u5230\u672C\u5730\u914D\u7F6E/\u9ED8\u8BA4`);
|
|
630
|
-
}
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
url = url ?? readWorkspaceConfig()?.serverUrl ?? getLocalServerUrl();
|
|
634
|
-
return url.replace(/\/$/, "");
|
|
696
|
+
return resolveServerUrlDetailed(baseUrl).url;
|
|
635
697
|
}
|
|
636
698
|
function createClient(baseUrl, source) {
|
|
637
|
-
return new SimingHttpClient(resolveServerUrl(baseUrl), source);
|
|
699
|
+
if (baseUrl !== void 0) return new SimingHttpClient(resolveServerUrl(baseUrl), source);
|
|
700
|
+
return new SimingHttpClient(() => resolveServerUrl(), source);
|
|
638
701
|
}
|
|
639
702
|
|
|
640
703
|
// src/commands/healthcheck.ts
|
|
641
704
|
var HEALTHCHECK_TIMEOUT_MS = 2e3;
|
|
705
|
+
var SOURCE_LABEL = {
|
|
706
|
+
flag: "CLI \u53C2\u6570 --url",
|
|
707
|
+
env: "\u73AF\u5883\u53D8\u91CF SIMING_SERVER_URL",
|
|
708
|
+
workspace: "\u5DE5\u4F5C\u533A .siming/config.json",
|
|
709
|
+
global: "\u5168\u5C40 ~/.siming/config.json",
|
|
710
|
+
default: "\u9ED8\u8BA4\u63A8\u5BFC"
|
|
711
|
+
};
|
|
642
712
|
async function runHealthcheck(opts) {
|
|
643
713
|
try {
|
|
644
714
|
const res = await fetch(`${opts.url}/health`, { signal: AbortSignal.timeout(HEALTHCHECK_TIMEOUT_MS) });
|
|
@@ -652,12 +722,21 @@ async function runHealthcheck(opts) {
|
|
|
652
722
|
}
|
|
653
723
|
}
|
|
654
724
|
async function healthcheckCommand(opts) {
|
|
655
|
-
const
|
|
725
|
+
const resolved = resolveServerUrlDetailed(opts.url);
|
|
726
|
+
const result = await runHealthcheck({ url: resolved.url });
|
|
656
727
|
if (result.ok) {
|
|
657
|
-
ok(`server healthy (v${result.version})`);
|
|
728
|
+
ok(`server healthy (v${result.version}) [${resolved.url}\uFF08\u6765\u6E90: ${SOURCE_LABEL[resolved.source]}\uFF09]`);
|
|
729
|
+
} else if (resolved.source === "default") {
|
|
730
|
+
err(
|
|
731
|
+
`\u672A\u53D1\u73B0\u4EFB\u4F55 siming \u914D\u7F6E\uFF08env/\u5DE5\u4F5C\u533A/\u5168\u5C40\u5C42\u5747\u672A\u8BBE\u7F6E serverUrl\uFF09\uFF0C\u6309\u9ED8\u8BA4\u5730\u5740 ${resolved.url} \u63A2\u6D4B\u5931\u8D25: ${result.error ?? "unknown"}`
|
|
732
|
+
);
|
|
733
|
+
info(
|
|
734
|
+
"hint: server \u672A\u542F\u52A8\u5219\u5148\u8FD0\u884C `siming server start`\uFF1Bserver \u5DF2\u542F\u52A8\u4F46\u7AEF\u53E3\u4E0D\u540C\uFF0C\u5219\u5728\u9879\u76EE\u6839\u521B\u5EFA .siming/config.json \u914D\u7F6E serverUrl\uFF0C\u6216\u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF SIMING_SERVER_URL"
|
|
735
|
+
);
|
|
736
|
+
process.exitCode = 1;
|
|
658
737
|
} else {
|
|
659
|
-
err(`server
|
|
660
|
-
info("hint:
|
|
738
|
+
err(`server \u4E0D\u53EF\u8FBE\uFF08${resolved.url}\uFF0C\u6765\u6E90: ${SOURCE_LABEL[resolved.source]}\uFF09: ${result.error ?? "unknown"}`);
|
|
739
|
+
info("hint: \u786E\u8BA4\u8BE5\u5730\u5740\u4E0A\u7684 server \u662F\u5426\u5B58\u6D3B\uFF08siming server status\uFF09\uFF1B\u5730\u5740\u4E0D\u5BF9\u5219\u4FEE\u6B63\u5BF9\u5E94\u6765\u6E90\u5C42\u7684 serverUrl \u914D\u7F6E");
|
|
661
740
|
process.exitCode = 1;
|
|
662
741
|
}
|
|
663
742
|
}
|
|
@@ -1089,7 +1168,18 @@ ${ctx.reposScanDetail}`
|
|
|
1089
1168
|
const leakByRepo = [];
|
|
1090
1169
|
const errRepos = [];
|
|
1091
1170
|
for (const repo of hitRepos) {
|
|
1092
|
-
const
|
|
1171
|
+
const cnt = await ctx.runGit(["rev-list", "--count", `${base}..${sha}`], repo);
|
|
1172
|
+
if (!cnt.ok) {
|
|
1173
|
+
errRepos.push(repo);
|
|
1174
|
+
continue;
|
|
1175
|
+
}
|
|
1176
|
+
const n = Number.parseInt(cnt.stdout.trim(), 10);
|
|
1177
|
+
if (!Number.isSafeInteger(n) || n < 0) {
|
|
1178
|
+
errRepos.push(repo);
|
|
1179
|
+
continue;
|
|
1180
|
+
}
|
|
1181
|
+
if (n === 0) continue;
|
|
1182
|
+
const r = await ctx.runGit(["diff", "--name-only", `${base}...${sha}`], repo);
|
|
1093
1183
|
if (!r.ok) {
|
|
1094
1184
|
errRepos.push(repo);
|
|
1095
1185
|
continue;
|
|
@@ -1098,7 +1188,7 @@ ${ctx.reposScanDetail}`
|
|
|
1098
1188
|
if (leaked.length > 0) leakByRepo.push({ repo, leaked });
|
|
1099
1189
|
}
|
|
1100
1190
|
if (errRepos.length > 0) {
|
|
1101
|
-
return fail3(type, `\u7248\u672C
|
|
1191
|
+
return fail3(type, `\u7248\u672C\u5224\u5B9A\u5931\u8D25\uFF08\u4ED3 ${errRepos.join("\u3001")}\uFF09`, `\u68C0\u67E5 verifiedCommit \u4E0E\u57FA\u7840\u5206\u652F\u53EF\u7528\u6027
|
|
1102
1192
|
${ctx.reposScanDetail}`);
|
|
1103
1193
|
}
|
|
1104
1194
|
if (leakByRepo.length > 0) {
|
|
@@ -1106,8 +1196,8 @@ ${ctx.reposScanDetail}`);
|
|
|
1106
1196
|
const suffix = leakByRepo.length > 3 ? `\uFF08\u53E6\u6709 ${leakByRepo.length - 3} \u4ED3\u6CC4\u6F0F\u89C1\u9010\u4ED3\u91CD\u67E5\uFF09` : "";
|
|
1107
1197
|
return fail3(
|
|
1108
1198
|
type,
|
|
1109
|
-
`verifiedCommit \
|
|
1110
|
-
`\
|
|
1199
|
+
`verifiedCommit \u672A\u5B8C\u5168\u8FDB\u5165\u57FA\u7840\u5206\u652F ${base}\u2014\u2014${lines.join("\uFF1B")}${suffix}`,
|
|
1200
|
+
`\u5C06\u542B\u9A8C\u8BC1\u7248\u672C\u7684\u4EFB\u52A1\u5206\u652F\u5408\u5E76\u8FDB\u57FA\u7840\u5206\u652F\u540E\u91CD\u8BD5\uFF08\u5E76\u884C\u4EFB\u52A1\u81F4\u57FA\u7840\u5206\u652F\u524D\u8FDB\u7684\u5206\u53C9\u573A\u666F\uFF1A\u91CD\u8D70\u5408\u5E76\uFF1B\u65E0\u6CD5\u53EF\u9760\u5408\u5E76\u65F6\u7ECF\u7528\u6237\u660E\u793A\u540E force \u63A8\u8FDB\u5E76\u7559\u75D5\uFF09
|
|
1111
1201
|
${ctx.reposScanDetail}`
|
|
1112
1202
|
);
|
|
1113
1203
|
}
|
|
@@ -1116,7 +1206,7 @@ ${ctx.reposScanDetail}`
|
|
|
1116
1206
|
return {
|
|
1117
1207
|
type,
|
|
1118
1208
|
status: "pass",
|
|
1119
|
-
detail: `verifiedCommit ${sha} \
|
|
1209
|
+
detail: `verifiedCommit ${sha} \u5DF2\u5305\u542B\u4E8E\u57FA\u7840\u5206\u652F ${base}\uFF08\u57FA\u7840\u5206\u652F\u524D\u8FDB\u4E0D\u5224\u6CC4\u6F0F\uFF1B\u547D\u4E2D\u4ED3 ${hitRepos.join("\u3001")}\uFF1B\u6587\u6863\u8DEF\u5F84\u8C41\u514D ${ctx.docPaths.join(" ")}${naPart}\uFF09
|
|
1120
1210
|
${ctx.reposScanDetail}`
|
|
1121
1211
|
};
|
|
1122
1212
|
}
|
|
@@ -1222,13 +1312,13 @@ function auditAiChecks(aiChecks, record) {
|
|
|
1222
1312
|
results.push({ id: check.id, item: check.item, status: "pass", detail: "\u5B8C\u6210\u5224\u5B9A\u9879\u5DF2\u81EA\u68C0\u901A\u8FC7\uFF08refId \u5173\u8054\uFF09" });
|
|
1223
1313
|
continue;
|
|
1224
1314
|
}
|
|
1225
|
-
const rejected = (record?.checks ?? []).
|
|
1315
|
+
const rejected = (record?.checks ?? []).find((c) => c.refId === check.id && c.passed === false);
|
|
1226
1316
|
if (rejected) {
|
|
1227
1317
|
results.push({
|
|
1228
1318
|
id: check.id,
|
|
1229
1319
|
item: check.item,
|
|
1230
1320
|
status: "fail",
|
|
1231
|
-
detail: `\u7559\u75D5\u7ED3\u8BBA\u672A\u901A\u8FC7\
|
|
1321
|
+
detail: `\u7559\u75D5\u7ED3\u8BBA\u672A\u901A\u8FC7\uFF08entry ${rejected.id} refId=${check.id} passed=false\uFF09\u3002\u4FEE\u590D\uFF1A\u91CD\u505A\u540E\u6309 entry \u7FFB\u7EFF\uFF08CLI record-check-patch --check ${rejected.id}\uFF1BMCP action=record-check-patch checkId=${rejected.id} passed=true\uFF09\uFF0C\u6216\u91CD\u505A\u540E record-check-add \u5E26 refId=${check.id} \u91CD\u8BB0`
|
|
1232
1322
|
});
|
|
1233
1323
|
continue;
|
|
1234
1324
|
}
|
|
@@ -1242,12 +1332,20 @@ function auditAiChecks(aiChecks, record) {
|
|
|
1242
1332
|
id: check.id,
|
|
1243
1333
|
item: check.item,
|
|
1244
1334
|
status: "fail",
|
|
1245
|
-
|
|
1335
|
+
// T202610130004 C3:过短分支同构补 item 原文与操作指引(同模糊语分支——无留痕时 patch 无目标,指引指向 add 带 refId)
|
|
1336
|
+
detail: `item\u300C${check.item}\u300D\u8FC7\u77ED\uFF08${check.item.length} < ${MIN_AI_CHECK_ITEM_LENGTH} \u5B57\u7B26\uFF0C\u6700\u5C0F\u5F62\u6001\u8981\u6C42\u53EF\u6838\u5BF9\u7684\u5177\u4F53\u4E8B\u5B9E\uFF09\u3002\u4FEE\u590D\uFF1Arecord-check-add \u5E26 refId=${check.id}\uFF08CLI --ref-id\uFF09+ \u5177\u4F53\u4E8B\u5B9E + passed=true`
|
|
1246
1337
|
});
|
|
1247
1338
|
continue;
|
|
1248
1339
|
}
|
|
1249
1340
|
if (VAGUE_AI_CHECK_BLACKLIST.some((w) => lowered.includes(w))) {
|
|
1250
|
-
results.push({
|
|
1341
|
+
results.push({
|
|
1342
|
+
id: check.id,
|
|
1343
|
+
item: check.item,
|
|
1344
|
+
status: "fail",
|
|
1345
|
+
// T202610130004 C3(I202610120001):模糊语分支仅在无 refId 留痕时触发,record-check-patch 无可修补目标(按 entry id 寻址)——
|
|
1346
|
+
// 指引指向 add 带 refId 重记;补 item 原文让被打回方定位是哪条自检项被判模糊
|
|
1347
|
+
detail: `item\u300C${check.item}\u300D\u4E3A\u6A21\u7CCA\u5B8C\u6210\u8BED\uFF08\u547D\u4E2D\u9ED1\u540D\u5355\u300C${VAGUE_AI_CHECK_BLACKLIST.join("/")}\u300D\uFF09\u3002\u4FEE\u590D\uFF1A\u6539\u5199\u4E3A\u53EF\u6838\u5BF9\u7684\u5177\u4F53\u4E8B\u5B9E\u540E record-check-add \u5E26 refId=${check.id}\uFF08CLI --ref-id\uFF09+ passed=true \u91CD\u8BB0`
|
|
1348
|
+
});
|
|
1251
1349
|
continue;
|
|
1252
1350
|
}
|
|
1253
1351
|
results.push({
|
|
@@ -1353,7 +1451,7 @@ function scanWorkspaceRepos(cwd, scanDepthOverride) {
|
|
|
1353
1451
|
var execFileAsync = promisify(execFile);
|
|
1354
1452
|
var defaultGitRunner = async (args, cwd) => {
|
|
1355
1453
|
try {
|
|
1356
|
-
const { stdout, stderr } = await execFileAsync("git", args, { cwd, timeout: 1e4 });
|
|
1454
|
+
const { stdout, stderr } = await execFileAsync("git", ["-c", "core.quotepath=false", ...args], { cwd, timeout: 1e4 });
|
|
1357
1455
|
return { ok: true, stdout, stderr };
|
|
1358
1456
|
} catch (err2) {
|
|
1359
1457
|
const e = err2;
|
|
@@ -2195,13 +2293,13 @@ function writeWorkspaceLayer(token, kind, opts) {
|
|
|
2195
2293
|
return ok2({ path: devJsonPath, kind, warnedDirectStart: !hadIsolationKeys, overwrote: hadToken });
|
|
2196
2294
|
}
|
|
2197
2295
|
function readStdinLine(stream) {
|
|
2198
|
-
return new Promise((
|
|
2296
|
+
return new Promise((resolve4) => {
|
|
2199
2297
|
let data = "";
|
|
2200
2298
|
const finish = (value) => {
|
|
2201
2299
|
stream.removeAllListeners("readable");
|
|
2202
2300
|
stream.removeAllListeners("end");
|
|
2203
2301
|
stream.destroy?.();
|
|
2204
|
-
|
|
2302
|
+
resolve4(value);
|
|
2205
2303
|
};
|
|
2206
2304
|
stream.setEncoding("utf8");
|
|
2207
2305
|
stream.on("end", () => finish(data));
|
|
@@ -2680,7 +2778,7 @@ function createMcpServer() {
|
|
|
2680
2778
|
const client = createClient(void 0, "mcp");
|
|
2681
2779
|
server.tool(
|
|
2682
2780
|
"siming_task",
|
|
2683
|
-
'task \u8D44\u6E90\u57DF\u805A\u5408\u5DE5\u5177\uFF08\u4EFB\u52A1\u5168\u64CD\u4F5C\u7ECF\u672C\u5DE5\u5177 + action \u53C2\u6570\uFF09\u3002action \u5FC5\u586B\uFF1B\u8C03\u7528\u65B9\u5E94\u5728 fieldMask \u4E2D\u5217\u51FA\u672C\u6B21\u771F\u5B9E\u63D0\u4F9B\u7684\u53EF\u9009\u5B57\u6BB5\uFF0Cmask \u5916\u7531\u5BBF\u4E3B\u81EA\u52A8\u586B\u5145\u7684\u7A7A\u4E32\u3001\u7A7A\u6570\u7EC4\u3001false\u30010 \u5747\u5FFD\u7565\uFF0Cmask \u5185\u7A7A\u6570\u7EC4/false \u8868\u793A\u663E\u5F0F\u6E05\u7A7A\u6216\u5173\u95ED\uFF1B\u5404 action \u56FA\u5B9A\u5FC5\u586B\u5B57\u6BB5\u65E0\u9700\u5199\u5165 mask\u3002\u5176\u4F59\u53C2\u6570\u5168\u53EF\u9009\u3001\u6309 action \u8FD0\u884C\u65F6\u6821\u9A8C\u5FC5\u586B\uFF08\u7F3A\u5931\u8FD4\u56DE\u5931\u8D25\u4E09\u8981\u7D20\uFF1A\u5BF9\u8C61+\u6839\u56E0+\u4FEE\u590D\u6307\u5F15\uFF09\u3002projectId \u4E3A key|id \u53CC\u5F62\u6001\uFF0C\u901A\u9053\u5C42\u81EA\u52A8\u5F52\u4E00\u4E3A 24-hex id\uFF1B\u663E\u5F0F\u6307\u5B9A\u89E3\u6790\u5931\u8D25\u62A5\u9519\u4E0D\u515C\u5E95\uFF1B\u7F3A\u7701\u8BED\u4E49\u6309 action\uFF1Acreate \u843D\u9ED8\u8BA4\u9879\u76EE\u94FE\uFF08\u5DE5\u4F5C\u533A defaultProject \u5931\u6548\u62A5\u9519\uFF0C\u65E0\u914D\u7F6E\u4E0D\u4F20\u7531 server \u6309\u6A21\u677F\u5F52\u5C5E\u515C\u5E95\uFF09\uFF0Cquery \u4E0D\u8FC7\u6EE4\uFF08\u5168\u5C40\u67E5\u8BE2\uFF09\u3002\u5199\u64CD\u4F5C\uFF08create/doc-*/record-*/archnote-add/pause/resume/cancel\uFF09\u54CD\u5E94\u4E3A\u8F7B\u91CF\u56DE\u6267\uFF1A{taskId, updated(\u89E6\u53CA\u5B57\u6BB5\u8DEF\u5F84), entry(\u65B0\u6761\u76EE id+kind\uFF0C\u4F9B\u540E\u7EED patch \u5B9A\u4F4D), echo(\u5199\u5165\u5185\u5BB9\u56DE\u663E), updatedAt, task(\u4EFB\u52A1\u8FDB\u5EA6\u6458\u8981 progress: {completed,total})}\u2014\u2014\u4E0D\u8FD4\u56DE\u5B8C\u6574\u4EFB\u52A1\u5B9E\u4F53\u3002action \u6E05\u5355\uFF08\u62EC\u53F7\u5185\u4E3A\u8BE5 action \u5FC5\u586B\u53C2\u6570\uFF09\uFF1Acreate(templateId,taskTitle,track\uFF1Btrack \u652F\u6301\u7EC4\u5408\u8F68\u9053\u2014\u2014\u6570\u7EC4\u5F62\u6001\uFF08\u5982 ["backend","godot"]\uFF0C\u6210\u5458=\u6CE8\u518C\u8868 active \u5355\u8F68\uFF09\u6216\u5355\u503C string\uFF1Ball \u4E3A\u4EFB\u52A1\u7EA7\u901A\u914D\uFF08\u6FC0\u6D3B\u521B\u5EFA\u65F6\u70B9\u5168\u90E8\u542F\u7528\u5355\u8F68\uFF0C\u5355\u503C\u4F7F\u7528\uFF09\uFF1B\u53EF\u9009 type=feature|bugfix|ui-tweak|research\u3001skipNodes\u3001projectId\uFF1BtemplateId \u652F\u6301 code|id \u53CC\u5F62\u6001\u2014\u2014code \u4E3A\u6A21\u677F\u4E1A\u52A1\u6807\u8BC6\uFF08\u9879\u76EE\u5185\u552F\u4E00\u3001kebab-case \u5FC5\u542B\u8FDE\u5B57\u7B26\uFF0C\u5982 full-workflow\uFF09\uFF0C\u63A8\u8350\u5F15\u7528\u5F62\u6001\uFF0C\u5BFB\u5740\u987B\u914D projectId \u6307\u5B9A\u9879\u76EE\u57DF\uFF1B24-hex \u6570\u636E\u5E93 id \u76F4\u67E5\u517C\u5BB9\uFF1Bcode \u5F62\u6001\u4E0D\u5B58\u5728\u65F6\u9519\u8BEF\u542B candidates \u76F8\u8FD1\u5019\u9009\u6E05\u5355\uFF08id/code/name \u22645 \u6761\uFF09\uFF1B\u54CD\u5E94 {task, firstNode}\u2014\u2014firstNode \u5373\u9996\u8282\u70B9\u5B8C\u6574\u8D44\u6599\u5305\uFF0C\u514D\u8C03 context)\uFF1Bquery(taskId \u8FD4\u56DE\u5355\u4EFB\u52A1\u8BE6\u60C5\uFF0C\u7F3A\u7701\u8FD4\u56DE\u5217\u8868\uFF0C\u53EF\u9009 status/track/projectId/page/limit)\uFF1Bcontext(taskId\uFF1B\u53EF\u9009 view=basic|full\u2014\u2014basic \u7F3A\u7701\u4E0D\u643A\u5E26 artifact \u5168\u6587\u5FEB\u7167\uFF0Cfull \u65AD\u70B9\u7EED\u8DD1\u9700\u5386\u53F2\u4EA7\u7269\u5168\u6587\u65F6\u7528\u3002\u26A0 \u514D\u91CD\u8BFB\uFF1Aadvance/approve \u6D41\u8F6C\u54CD\u5E94\u5DF2\u542B\u4E0B\u4E00\u8282\u70B9\u5B8C\u6574\u8D44\u6599\u5305\uFF0C\u540C\u4F1A\u8BDD\u5185\u6D41\u8F6C\u540E\u76F4\u63A5\u5F00\u5DE5\u3001\u65E0\u9700\u518D\u8C03 context\uFF1B\u4EC5\u65B0\u4F1A\u8BDD/\u65AD\u70B9\u7EED\u8DD1\u8C03\u7528)\uFF1Bnode(taskId,view=prompt|skills\uFF1BnodeId \u7F3A\u7701\u7528\u5F53\u524D\u8282\u70B9\uFF1B\u26A0 view \u503C\u968F action \u4E0D\u540C\uFF1Anode\u2192prompt|skills\uFF0Ccontext\u2192basic|full\uFF0C\u9519\u914D\u62A5\u9519)\uFF1Badvance(taskId\uFF1Bnote \u5199 history\u3001summary \u5199 nodeRecords\uFF0C\u4E24\u4F4D\u72EC\u7ACB\uFF1B\u54CD\u5E94\u5DF2\u542B\u4E0B\u4E00\u8282\u70B9\u8D44\u6599\u5305\uFF0C\u540C\u4F1A\u8BDD\u514D\u91CD\u8BFB context\u3002\u26A0 T202609230001 \u8282\u70B9\u95E8\u7981\uFF1A\u914D\u7F6E\u4E86 toolChecks/aiChecks \u7684\u8282\u70B9\u63A8\u8FDB\u524D\u81EA\u52A8\u6267\u884C\u68C0\u67E5\u2014\u2014fail \u4F1A\u88AB\u6253\u56DE\u5E76\u8FD4\u56DE\u9010\u9879\u4FEE\u590D\u6307\u5F15\uFF08\u7ED3\u679C\u5DF2\u5199 history checks_rejected\uFF09\uFF0C\u6309\u6307\u5F15\u4FEE\u590D\u6216\u83B7\u7528\u6237\u8C41\u514D\u7559\u75D5\u540E\u91CD\u63A8\uFF1B\u975E\u4EBA\u5DE5\u5BA1\u6279\u8282\u70B9\u7981\u6B62\u56E0\u95E8\u7981\u4E2D\u65AD\u4EFB\u52A1\uFF08\u6253\u56DE\u4FE1\u606F\u5373\u7EE7\u7EED\u4F9D\u636E\uFF09\u3002force+forceReason \u6210\u5BF9\u63D0\u4F9B\u65F6\u53EF\u8D8A\u8FC7 fail \u5F3A\u5236\u63A8\u8FDB\u2014\u2014\u4EC5\u51ED\u7528\u6237\u660E\u793A\u6307\u4EE4\uFF0CAI \u7981\u6B62\u81EA\u51B3\uFF0C\u7406\u7531\u539F\u6587\u843D history \u5BA1\u8BA1)\uFF1Bcheck(taskId\uFF1B\u95E8\u7981\u53EA\u8BFB\u9884\u68C0\u2014\u2014\u9010\u9879\u62A5\u544A\u4E0D\u5199\u4EFB\u4F55\u72B6\u6001\uFF0Cadvance \u524D\u81EA\u67E5\u7528)\uFF1Bapprove(taskId,decision=approved|rejected\uFF1B\u53EF\u9009 comment\uFF1B\u54CD\u5E94\u5DF2\u542B\u4E0B\u4E00\u8282\u70B9\u8D44\u6599\u5305\uFF0C\u540C\u4F1A\u8BDD\u514D\u91CD\u8BFB context)\uFF1Bpause(taskId\uFF1B\u53EF\u9009 reason)\uFF1Bresume(taskId\uFF1B\u53EF\u9009 resumeNote)\uFF1Bcancel(taskId\uFF1B\u53EF\u9009 reason 1-500 \u5B57\u7B26\uFF1B\u26A0 \u7EC8\u6001\u4E0D\u53EF\u9006\u2014\u2014active/paused \u53EF\u53D6\u6D88\uFF0Ccompleted/cancelled \u62D2\u7EDD\u5E76\u8FD4\u56DE TASK_TERMINATED\uFF1B\u53D6\u6D88\u540E\u7ECF\u672C\u5DE5\u5177\u7684\u6D41\u8F6C\u4E0E\u8BB0\u5F55\u5199\u64CD\u4F5C\u88AB\u62D2)\uFF1Bhistory(taskId)\uFF1Binstance(taskId\u2014\u2014\u67E5\u770B\u4EFB\u52A1 DAG \u5B9E\u4F8B\u5FEB\u7167\uFF1A\u521B\u5EFA\u4EFB\u52A1\u65F6\u51BB\u7ED3\u7684\u6A21\u677F\u5B9E\u4F8B\uFF0C\u6A21\u677F\u540E\u7EED\u53D8\u66F4\u4E0D\u56DE\u6EAF)\u3002\u8BB0\u5F55\u5199\u5165\uFF1Arecord-set(taskId,node\uFF1Bsummary \u4E0E\u516D\u4E2A\u7ED3\u6784\u5316\u5B57\u6BB5\uFF08baseBranch/verifiedCommit/fixesApplied/testReport/deferredIssues/evidenceFiles\uFF09\u81F3\u5C11\u5176\u4E00\u2014\u2014\u7ED3\u6784\u5316\u5B57\u6BB5\u6309\u8282\u70B9 prompt\u300C\u7ED3\u6784\u5316\u5B57\u6BB5\u5199\u5165\u8981\u6C42\u300D\u9010\u5B57\u6BB5\u843D\u5E93\uFF0CPATCH \u8BED\u4E49=\u4EC5\u66F4\u65B0\u63D0\u4F9B\u5B57\u6BB5)\uFF1Brecord-check-add(taskId,node,item\uFF1B\u53EF\u9009 passed \u7F3A\u7701 true\u3001refId=aiChecks \u81EA\u68C0\u7559\u75D5\u951A\uFF08\u5BA1\u8BA1\u8BA4 refId===aiCheck.id \u4E14 passed=true\uFF0C\u7F3A\u7559\u75D5\u7684\u5B8C\u6210\u5224\u5B9A\u5BA1\u8BA1 fail\uFF09\u3001source=self|tool \u672C\u7248\u5DE5\u5177\u7F3A\u7701\u4E0D\u5199\uFF1B\u6279\u91CF checkItems \u5143\u7D20\u540C\u6784\uFF1B\u56DE\u6267 entry.id \u4F9B record-check-patch \u5B9A\u4F4D)\uFF1Brecord-check-patch(taskId,node,checkId\uFF1B\u53EF\u9009 passed/item/refId/source\uFF0C\u4EC5\u66F4\u65B0\u63D0\u4F9B\u5B57\u6BB5)\uFF1Brecord-artifact-add(taskId,node,artifactType=prd|tech|code|test|doc|other\uFF1Bpath \u7EAF\u5F15\u7528 / file \u8BFB\u672C\u673A\u6587\u4EF6 / content \u76F4\u4F20\u5168\u6587\u2014\u2014file \u4E0E content\u3001file \u4E0E path \u4E92\u65A5\uFF0Ccontent \u53EF\u4E0E path \u6210\u5BF9\u6216\u5355\u72EC\uFF0C\u5355\u72EC\u65F6\u767B\u8BB0\u503C\u5408\u6210 mcp-inline/<type>\uFF1B\u53EF\u9009 note)\uFF1Brecord-confirm(taskId,node,quote\u2014\u2014\u6682\u505C\u70B9\u7528\u6237\u786E\u8BA4\u539F\u6587\u9010\u5B57)\uFF1Brecord-decision-add(taskId,node,topic,decisionText)\uFF1Brecord-review-set(taskId,node,verdict=pass|fail,rounds,critical)\u3002\u9700\u6C42\u6587\u6863\uFF1Adoc-set(taskId\uFF1Bwhat/why/trackNote \u81F3\u5C11\u4F20\u4E00)\uFF1Bdoc-acceptance-add(taskId,text)\uFF1Bdoc-non-goal-add(taskId,text)\u3002\u7D20\u6750\uFF1Aarchnote-add(taskId,text)\u3002\u6279\u91CF\u5F62\u6001\uFF08\u63A8\u8350\uFF0C\u516D\u7C7B\u540C\u6784\uFF09\uFF1Arecord-check-add \u4F20 checkItems=[{item,passed?}]\u3001record-artifact-add \u4F20 artifactEntries=[{artifactType,path?/file?/content?,note?}]\u3001record-decision-add \u4F20 decisionEntries=[{topic,decisionText}]\u3001doc-acceptance-add/doc-non-goal-add/archnote-add \u4F20 textItems=[string]\u2014\u2014\u6279\u91CF\u53C2\u6570\u4E0E\u5355\u6761\u53C2\u6570\u4E8C\u9009\u4E00\uFF0C\u4E00\u6B21\u8C03\u7528\u5199\u591A\u6761\uFF08\u4E0A\u9650 50 \u6761/\u6279\uFF0Cartifact \u5168\u6587\u5FEB\u7167\u603B\u91CF \u22642M \u5B57\u7B26/\u6279\uFF09\uFF1B\u90E8\u5206\u5931\u8D25\u4FDD\u7559\u6210\u529F\u6761\u76EE\u5E76\u9010\u6761\u62A5\u544A\uFF08failures[].index=\u539F\u59CB\u63D0\u4EA4\u5E8F\uFF0C\u53EA\u91CD\u8BD5\u5931\u8D25\u9879\uFF09\uFF0Capplied=0 \u6574\u4F53\u62A5\u5931\u8D25\u3002',
|
|
2781
|
+
'task \u8D44\u6E90\u57DF\u805A\u5408\u5DE5\u5177\uFF08\u4EFB\u52A1\u5168\u64CD\u4F5C\u7ECF\u672C\u5DE5\u5177 + action \u53C2\u6570\uFF09\u3002action \u5FC5\u586B\uFF1B\u8C03\u7528\u65B9\u5E94\u5728 fieldMask \u4E2D\u5217\u51FA\u672C\u6B21\u771F\u5B9E\u63D0\u4F9B\u7684\u53EF\u9009\u5B57\u6BB5\uFF0Cmask \u5916\u7531\u5BBF\u4E3B\u81EA\u52A8\u586B\u5145\u7684\u7A7A\u4E32\u3001\u7A7A\u6570\u7EC4\u3001false\u30010 \u5747\u5FFD\u7565\uFF0Cmask \u5185\u7A7A\u6570\u7EC4/false \u8868\u793A\u663E\u5F0F\u6E05\u7A7A\u6216\u5173\u95ED\uFF1B\u5404 action \u56FA\u5B9A\u5FC5\u586B\u5B57\u6BB5\u65E0\u9700\u5199\u5165 mask\u3002\u5176\u4F59\u53C2\u6570\u5168\u53EF\u9009\u3001\u6309 action \u8FD0\u884C\u65F6\u6821\u9A8C\u5FC5\u586B\uFF08\u7F3A\u5931\u8FD4\u56DE\u5931\u8D25\u4E09\u8981\u7D20\uFF1A\u5BF9\u8C61+\u6839\u56E0+\u4FEE\u590D\u6307\u5F15\uFF09\u3002projectId \u4E3A key|id \u53CC\u5F62\u6001\uFF0C\u901A\u9053\u5C42\u81EA\u52A8\u5F52\u4E00\u4E3A 24-hex id\uFF1B\u663E\u5F0F\u6307\u5B9A\u89E3\u6790\u5931\u8D25\u62A5\u9519\u4E0D\u515C\u5E95\uFF1B\u7F3A\u7701\u8BED\u4E49\u6309 action\uFF1Acreate \u843D\u9ED8\u8BA4\u9879\u76EE\u94FE\uFF08\u5DE5\u4F5C\u533A defaultProject \u5931\u6548\u62A5\u9519\uFF0C\u65E0\u914D\u7F6E\u4E0D\u4F20\u7531 server \u6309\u6A21\u677F\u5F52\u5C5E\u515C\u5E95\uFF09\uFF0Cquery \u4E0D\u8FC7\u6EE4\uFF08\u5168\u5C40\u67E5\u8BE2\uFF09\u3002\u5199\u64CD\u4F5C\uFF08create/doc-*/record-*/archnote-add/pause/resume/cancel\uFF09\u54CD\u5E94\u4E3A\u8F7B\u91CF\u56DE\u6267\uFF1A{taskId, updated(\u89E6\u53CA\u5B57\u6BB5\u8DEF\u5F84), entry(\u65B0\u6761\u76EE id+kind\uFF0C\u4F9B\u540E\u7EED patch \u5B9A\u4F4D), echo(\u5199\u5165\u5185\u5BB9\u56DE\u663E), updatedAt, task(\u4EFB\u52A1\u8FDB\u5EA6\u6458\u8981 progress: {completed,total})}\u2014\u2014\u4E0D\u8FD4\u56DE\u5B8C\u6574\u4EFB\u52A1\u5B9E\u4F53\u3002action \u6E05\u5355\uFF08\u62EC\u53F7\u5185\u4E3A\u8BE5 action \u5FC5\u586B\u53C2\u6570\uFF09\uFF1Acreate(templateId,taskTitle,track\uFF1Btrack \u652F\u6301\u7EC4\u5408\u8F68\u9053\u2014\u2014\u6570\u7EC4\u5F62\u6001\uFF08\u5982 ["backend","godot"]\uFF0C\u6210\u5458=\u6CE8\u518C\u8868 active \u5355\u8F68\uFF09\u6216\u5355\u503C string\uFF1Ball \u4E3A\u4EFB\u52A1\u7EA7\u901A\u914D\uFF08\u6FC0\u6D3B\u521B\u5EFA\u65F6\u70B9\u5168\u90E8\u542F\u7528\u5355\u8F68\uFF0C\u5355\u503C\u4F7F\u7528\uFF09\uFF1B\u53EF\u9009 type=feature|bugfix|ui-tweak|research\u3001skipNodes\u3001projectId\uFF1BtemplateId \u652F\u6301 code|id \u53CC\u5F62\u6001\u2014\u2014code \u4E3A\u6A21\u677F\u4E1A\u52A1\u6807\u8BC6\uFF08\u9879\u76EE\u5185\u552F\u4E00\u3001kebab-case \u5FC5\u542B\u8FDE\u5B57\u7B26\uFF0C\u5982 full-workflow\uFF09\uFF0C\u63A8\u8350\u5F15\u7528\u5F62\u6001\uFF0C\u5BFB\u5740\u987B\u914D projectId \u6307\u5B9A\u9879\u76EE\u57DF\uFF1B24-hex \u6570\u636E\u5E93 id \u76F4\u67E5\u517C\u5BB9\uFF1Bcode \u5F62\u6001\u4E0D\u5B58\u5728\u65F6\u9519\u8BEF\u542B candidates \u76F8\u8FD1\u5019\u9009\u6E05\u5355\uFF08id/code/name \u22645 \u6761\uFF09\uFF1B\u54CD\u5E94 {task, firstNode}\u2014\u2014firstNode \u5373\u9996\u8282\u70B9\u5B8C\u6574\u8D44\u6599\u5305\uFF0C\u514D\u8C03 context)\uFF1Bquery(taskId \u8FD4\u56DE\u5355\u4EFB\u52A1\u8BE6\u60C5\uFF0C\u7F3A\u7701\u8FD4\u56DE\u5217\u8868\uFF0C\u53EF\u9009 status/track/projectId/page/limit)\uFF1Bcontext(taskId\uFF1B\u53EF\u9009 view=basic|full\u2014\u2014basic \u7F3A\u7701\u4E0D\u643A\u5E26 artifact \u5168\u6587\u5FEB\u7167\uFF0Cfull \u65AD\u70B9\u7EED\u8DD1\u9700\u5386\u53F2\u4EA7\u7269\u5168\u6587\u65F6\u7528\u3002\u26A0 \u514D\u91CD\u8BFB\uFF1Aadvance/approve \u6D41\u8F6C\u54CD\u5E94\u5DF2\u542B\u4E0B\u4E00\u8282\u70B9\u5B8C\u6574\u8D44\u6599\u5305\uFF0C\u540C\u4F1A\u8BDD\u5185\u6D41\u8F6C\u540E\u76F4\u63A5\u5F00\u5DE5\u3001\u65E0\u9700\u518D\u8C03 context\uFF1B\u4EC5\u65B0\u4F1A\u8BDD/\u65AD\u70B9\u7EED\u8DD1\u8C03\u7528)\uFF1Bnode(taskId,view=prompt|skills\uFF1BnodeId \u7F3A\u7701\u7528\u5F53\u524D\u8282\u70B9\uFF1B\u26A0 view \u503C\u968F action \u4E0D\u540C\uFF1Anode\u2192prompt|skills\uFF0Ccontext\u2192basic|full\uFF0C\u9519\u914D\u62A5\u9519)\uFF1Badvance(taskId\uFF1Bnote \u5199 history\u3001summary \u5199 nodeRecords\uFF0C\u4E24\u4F4D\u72EC\u7ACB\uFF1B\u26A0 T202610130004 \u7EC8\u6001\u6536\u5C3E\uFF1A\u4EFB\u52A1\u5904\u4E8E\u7EC8\u8282\u70B9\u65F6 advance \u5FC5\u5E26 finalize=true \u4F5C\u6536\u5C3E\u786E\u8BA4\uFF08\u7F3A\u7701\u88AB\u62D2\u5E76\u8FD4\u56DE\u63D0\u793A\uFF09\uFF0C\u4E2D\u95F4\u8282\u70B9\u5FFD\u7565\u8BE5\u53C2\u6570\uFF1B\u54CD\u5E94\u5DF2\u542B\u4E0B\u4E00\u8282\u70B9\u8D44\u6599\u5305\uFF0C\u540C\u4F1A\u8BDD\u514D\u91CD\u8BFB context\u3002\u26A0 T202609230001 \u8282\u70B9\u95E8\u7981\uFF1A\u914D\u7F6E\u4E86 toolChecks/aiChecks \u7684\u8282\u70B9\u63A8\u8FDB\u524D\u81EA\u52A8\u6267\u884C\u68C0\u67E5\u2014\u2014fail \u4F1A\u88AB\u6253\u56DE\u5E76\u8FD4\u56DE\u9010\u9879\u4FEE\u590D\u6307\u5F15\uFF08\u7ED3\u679C\u5DF2\u5199 history checks_rejected\uFF09\uFF0C\u6309\u6307\u5F15\u4FEE\u590D\u6216\u83B7\u7528\u6237\u8C41\u514D\u7559\u75D5\u540E\u91CD\u63A8\uFF1B\u975E\u4EBA\u5DE5\u5BA1\u6279\u8282\u70B9\u7981\u6B62\u56E0\u95E8\u7981\u4E2D\u65AD\u4EFB\u52A1\uFF08\u6253\u56DE\u4FE1\u606F\u5373\u7EE7\u7EED\u4F9D\u636E\uFF09\u3002force+forceReason \u6210\u5BF9\u63D0\u4F9B\u65F6\u53EF\u8D8A\u8FC7 fail \u5F3A\u5236\u63A8\u8FDB\u2014\u2014\u4EC5\u51ED\u7528\u6237\u660E\u793A\u6307\u4EE4\uFF0CAI \u7981\u6B62\u81EA\u51B3\uFF0C\u7406\u7531\u539F\u6587\u843D history \u5BA1\u8BA1)\uFF1Bcheck(taskId\uFF1B\u95E8\u7981\u53EA\u8BFB\u9884\u68C0\u2014\u2014\u9010\u9879\u62A5\u544A\u4E0D\u5199\u4EFB\u4F55\u72B6\u6001\uFF0Cadvance \u524D\u81EA\u67E5\u7528)\uFF1Bapprove(taskId,decision=approved|rejected\uFF1B\u53EF\u9009 comment\uFF1B\u54CD\u5E94\u5DF2\u542B\u4E0B\u4E00\u8282\u70B9\u8D44\u6599\u5305\uFF0C\u540C\u4F1A\u8BDD\u514D\u91CD\u8BFB context)\uFF1Bpause(taskId\uFF1B\u53EF\u9009 reason)\uFF1Bresume(taskId\uFF1B\u53EF\u9009 resumeNote)\uFF1Bcancel(taskId\uFF1B\u53EF\u9009 reason 1-500 \u5B57\u7B26\uFF1B\u26A0 \u7EC8\u6001\u4E0D\u53EF\u9006\u2014\u2014active/paused \u53EF\u53D6\u6D88\uFF0Ccompleted/cancelled \u62D2\u7EDD\u5E76\u8FD4\u56DE TASK_TERMINATED\uFF1B\u53D6\u6D88\u540E\u7ECF\u672C\u5DE5\u5177\u7684\u6D41\u8F6C\u4E0E\u8BB0\u5F55\u5199\u64CD\u4F5C\u88AB\u62D2)\uFF1Bhistory(taskId)\uFF1Binstance(taskId\u2014\u2014\u67E5\u770B\u4EFB\u52A1 DAG \u5B9E\u4F8B\u5FEB\u7167\uFF1A\u521B\u5EFA\u4EFB\u52A1\u65F6\u51BB\u7ED3\u7684\u6A21\u677F\u5B9E\u4F8B\uFF0C\u6A21\u677F\u540E\u7EED\u53D8\u66F4\u4E0D\u56DE\u6EAF)\u3002\u8BB0\u5F55\u5199\u5165\uFF1Arecord-set(taskId,node\uFF1Bsummary \u4E0E\u516D\u4E2A\u7ED3\u6784\u5316\u5B57\u6BB5\uFF08baseBranch/verifiedCommit/fixesApplied/testReport/deferredIssues/evidenceFiles\uFF09\u81F3\u5C11\u5176\u4E00\u2014\u2014\u7ED3\u6784\u5316\u5B57\u6BB5\u6309\u8282\u70B9 prompt\u300C\u7ED3\u6784\u5316\u5B57\u6BB5\u5199\u5165\u8981\u6C42\u300D\u9010\u5B57\u6BB5\u843D\u5E93\uFF0CPATCH \u8BED\u4E49=\u4EC5\u66F4\u65B0\u63D0\u4F9B\u5B57\u6BB5)\uFF1Brecord-check-add(taskId,node,item\uFF1B\u53EF\u9009 passed \u7F3A\u7701 true\u3001refId=aiChecks \u81EA\u68C0\u7559\u75D5\u951A\uFF08\u5BA1\u8BA1\u8BA4 refId===aiCheck.id \u4E14 passed=true\uFF0C\u7F3A\u7559\u75D5\u7684\u5B8C\u6210\u5224\u5B9A\u5BA1\u8BA1 fail\uFF09\u3001source=self|tool \u672C\u7248\u5DE5\u5177\u7F3A\u7701\u4E0D\u5199\uFF1B\u6279\u91CF checkItems \u5143\u7D20\u540C\u6784\uFF1B\u56DE\u6267 entry.id \u4F9B record-check-patch \u5B9A\u4F4D)\uFF1Brecord-check-patch(taskId,node,checkId\uFF1B\u53EF\u9009 passed/item/refId/source\uFF0C\u4EC5\u66F4\u65B0\u63D0\u4F9B\u5B57\u6BB5)\uFF1Brecord-artifact-add(taskId,node,artifactType=prd|tech|code|test|doc|other\uFF1Bpath \u7EAF\u5F15\u7528 / file \u8BFB\u672C\u673A\u6587\u4EF6 / content \u76F4\u4F20\u5168\u6587\u2014\u2014file \u4E0E content\u3001file \u4E0E path \u4E92\u65A5\uFF0Ccontent \u53EF\u4E0E path \u6210\u5BF9\u6216\u5355\u72EC\uFF0C\u5355\u72EC\u65F6\u767B\u8BB0\u503C\u5408\u6210 mcp-inline/<type>\uFF1B\u53EF\u9009 note)\uFF1Brecord-confirm(taskId,node,quote\u2014\u2014\u6682\u505C\u70B9\u7528\u6237\u786E\u8BA4\u539F\u6587\u9010\u5B57)\uFF1Brecord-decision-add(taskId,node,topic,decisionText)\uFF1Brecord-review-set(taskId,node,verdict=pass|fail,rounds,critical)\u3002\u9700\u6C42\u6587\u6863\uFF1Adoc-set(taskId\uFF1Bwhat/why/trackNote \u81F3\u5C11\u4F20\u4E00)\uFF1Bdoc-acceptance-add(taskId,text)\uFF1Bdoc-non-goal-add(taskId,text)\u3002\u7D20\u6750\uFF1Aarchnote-add(taskId,text)\u3002\u6279\u91CF\u5F62\u6001\uFF08\u63A8\u8350\uFF0C\u516D\u7C7B\u540C\u6784\uFF09\uFF1Arecord-check-add \u4F20 checkItems=[{item,passed?}]\u3001record-artifact-add \u4F20 artifactEntries=[{artifactType,path?/file?/content?,note?}]\u3001record-decision-add \u4F20 decisionEntries=[{topic,decisionText}]\u3001doc-acceptance-add/doc-non-goal-add/archnote-add \u4F20 textItems=[string]\u2014\u2014\u6279\u91CF\u53C2\u6570\u4E0E\u5355\u6761\u53C2\u6570\u4E8C\u9009\u4E00\uFF0C\u4E00\u6B21\u8C03\u7528\u5199\u591A\u6761\uFF08\u4E0A\u9650 50 \u6761/\u6279\uFF0Cartifact \u5168\u6587\u5FEB\u7167\u603B\u91CF \u22642M \u5B57\u7B26/\u6279\uFF09\uFF1B\u90E8\u5206\u5931\u8D25\u4FDD\u7559\u6210\u529F\u6761\u76EE\u5E76\u9010\u6761\u62A5\u544A\uFF08failures[].index=\u539F\u59CB\u63D0\u4EA4\u5E8F\uFF0C\u53EA\u91CD\u8BD5\u5931\u8D25\u9879\uFF09\uFF0Capplied=0 \u6574\u4F53\u62A5\u5931\u8D25\u3002',
|
|
2684
2782
|
taskArgs,
|
|
2685
2783
|
async (rawArgs) => {
|
|
2686
2784
|
const masked = applyFieldMask(rawArgs, TASK_FIELD_SPECS);
|
|
@@ -3163,7 +3261,16 @@ function createMcpServer() {
|
|
|
3163
3261
|
}
|
|
3164
3262
|
|
|
3165
3263
|
// src/commands/mcp-serve.ts
|
|
3264
|
+
var SOURCE_LABEL2 = {
|
|
3265
|
+
flag: "CLI \u53C2\u6570 --url",
|
|
3266
|
+
env: "\u73AF\u5883\u53D8\u91CF SIMING_SERVER_URL",
|
|
3267
|
+
workspace: "\u5DE5\u4F5C\u533A .siming/config.json",
|
|
3268
|
+
global: "\u5168\u5C40 ~/.siming/config.json",
|
|
3269
|
+
default: "\u9ED8\u8BA4\u63A8\u5BFC"
|
|
3270
|
+
};
|
|
3166
3271
|
async function mcpServeCommand() {
|
|
3272
|
+
const resolved = resolveServerUrlDetailed();
|
|
3273
|
+
console.error(`[siming] mcp-serve \u5DF2\u542F\u52A8\uFF1Aserver=${resolved.url}\uFF08\u6765\u6E90: ${SOURCE_LABEL2[resolved.source]}\uFF09\uFF1BserverUrl \u6BCF\u8BF7\u6C42\u73B0\u89E3\u6790\uFF0C\u914D\u7F6E\u53D8\u66F4\u65E0\u9700\u91CD\u542F`);
|
|
3167
3274
|
const server = createMcpServer();
|
|
3168
3275
|
const transport = new StdioServerTransport();
|
|
3169
3276
|
await server.connect(transport);
|
|
@@ -9296,13 +9403,13 @@ function createSettingsCommand() {
|
|
|
9296
9403
|
return settings;
|
|
9297
9404
|
}
|
|
9298
9405
|
function readStdin() {
|
|
9299
|
-
return new Promise((
|
|
9406
|
+
return new Promise((resolve4) => {
|
|
9300
9407
|
let data = "";
|
|
9301
9408
|
process.stdin.setEncoding("utf8");
|
|
9302
9409
|
process.stdin.on("data", (chunk) => {
|
|
9303
9410
|
data += chunk;
|
|
9304
9411
|
});
|
|
9305
|
-
process.stdin.on("end", () =>
|
|
9412
|
+
process.stdin.on("end", () => resolve4(data));
|
|
9306
9413
|
});
|
|
9307
9414
|
}
|
|
9308
9415
|
|
|
@@ -9314,7 +9421,7 @@ import { VERSION as VERSION4, SIMING_CONFIG_KEYS as SIMING_CONFIG_KEYS2 } from "
|
|
|
9314
9421
|
// src/commands/server/daemon.ts
|
|
9315
9422
|
import { execFileSync } from "child_process";
|
|
9316
9423
|
import { closeSync, existsSync as existsSync11, lstatSync, mkdirSync as mkdirSync6, openSync, readFileSync as readFileSync17, renameSync as renameSync5, rmSync as rmSync4, writeFileSync as writeFileSync6 } from "fs";
|
|
9317
|
-
import { join as join11, resolve as
|
|
9424
|
+
import { join as join11, resolve as resolve3 } from "path";
|
|
9318
9425
|
import { spawn } from "child_process";
|
|
9319
9426
|
|
|
9320
9427
|
// src/commands/server/probe.ts
|
|
@@ -9523,7 +9630,7 @@ function readLogTail(lines = 30) {
|
|
|
9523
9630
|
return all.slice(-lines);
|
|
9524
9631
|
}
|
|
9525
9632
|
function spawnDaemon(configEnv) {
|
|
9526
|
-
const entry =
|
|
9633
|
+
const entry = resolve3(process.argv[1] ?? "");
|
|
9527
9634
|
if (entry.length === 0 || !existsSync11(entry)) {
|
|
9528
9635
|
throw new Error(`\u65E0\u6CD5\u5B9A\u4F4D siming \u5165\u53E3\u811A\u672C\uFF08process.argv[1]=${process.argv[1] ?? "(\u7A7A)"}\uFF09`);
|
|
9529
9636
|
}
|
|
@@ -9848,12 +9955,12 @@ async function logsAction(opts) {
|
|
|
9848
9955
|
}
|
|
9849
9956
|
if (tail.length > 0) console.log(tail.join("\n"));
|
|
9850
9957
|
if (!opts.follow) return 0;
|
|
9851
|
-
await new Promise((
|
|
9958
|
+
await new Promise((resolve4) => {
|
|
9852
9959
|
const child = spawn2("tail", ["-n", "0", "-f", logfilePath()], { stdio: "inherit" });
|
|
9853
|
-
child.on("exit", () =>
|
|
9960
|
+
child.on("exit", () => resolve4());
|
|
9854
9961
|
child.on("error", (e) => {
|
|
9855
9962
|
err(`\u65E0\u6CD5\u542F\u52A8 tail: ${e.message}`);
|
|
9856
|
-
|
|
9963
|
+
resolve4();
|
|
9857
9964
|
});
|
|
9858
9965
|
});
|
|
9859
9966
|
return 0;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@siming-org/cli",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.7",
|
|
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/core": "0.8.
|
|
31
|
-
"@siming-org/server": "0.8.
|
|
30
|
+
"@siming-org/core": "0.8.7",
|
|
31
|
+
"@siming-org/server": "0.8.7"
|
|
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-10-
|
|
3
|
+
"exportedAt": "2026-10-14T08:44:31.828Z",
|
|
4
4
|
"warnings": [],
|
|
5
5
|
"template": {
|
|
6
6
|
"name": "full_workflow",
|
|
@@ -25,7 +25,9 @@
|
|
|
25
25
|
"agents": [
|
|
26
26
|
"prd-reviewer"
|
|
27
27
|
]
|
|
28
|
-
}
|
|
28
|
+
},
|
|
29
|
+
"toolChecks": [],
|
|
30
|
+
"aiChecks": []
|
|
29
31
|
},
|
|
30
32
|
{
|
|
31
33
|
"id": "ALIGN",
|
|
@@ -73,11 +75,13 @@
|
|
|
73
75
|
"sourcePreset": {
|
|
74
76
|
"code": "interaction-design",
|
|
75
77
|
"version": "1.2.0",
|
|
76
|
-
"contentHash": "
|
|
78
|
+
"contentHash": "fdefbe0ca7834e9b",
|
|
77
79
|
"agents": [
|
|
78
80
|
"alignment-reviewer"
|
|
79
81
|
]
|
|
80
|
-
}
|
|
82
|
+
},
|
|
83
|
+
"toolChecks": [],
|
|
84
|
+
"aiChecks": []
|
|
81
85
|
},
|
|
82
86
|
{
|
|
83
87
|
"id": "DESIGN",
|
|
@@ -95,8 +99,8 @@
|
|
|
95
99
|
],
|
|
96
100
|
"sourcePreset": {
|
|
97
101
|
"code": "design-tech",
|
|
98
|
-
"version": "1.8.
|
|
99
|
-
"contentHash": "
|
|
102
|
+
"version": "1.8.1",
|
|
103
|
+
"contentHash": "c1baf274770d39b2",
|
|
100
104
|
"agents": [
|
|
101
105
|
"alignment-reviewer",
|
|
102
106
|
"arch-reviewer"
|
|
@@ -140,8 +144,8 @@
|
|
|
140
144
|
],
|
|
141
145
|
"sourcePreset": {
|
|
142
146
|
"code": "code-backend",
|
|
143
|
-
"version": "1.5.
|
|
144
|
-
"contentHash": "
|
|
147
|
+
"version": "1.5.1",
|
|
148
|
+
"contentHash": "e0d1fe3a22acf0a0",
|
|
145
149
|
"agents": [
|
|
146
150
|
"code-reviewer"
|
|
147
151
|
]
|
|
@@ -242,7 +246,9 @@
|
|
|
242
246
|
"agents": [
|
|
243
247
|
"test-reviewer"
|
|
244
248
|
]
|
|
245
|
-
}
|
|
249
|
+
},
|
|
250
|
+
"toolChecks": [],
|
|
251
|
+
"aiChecks": []
|
|
246
252
|
},
|
|
247
253
|
{
|
|
248
254
|
"id": "UT_DEV",
|
|
@@ -304,7 +310,9 @@
|
|
|
304
310
|
"agents": [
|
|
305
311
|
"test-reviewer"
|
|
306
312
|
]
|
|
307
|
-
}
|
|
313
|
+
},
|
|
314
|
+
"toolChecks": [],
|
|
315
|
+
"aiChecks": []
|
|
308
316
|
},
|
|
309
317
|
{
|
|
310
318
|
"id": "UI_UT_DEV",
|
|
@@ -471,15 +479,15 @@
|
|
|
471
479
|
"label": "发布验收",
|
|
472
480
|
"phase": "exit",
|
|
473
481
|
"track": "all",
|
|
474
|
-
"prompt": "# 发布验收\n\n## 节点职责\n\n核对最终集成验证证据与当前版本是否一致,向用户呈现可独立理解的验收摘要,并按本节点在流程中的位置承载确认与代码归档:存在后继审批边时,用户确认由流转边暂停点承载,本节点不重复确认;本节点为任务终点时,节点内确认是任务收尾唯一授权门。本节点不重复执行测试、代码评审或回归分析。\n\n## 依赖信息\n\n先检查当前任务上下文,读取需求、验收标准、非目标、已激活节点的完成记录、`test-integrate` 的测试范围与结果、日志以及已验证版本标识,并读取项目分支与归档策略。加载 `workflow-discipline`。\n\n缺少集成验证证据、版本标识或前序完成记录时,先从任务上下文补齐;证据仍不完整或无法对应当前版本时停止验收,不推断通过。\n\n## 执行流程\n\n1. 确认所有已激活的前序节点均已完成,不写死某一模板路径下的节点清单。\n2. 比较当前生产代码与 `test-integrate` 绑定的已验证版本。存在新的生产代码变化时,退回集成验证重新判断范围并回归;纯文档或记录变化说明为何不影响证据。\n3. 逐条核对验收标准对应的实现位置和前序验证证据,并确认非目标未被误实现、范围变化已说明、所有 reviewer 的阻塞问题已解决。\n4. 汇总集成测试范围与统计、未授权跳过、实现与验收标准对应关系、范围变化、已知问题和风险,形成简洁且不依赖任务内部术语的验收摘要。\n5. 判定本节点位置:读取任务上下文中的任务结构(DAG 节点集与各节点状态)——本节点是任务最后一个节点(如快速流程形态,已完成数加一等于节点总数)即为终态形态;存在后继节点(如架构归档节点)即为非终态形态。advance 响应的 nextNode 资料包可作交叉印证。两种形态的确认与归档时序不同,按后续步骤分支执行,判定结果写入节点记录。\n6. **终态形态(本节点为任务终点,无后继审批边)**:向用户呈现验收摘要并在节点内取得明确决定。只有明确的通过、确认归档或等价肯定表达构成确认;提问、条件句、部分认同、沉默或模糊表态不构成确认。确认后逐字记录确认原文,并按项目声明完成提交、合并、推送或其他代码归档动作。无项目策略时采用保留历史且可回退的常规方式,并记录采用的默认。\n7. **非终态形态(存在后继审批边)**:向用户呈现验收摘要(作为暂停点审批材料);推进前在节点记录写入显式「归档待办」条目(归档动作清单:目标分支、合并方式、推送范围);然后推进进入暂停点等待用户审批——审批通过即验收确认,确认原文以审批记录留痕(须逐字引用用户确认表态,不得转述失真),本节点不重复确认。审批通过后、开始下一节点工作前,先完成归档待办中的代码归档动作(提交/合并/推送),完成后回写归档结果闭环该待办;归档待办在归档完成前不得闭环。\n8. 归档过程中遇到冲突或失败时先检查实际版本控制状态并自主诊断;无法可靠解决时说明当前状态和卡点,不猜测操作结果。\n\n## 产出与检查\n\n推进前确认:\n\n- 所有已激活前序节点已完成;\n- 集成验证证据完整,所有适用测试通过,失败为 0,未授权跳过为 0;\n- 当前生产代码与已验证版本一致;\n- 每条验收标准都有实现和验证证据,非目标、范围变化与已知问题已说明;\n- 没有未解决的 BLOCKER、HIGH 或其他流程定义的阻塞问题;\n- 终态形态:用户已明确确认,确认原文已逐字记录,代码已按项目策略归档;\n- 非终态形态:验收摘要已呈现,归档待办已写入且动作清单明确(归档动作待审批通过后执行,不在本节点提前归档);\n- 最终提交、分支和远程状态可追溯。\n\n## 任务差异处理\n\n任务没有代码或项目没有分支归档流程时,执行适用的验收确认并说明不适用项。用户要求附条件通过或接受具体风险时,终态形态在节点内记录条件、风险和确认原文;非终态形态该表态在暂停点审批中给出,审批记录即留痕。未被明确接受的阻塞问题不得归档。证据过期、验收标准缺失或代码归档失败时,按实际问题返回相应节点处理,不在本节点重新执行其职责。\n\n## 节点记录与推进\n\n
|
|
482
|
+
"prompt": "# 发布验收\n\n## 节点职责\n\n核对最终集成验证证据与当前版本是否一致,向用户呈现可独立理解的验收摘要,并按本节点在流程中的位置承载确认与代码归档:存在后继审批边时,用户确认由流转边暂停点承载,本节点不重复确认;本节点为任务终点时,节点内确认是任务收尾唯一授权门。本节点不重复执行测试、代码评审或回归分析。\n\n## 依赖信息\n\n先检查当前任务上下文,读取需求、验收标准、非目标、已激活节点的完成记录、`test-integrate` 的测试范围与结果、日志以及已验证版本标识,并读取项目分支与归档策略。加载 `workflow-discipline`。\n\n缺少集成验证证据、版本标识或前序完成记录时,先从任务上下文补齐;证据仍不完整或无法对应当前版本时停止验收,不推断通过。\n\n## 执行流程\n\n1. 确认所有已激活的前序节点均已完成,不写死某一模板路径下的节点清单。\n2. 比较当前生产代码与 `test-integrate` 绑定的已验证版本。存在新的生产代码变化时,退回集成验证重新判断范围并回归;纯文档或记录变化说明为何不影响证据。\n3. 逐条核对验收标准对应的实现位置和前序验证证据,并确认非目标未被误实现、范围变化已说明、所有 reviewer 的阻塞问题已解决。\n4. 汇总集成测试范围与统计、未授权跳过、实现与验收标准对应关系、范围变化、已知问题和风险,形成简洁且不依赖任务内部术语的验收摘要。\n5. 判定本节点位置:读取任务上下文中的任务结构(DAG 节点集与各节点状态)——本节点是任务最后一个节点(如快速流程形态,已完成数加一等于节点总数)即为终态形态;存在后继节点(如架构归档节点)即为非终态形态。advance 响应的 nextNode 资料包可作交叉印证。两种形态的确认与归档时序不同,按后续步骤分支执行,判定结果写入节点记录。\n6. **终态形态(本节点为任务终点,无后继审批边)**:向用户呈现验收摘要并在节点内取得明确决定。只有明确的通过、确认归档或等价肯定表达构成确认;提问、条件句、部分认同、沉默或模糊表态不构成确认。确认后逐字记录确认原文,并按项目声明完成提交、合并、推送或其他代码归档动作。无项目策略时采用保留历史且可回退的常规方式,并记录采用的默认。\n7. **非终态形态(存在后继审批边)**:向用户呈现验收摘要(作为暂停点审批材料);推进前在节点记录写入显式「归档待办」条目(归档动作清单:目标分支、合并方式、推送范围);然后推进进入暂停点等待用户审批——审批通过即验收确认,确认原文以审批记录留痕(须逐字引用用户确认表态,不得转述失真),本节点不重复确认。审批通过后、开始下一节点工作前,先完成归档待办中的代码归档动作(提交/合并/推送),完成后回写归档结果闭环该待办;归档待办在归档完成前不得闭环。\n8. 归档过程中遇到冲突或失败时先检查实际版本控制状态并自主诊断;无法可靠解决时说明当前状态和卡点,不猜测操作结果。\n\n## 产出与检查\n\n推进前确认:\n\n- 所有已激活前序节点已完成;\n- 集成验证证据完整,所有适用测试通过,失败为 0,未授权跳过为 0;\n- 当前生产代码与已验证版本一致;\n- 每条验收标准都有实现和验证证据,非目标、范围变化与已知问题已说明;\n- 没有未解决的 BLOCKER、HIGH 或其他流程定义的阻塞问题;\n- 终态形态:用户已明确确认,确认原文已逐字记录,代码已按项目策略归档;\n- 非终态形态:验收摘要已呈现,归档待办已写入且动作清单明确(归档动作待审批通过后执行,不在本节点提前归档);\n- 最终提交、分支和远程状态可追溯。\n\n## 任务差异处理\n\n任务没有代码或项目没有分支归档流程时,执行适用的验收确认并说明不适用项。用户要求附条件通过或接受具体风险时,终态形态在节点内记录条件、风险和确认原文;非终态形态该表态在暂停点审批中给出,审批记录即留痕。未被明确接受的阻塞问题不得归档。证据过期、验收标准缺失或代码归档失败时,按实际问题返回相应节点处理,不在本节点重新执行其职责。\n\n## 节点记录与推进\n\n推进前将验收摘要、证据时效、验收标准对照、范围变化、已知问题和位置判定结果写入当前节点记录;非终态形态同时写入归档待办,并在归档完成前保持其未闭环。终态形态在用户确认后追加确认原文与归档结果;非终态形态在暂停点审批通过并完成归档后,追加审批引用、归档策略与结果、最终提交和远程状态,闭环归档待办。完成推进前检查后推进下一节点——终态形态的推进必须带收尾确认参数(CLI `--finalize` / MCP `finalize=true`),终节点缺省 advance 会被拒绝并提示;非终态形态不带该参数(携带也会被忽略);批后追加动作发生在推进之后,不阻塞推进。",
|
|
475
483
|
"skills": [
|
|
476
484
|
"workflow-discipline"
|
|
477
485
|
],
|
|
478
486
|
"agents": [],
|
|
479
487
|
"sourcePreset": {
|
|
480
488
|
"code": "release-accept",
|
|
481
|
-
"version": "1.5.
|
|
482
|
-
"contentHash": "
|
|
489
|
+
"version": "1.5.1",
|
|
490
|
+
"contentHash": "abab1a2557e55c73",
|
|
483
491
|
"agents": []
|
|
484
492
|
},
|
|
485
493
|
"toolChecks": [
|
|
@@ -508,7 +516,7 @@
|
|
|
508
516
|
"label": "架构信息归档",
|
|
509
517
|
"phase": "exit",
|
|
510
518
|
"track": "all",
|
|
511
|
-
"prompt": "# 架构信息归档\n\n## 节点职责\n\n从任务决策中筛选对未来设计持续有帮助的项目重大信息,形成架构信息修改计划,经独立 `arch-info-reviewer` 评审和用户明确确认后写入项目架构文档。没有合格条目是正常结果,本节点完成后任务正式收敛。\n\n## 依赖信息\n\n先检查当前任务上下文,读取需求、关键决策、技术方案、各节点记录、架构候选素材和发布验收结果,并读取项目及架构文档目录的提示词、记录标准、索引和相关现有条目。加载 `workflow-discipline`,调用独立 `arch-info-reviewer` 评审修改计划。\n\n项目已有架构文档体系时遵循其分类、命名、索引和写入规则。没有体系时先判断是否确有合格条目,不为“无新增”创建空目录或空文档。\n\n开工自检:检查前序节点记录中存在未闭环的归档待办(如发布验收节点审批通过后尚未完成的代码归档)时,先完成该归档并回写闭环,再开始本节点工作。\n\n## 执行流程\n\n1. 汇总任务中的候选决策,逐条判断它是否会约束未来多个设计或实现,是否属于项目特有的重要业务规则、模块边界、技术选型、兼容策略或跨任务约束。\n2. 排除常规功能演进、局部实现、缺陷修复过程、工作流水和通用工程常识;说明不收录理由及更合适的载体,没有其他载体时保留在任务记录。\n3. 检索架构索引和相关正文,判断候选是新增主题、现有主题演进、替代或退役,避免创建重复或冲突条目。\n4. 形成修改计划:建议项写明主题、决策、未来约束、适用范围、目标文档及新增或演进方式;不收录项写明门槛结论。允许建议项为零。\n5. 将项目记录标准、现有相关文档、客观决策素材和修改计划交给 `arch-info-reviewer`,不提供撰写者结论或预期结果。修复 BLOCKER、HIGH Findings 后重新评审,直至获得 PASS;MEDIUM、LOW 逐项处理或记录保留理由。\n6. 向用户同时呈现修改计划和独立评审结论。只有明确批准、调整后批准、放弃或确认无新增构成决定;逐字记录用户原文。\n7. 仅写入用户批准的条目:按项目组织更新正文和索引,同主题优先演进;无批准条目时不创建或修改架构文档。\n8. 核对批准条目与实际写入、正文与索引、演进与替代关系。有文档变化时按项目策略提交并推送;无变化时记录跳过。\n\n## 产出与检查\n\n推进前确认:\n\n- 任务决策和候选素材已完整读取;\n- 所有候选均经过记录门槛判断,修改计划包含建议项和不收录理由;\n- 相关现有条目已检索,新增、演进、替代和退役关系明确;\n- `arch-info-reviewer` 最终结论为 PASS,所有 Findings 均已处理或说明;\n- 修改计划和评审结论已呈现用户,确认原文已逐字记录;\n- 仅有用户批准的条目被写入,正文与索引一致;\n- 无新增时未创建空文档,有变化时提交与远程状态可追溯;\n- 当前节点记录完整,任务可以正式收敛。\n\n## 任务差异处理\n\n项目没有架构体系但有获批的重大决策时,优先使用项目声明的文档根建立最小结构;无文档根声明时使用 `docs/architecture/`,只创建承载获批内容所需的文件。用户未批准修改计划时保持暂停,不提前写入。候选全部不达门槛时,呈现“无新增”及主要理由,经用户确认后正常完成。\n\n## 节点记录与推进\n\n
|
|
519
|
+
"prompt": "# 架构信息归档\n\n## 节点职责\n\n从任务决策中筛选对未来设计持续有帮助的项目重大信息,形成架构信息修改计划,经独立 `arch-info-reviewer` 评审和用户明确确认后写入项目架构文档。没有合格条目是正常结果,本节点完成后任务正式收敛。\n\n## 依赖信息\n\n先检查当前任务上下文,读取需求、关键决策、技术方案、各节点记录、架构候选素材和发布验收结果,并读取项目及架构文档目录的提示词、记录标准、索引和相关现有条目。加载 `workflow-discipline`,调用独立 `arch-info-reviewer` 评审修改计划。\n\n项目已有架构文档体系时遵循其分类、命名、索引和写入规则。没有体系时先判断是否确有合格条目,不为“无新增”创建空目录或空文档。\n\n开工自检:检查前序节点记录中存在未闭环的归档待办(如发布验收节点审批通过后尚未完成的代码归档)时,先完成该归档并回写闭环,再开始本节点工作。\n\n## 执行流程\n\n1. 汇总任务中的候选决策,逐条判断它是否会约束未来多个设计或实现,是否属于项目特有的重要业务规则、模块边界、技术选型、兼容策略或跨任务约束。\n2. 排除常规功能演进、局部实现、缺陷修复过程、工作流水和通用工程常识;说明不收录理由及更合适的载体,没有其他载体时保留在任务记录。\n3. 检索架构索引和相关正文,判断候选是新增主题、现有主题演进、替代或退役,避免创建重复或冲突条目。\n4. 形成修改计划:建议项写明主题、决策、未来约束、适用范围、目标文档及新增或演进方式;不收录项写明门槛结论。允许建议项为零。\n5. 将项目记录标准、现有相关文档、客观决策素材和修改计划交给 `arch-info-reviewer`,不提供撰写者结论或预期结果。修复 BLOCKER、HIGH Findings 后重新评审,直至获得 PASS;MEDIUM、LOW 逐项处理或记录保留理由。\n6. 向用户同时呈现修改计划和独立评审结论。只有明确批准、调整后批准、放弃或确认无新增构成决定;逐字记录用户原文。\n7. 仅写入用户批准的条目:按项目组织更新正文和索引,同主题优先演进;无批准条目时不创建或修改架构文档。\n8. 核对批准条目与实际写入、正文与索引、演进与替代关系。有文档变化时按项目策略提交并推送;无变化时记录跳过。\n\n## 产出与检查\n\n推进前确认:\n\n- 任务决策和候选素材已完整读取;\n- 所有候选均经过记录门槛判断,修改计划包含建议项和不收录理由;\n- 相关现有条目已检索,新增、演进、替代和退役关系明确;\n- `arch-info-reviewer` 最终结论为 PASS,所有 Findings 均已处理或说明;\n- 修改计划和评审结论已呈现用户,确认原文已逐字记录;\n- 仅有用户批准的条目被写入,正文与索引一致;\n- 无新增时未创建空文档,有变化时提交与远程状态可追溯;\n- 当前节点记录完整,任务可以正式收敛。\n\n## 任务差异处理\n\n项目没有架构体系但有获批的重大决策时,优先使用项目声明的文档根建立最小结构;无文档根声明时使用 `docs/architecture/`,只创建承载获批内容所需的文件。用户未批准修改计划时保持暂停,不提前写入。候选全部不达门槛时,呈现“无新增”及主要理由,经用户确认后正常完成。\n\n## 节点记录与推进\n\n将架构归档结论、候选过滤、修改计划、独立评审结论、用户确认原文、写入或不收录决定、架构文档与索引引用、提交和远程状态写入当前节点记录。完成上述检查后推进终态,使任务完成——终节点推进必须带收尾确认参数(CLI `--finalize` / MCP `finalize=true`),缺省 advance 会被拒绝并提示;在任务完成前不开始其他任务。",
|
|
512
520
|
"skills": [
|
|
513
521
|
"workflow-discipline"
|
|
514
522
|
],
|
|
@@ -517,8 +525,8 @@
|
|
|
517
525
|
],
|
|
518
526
|
"sourcePreset": {
|
|
519
527
|
"code": "archive-architecture",
|
|
520
|
-
"version": "1.5.
|
|
521
|
-
"contentHash": "
|
|
528
|
+
"version": "1.5.1",
|
|
529
|
+
"contentHash": "b9e065c450df6f67",
|
|
522
530
|
"agents": [
|
|
523
531
|
"arch-info-reviewer"
|
|
524
532
|
]
|
|
@@ -660,25 +668,25 @@
|
|
|
660
668
|
"x": 110,
|
|
661
669
|
"y": 184
|
|
662
670
|
},
|
|
663
|
-
"
|
|
664
|
-
"x":
|
|
671
|
+
"INTERACTION": {
|
|
672
|
+
"x": 180,
|
|
665
673
|
"y": 328
|
|
666
674
|
},
|
|
667
|
-
"
|
|
675
|
+
"DESIGN": {
|
|
668
676
|
"x": 110,
|
|
669
677
|
"y": 472
|
|
670
678
|
},
|
|
671
679
|
"CODE_BACKEND": {
|
|
672
|
-
"x":
|
|
673
|
-
"y":
|
|
680
|
+
"x": 180,
|
|
681
|
+
"y": 616
|
|
674
682
|
},
|
|
675
683
|
"CODE_UI": {
|
|
676
|
-
"x":
|
|
677
|
-
"y":
|
|
684
|
+
"x": 40,
|
|
685
|
+
"y": 1048
|
|
678
686
|
},
|
|
679
687
|
"UI_VISUAL": {
|
|
680
|
-
"x":
|
|
681
|
-
"y":
|
|
688
|
+
"x": 40,
|
|
689
|
+
"y": 1480
|
|
682
690
|
},
|
|
683
691
|
"UT_DESIGN": {
|
|
684
692
|
"x": 180,
|
|
@@ -689,36 +697,36 @@
|
|
|
689
697
|
"y": 904
|
|
690
698
|
},
|
|
691
699
|
"UI_UT_DESIGN": {
|
|
692
|
-
"x":
|
|
693
|
-
"y":
|
|
700
|
+
"x": 40,
|
|
701
|
+
"y": 1192
|
|
694
702
|
},
|
|
695
703
|
"UI_UT_DEV": {
|
|
696
|
-
"x":
|
|
697
|
-
"y":
|
|
704
|
+
"x": 40,
|
|
705
|
+
"y": 1336
|
|
698
706
|
},
|
|
699
707
|
"E2E_DESIGN": {
|
|
700
708
|
"x": 110,
|
|
701
|
-
"y":
|
|
709
|
+
"y": 1624
|
|
702
710
|
},
|
|
703
711
|
"E2E_DEV": {
|
|
704
712
|
"x": 110,
|
|
705
|
-
"y":
|
|
713
|
+
"y": 1768
|
|
706
714
|
},
|
|
707
715
|
"INTEGRATE": {
|
|
708
716
|
"x": 110,
|
|
709
|
-
"y":
|
|
717
|
+
"y": 1912
|
|
710
718
|
},
|
|
711
719
|
"ACCEPT": {
|
|
712
|
-
"x":
|
|
713
|
-
"y":
|
|
720
|
+
"x": 110,
|
|
721
|
+
"y": 2056
|
|
714
722
|
},
|
|
715
723
|
"ARCHIVE": {
|
|
716
724
|
"x": 110,
|
|
717
|
-
"y":
|
|
725
|
+
"y": 2200
|
|
718
726
|
}
|
|
719
727
|
},
|
|
720
728
|
"isDefault": false,
|
|
721
|
-
"version": "3.7.
|
|
729
|
+
"version": "3.7.3"
|
|
722
730
|
},
|
|
723
731
|
"dependencies": {
|
|
724
732
|
"skills": [
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"exportFormatVersion": "1.0",
|
|
3
|
-
"exportedAt": "2026-10-
|
|
3
|
+
"exportedAt": "2026-10-14T08:44:31.836Z",
|
|
4
4
|
"warnings": [],
|
|
5
5
|
"template": {
|
|
6
6
|
"name": "quick_workflow",
|
|
@@ -159,15 +159,15 @@
|
|
|
159
159
|
"label": "发布验收",
|
|
160
160
|
"phase": "exit",
|
|
161
161
|
"track": "all",
|
|
162
|
-
"prompt": "# 发布验收\n\n## 节点职责\n\n核对最终集成验证证据与当前版本是否一致,向用户呈现可独立理解的验收摘要,并按本节点在流程中的位置承载确认与代码归档:存在后继审批边时,用户确认由流转边暂停点承载,本节点不重复确认;本节点为任务终点时,节点内确认是任务收尾唯一授权门。本节点不重复执行测试、代码评审或回归分析。\n\n## 依赖信息\n\n先检查当前任务上下文,读取需求、验收标准、非目标、已激活节点的完成记录、`test-integrate` 的测试范围与结果、日志以及已验证版本标识,并读取项目分支与归档策略。加载 `workflow-discipline`。\n\n缺少集成验证证据、版本标识或前序完成记录时,先从任务上下文补齐;证据仍不完整或无法对应当前版本时停止验收,不推断通过。\n\n## 执行流程\n\n1. 确认所有已激活的前序节点均已完成,不写死某一模板路径下的节点清单。\n2. 比较当前生产代码与 `test-integrate` 绑定的已验证版本。存在新的生产代码变化时,退回集成验证重新判断范围并回归;纯文档或记录变化说明为何不影响证据。\n3. 逐条核对验收标准对应的实现位置和前序验证证据,并确认非目标未被误实现、范围变化已说明、所有 reviewer 的阻塞问题已解决。\n4. 汇总集成测试范围与统计、未授权跳过、实现与验收标准对应关系、范围变化、已知问题和风险,形成简洁且不依赖任务内部术语的验收摘要。\n5. 判定本节点位置:读取任务上下文中的任务结构(DAG 节点集与各节点状态)——本节点是任务最后一个节点(如快速流程形态,已完成数加一等于节点总数)即为终态形态;存在后继节点(如架构归档节点)即为非终态形态。advance 响应的 nextNode 资料包可作交叉印证。两种形态的确认与归档时序不同,按后续步骤分支执行,判定结果写入节点记录。\n6. **终态形态(本节点为任务终点,无后继审批边)**:向用户呈现验收摘要并在节点内取得明确决定。只有明确的通过、确认归档或等价肯定表达构成确认;提问、条件句、部分认同、沉默或模糊表态不构成确认。确认后逐字记录确认原文,并按项目声明完成提交、合并、推送或其他代码归档动作。无项目策略时采用保留历史且可回退的常规方式,并记录采用的默认。\n7. **非终态形态(存在后继审批边)**:向用户呈现验收摘要(作为暂停点审批材料);推进前在节点记录写入显式「归档待办」条目(归档动作清单:目标分支、合并方式、推送范围);然后推进进入暂停点等待用户审批——审批通过即验收确认,确认原文以审批记录留痕(须逐字引用用户确认表态,不得转述失真),本节点不重复确认。审批通过后、开始下一节点工作前,先完成归档待办中的代码归档动作(提交/合并/推送),完成后回写归档结果闭环该待办;归档待办在归档完成前不得闭环。\n8. 归档过程中遇到冲突或失败时先检查实际版本控制状态并自主诊断;无法可靠解决时说明当前状态和卡点,不猜测操作结果。\n\n## 产出与检查\n\n推进前确认:\n\n- 所有已激活前序节点已完成;\n- 集成验证证据完整,所有适用测试通过,失败为 0,未授权跳过为 0;\n- 当前生产代码与已验证版本一致;\n- 每条验收标准都有实现和验证证据,非目标、范围变化与已知问题已说明;\n- 没有未解决的 BLOCKER、HIGH 或其他流程定义的阻塞问题;\n- 终态形态:用户已明确确认,确认原文已逐字记录,代码已按项目策略归档;\n- 非终态形态:验收摘要已呈现,归档待办已写入且动作清单明确(归档动作待审批通过后执行,不在本节点提前归档);\n- 最终提交、分支和远程状态可追溯。\n\n## 任务差异处理\n\n任务没有代码或项目没有分支归档流程时,执行适用的验收确认并说明不适用项。用户要求附条件通过或接受具体风险时,终态形态在节点内记录条件、风险和确认原文;非终态形态该表态在暂停点审批中给出,审批记录即留痕。未被明确接受的阻塞问题不得归档。证据过期、验收标准缺失或代码归档失败时,按实际问题返回相应节点处理,不在本节点重新执行其职责。\n\n## 节点记录与推进\n\n
|
|
162
|
+
"prompt": "# 发布验收\n\n## 节点职责\n\n核对最终集成验证证据与当前版本是否一致,向用户呈现可独立理解的验收摘要,并按本节点在流程中的位置承载确认与代码归档:存在后继审批边时,用户确认由流转边暂停点承载,本节点不重复确认;本节点为任务终点时,节点内确认是任务收尾唯一授权门。本节点不重复执行测试、代码评审或回归分析。\n\n## 依赖信息\n\n先检查当前任务上下文,读取需求、验收标准、非目标、已激活节点的完成记录、`test-integrate` 的测试范围与结果、日志以及已验证版本标识,并读取项目分支与归档策略。加载 `workflow-discipline`。\n\n缺少集成验证证据、版本标识或前序完成记录时,先从任务上下文补齐;证据仍不完整或无法对应当前版本时停止验收,不推断通过。\n\n## 执行流程\n\n1. 确认所有已激活的前序节点均已完成,不写死某一模板路径下的节点清单。\n2. 比较当前生产代码与 `test-integrate` 绑定的已验证版本。存在新的生产代码变化时,退回集成验证重新判断范围并回归;纯文档或记录变化说明为何不影响证据。\n3. 逐条核对验收标准对应的实现位置和前序验证证据,并确认非目标未被误实现、范围变化已说明、所有 reviewer 的阻塞问题已解决。\n4. 汇总集成测试范围与统计、未授权跳过、实现与验收标准对应关系、范围变化、已知问题和风险,形成简洁且不依赖任务内部术语的验收摘要。\n5. 判定本节点位置:读取任务上下文中的任务结构(DAG 节点集与各节点状态)——本节点是任务最后一个节点(如快速流程形态,已完成数加一等于节点总数)即为终态形态;存在后继节点(如架构归档节点)即为非终态形态。advance 响应的 nextNode 资料包可作交叉印证。两种形态的确认与归档时序不同,按后续步骤分支执行,判定结果写入节点记录。\n6. **终态形态(本节点为任务终点,无后继审批边)**:向用户呈现验收摘要并在节点内取得明确决定。只有明确的通过、确认归档或等价肯定表达构成确认;提问、条件句、部分认同、沉默或模糊表态不构成确认。确认后逐字记录确认原文,并按项目声明完成提交、合并、推送或其他代码归档动作。无项目策略时采用保留历史且可回退的常规方式,并记录采用的默认。\n7. **非终态形态(存在后继审批边)**:向用户呈现验收摘要(作为暂停点审批材料);推进前在节点记录写入显式「归档待办」条目(归档动作清单:目标分支、合并方式、推送范围);然后推进进入暂停点等待用户审批——审批通过即验收确认,确认原文以审批记录留痕(须逐字引用用户确认表态,不得转述失真),本节点不重复确认。审批通过后、开始下一节点工作前,先完成归档待办中的代码归档动作(提交/合并/推送),完成后回写归档结果闭环该待办;归档待办在归档完成前不得闭环。\n8. 归档过程中遇到冲突或失败时先检查实际版本控制状态并自主诊断;无法可靠解决时说明当前状态和卡点,不猜测操作结果。\n\n## 产出与检查\n\n推进前确认:\n\n- 所有已激活前序节点已完成;\n- 集成验证证据完整,所有适用测试通过,失败为 0,未授权跳过为 0;\n- 当前生产代码与已验证版本一致;\n- 每条验收标准都有实现和验证证据,非目标、范围变化与已知问题已说明;\n- 没有未解决的 BLOCKER、HIGH 或其他流程定义的阻塞问题;\n- 终态形态:用户已明确确认,确认原文已逐字记录,代码已按项目策略归档;\n- 非终态形态:验收摘要已呈现,归档待办已写入且动作清单明确(归档动作待审批通过后执行,不在本节点提前归档);\n- 最终提交、分支和远程状态可追溯。\n\n## 任务差异处理\n\n任务没有代码或项目没有分支归档流程时,执行适用的验收确认并说明不适用项。用户要求附条件通过或接受具体风险时,终态形态在节点内记录条件、风险和确认原文;非终态形态该表态在暂停点审批中给出,审批记录即留痕。未被明确接受的阻塞问题不得归档。证据过期、验收标准缺失或代码归档失败时,按实际问题返回相应节点处理,不在本节点重新执行其职责。\n\n## 节点记录与推进\n\n推进前将验收摘要、证据时效、验收标准对照、范围变化、已知问题和位置判定结果写入当前节点记录;非终态形态同时写入归档待办,并在归档完成前保持其未闭环。终态形态在用户确认后追加确认原文与归档结果;非终态形态在暂停点审批通过并完成归档后,追加审批引用、归档策略与结果、最终提交和远程状态,闭环归档待办。完成推进前检查后推进下一节点——终态形态的推进必须带收尾确认参数(CLI `--finalize` / MCP `finalize=true`),终节点缺省 advance 会被拒绝并提示;非终态形态不带该参数(携带也会被忽略);批后追加动作发生在推进之后,不阻塞推进。",
|
|
163
163
|
"skills": [
|
|
164
164
|
"workflow-discipline"
|
|
165
165
|
],
|
|
166
166
|
"agents": [],
|
|
167
167
|
"sourcePreset": {
|
|
168
168
|
"code": "release-accept",
|
|
169
|
-
"version": "1.5.
|
|
170
|
-
"contentHash": "
|
|
169
|
+
"version": "1.5.1",
|
|
170
|
+
"contentHash": "abab1a2557e55c73",
|
|
171
171
|
"agents": []
|
|
172
172
|
},
|
|
173
173
|
"toolChecks": [
|
|
@@ -233,7 +233,7 @@
|
|
|
233
233
|
}
|
|
234
234
|
],
|
|
235
235
|
"isDefault": false,
|
|
236
|
-
"version": "2.0.
|
|
236
|
+
"version": "2.0.7"
|
|
237
237
|
},
|
|
238
238
|
"dependencies": {
|
|
239
239
|
"skills": [
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"exportFormatVersion": "1.0",
|
|
3
|
-
"exportedAt": "2026-10-
|
|
3
|
+
"exportedAt": "2026-10-14T08:44:31.834Z",
|
|
4
4
|
"warnings": [],
|
|
5
5
|
"template": {
|
|
6
6
|
"name": "research_workflow",
|
|
@@ -45,15 +45,15 @@
|
|
|
45
45
|
"label": "调研验收",
|
|
46
46
|
"phase": "exit",
|
|
47
47
|
"track": "all",
|
|
48
|
-
"prompt": "# 调研验收\n\n## 节点职责\n\n对照已确认的调研范围核对报告完整性和证据状态,向用户呈现可独立判断的验收摘要;用户明确确认后,按项目策略归档报告并完成任务。\n\n## 依赖信息\n\n先检查当前任务上下文,读取已确认的调研问题、范围、证据标准、停止条件、调研报告、来源与实验记录、限制和开放问题,以及项目的归档约定。加载 `workflow-discipline`。\n\n本节点不重新执行调研,不虚构独立 reviewer,也不做代码测试或代码评审。报告存在缺失、越界或证据不匹配时,返回 `research-execute` 补充或修订。\n\n## 执行流程\n\n1. 建立“调研问题 → 结论或无法结论 → 证据 → 报告位置”的对应关系,确认已确认范围中的问题没有遗漏。\n2. 核对结论是否能追溯到报告所列代码、原始资料或实验,事实、推断、建议、限制和开放问题是否清楚区分。\n3. 检查问题校正和新增发现是否改变了已确认范围;属于范围外的重要事项只列为后续议题,不在本任务中静默扩展。\n4. 发现问题遗漏、证据无法支持结论、限制被隐瞒或报告不可复核时,记录具体缺口并返回调研执行修订;修订后重新核对受影响内容。\n5. 形成验收摘要,逐项呈现问题与结论、关键证据、无法结论、可信度与适用限制、开放问题和建议边界,并说明报告归档位置。\n6. 请求用户对本次调研结果作明确确认。提问、条件句、模糊表态或沉默不视为确认;用户未确认时保持当前节点。\n7. 用户确认后记录确认原文,按项目约定归档调研报告和相关记录,完成任务。\n\n## 产出与检查\n\n完成前确认:\n\n- 已确认范围中的每个问题都有结论或明确的无法结论及原因;\n- 结论可追溯到对应证据,报告位置明确;\n- 事实、推断、建议、限制和开放问题已清楚区分;\n- 问题校正与新增发现没有静默改变任务范围;\n- 验收摘要足以让用户判断调研结果及其边界;\n- 用户已明确确认,确认原文已记录;\n- 调研报告已按项目策略归档,归档结果可追溯。\n\n## 任务差异处理\n\n调研报告可以包含无法结论,前提是原因、已尝试方法和缺失证据如实说明。项目没有特殊归档流程时,采用现有文档和版本控制惯例保存报告,不擅自建立新流程。报告之外出现生产代码变更时,说明任务越界并暂停,不在调研验收中处理。用户要求改变调研目标或补充新的范围时,记录为范围变更并回到适当节点处理。\n\n## 节点记录与推进\n\n
|
|
48
|
+
"prompt": "# 调研验收\n\n## 节点职责\n\n对照已确认的调研范围核对报告完整性和证据状态,向用户呈现可独立判断的验收摘要;用户明确确认后,按项目策略归档报告并完成任务。\n\n## 依赖信息\n\n先检查当前任务上下文,读取已确认的调研问题、范围、证据标准、停止条件、调研报告、来源与实验记录、限制和开放问题,以及项目的归档约定。加载 `workflow-discipline`。\n\n本节点不重新执行调研,不虚构独立 reviewer,也不做代码测试或代码评审。报告存在缺失、越界或证据不匹配时,返回 `research-execute` 补充或修订。\n\n## 执行流程\n\n1. 建立“调研问题 → 结论或无法结论 → 证据 → 报告位置”的对应关系,确认已确认范围中的问题没有遗漏。\n2. 核对结论是否能追溯到报告所列代码、原始资料或实验,事实、推断、建议、限制和开放问题是否清楚区分。\n3. 检查问题校正和新增发现是否改变了已确认范围;属于范围外的重要事项只列为后续议题,不在本任务中静默扩展。\n4. 发现问题遗漏、证据无法支持结论、限制被隐瞒或报告不可复核时,记录具体缺口并返回调研执行修订;修订后重新核对受影响内容。\n5. 形成验收摘要,逐项呈现问题与结论、关键证据、无法结论、可信度与适用限制、开放问题和建议边界,并说明报告归档位置。\n6. 请求用户对本次调研结果作明确确认。提问、条件句、模糊表态或沉默不视为确认;用户未确认时保持当前节点。\n7. 用户确认后记录确认原文,按项目约定归档调研报告和相关记录,完成任务。\n\n## 产出与检查\n\n完成前确认:\n\n- 已确认范围中的每个问题都有结论或明确的无法结论及原因;\n- 结论可追溯到对应证据,报告位置明确;\n- 事实、推断、建议、限制和开放问题已清楚区分;\n- 问题校正与新增发现没有静默改变任务范围;\n- 验收摘要足以让用户判断调研结果及其边界;\n- 用户已明确确认,确认原文已记录;\n- 调研报告已按项目策略归档,归档结果可追溯。\n\n## 任务差异处理\n\n调研报告可以包含无法结论,前提是原因、已尝试方法和缺失证据如实说明。项目没有特殊归档流程时,采用现有文档和版本控制惯例保存报告,不擅自建立新流程。报告之外出现生产代码变更时,说明任务越界并暂停,不在调研验收中处理。用户要求改变调研目标或补充新的范围时,记录为范围变更并回到适当节点处理。\n\n## 节点记录与推进\n\n将问题覆盖关系、证据核对结果、退回修订及结果、无法结论、限制和开放问题、验收摘要、用户确认原文、报告与归档引用写入当前节点记录。所有检查完成后结束任务——终节点推进必须带收尾确认参数(CLI `--finalize` / MCP `finalize=true`),缺省 advance 会被拒绝并提示;任何检查未满足时保留在当前节点或返回相应节点处理。",
|
|
49
49
|
"skills": [
|
|
50
50
|
"workflow-discipline"
|
|
51
51
|
],
|
|
52
52
|
"agents": [],
|
|
53
53
|
"sourcePreset": {
|
|
54
54
|
"code": "research-accept",
|
|
55
|
-
"version": "1.3.
|
|
56
|
-
"contentHash": "
|
|
55
|
+
"version": "1.3.1",
|
|
56
|
+
"contentHash": "19e18ecbc644e994",
|
|
57
57
|
"agents": []
|
|
58
58
|
}
|
|
59
59
|
}
|
|
@@ -88,7 +88,7 @@
|
|
|
88
88
|
}
|
|
89
89
|
},
|
|
90
90
|
"isDefault": false,
|
|
91
|
-
"version": "1.0.
|
|
91
|
+
"version": "1.0.4"
|
|
92
92
|
},
|
|
93
93
|
"dependencies": {
|
|
94
94
|
"skills": [
|