@siming-org/cli 0.8.2 → 0.8.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +390 -207
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -666,12 +666,12 @@ async function healthcheckCommand(opts) {
666
666
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
667
667
 
668
668
  // src/mcp/server.ts
669
- import { readFileSync as readFileSync8 } from "fs";
669
+ import { readFileSync as readFileSync9 } from "fs";
670
670
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
671
671
  import { VERSION } from "@siming-org/core";
672
672
 
673
673
  // src/client/handlers/task.ts
674
- import { readFileSync as readFileSync5 } from "fs";
674
+ import { readFileSync as readFileSync6 } from "fs";
675
675
  import {
676
676
  ARTIFACT_TYPES
677
677
  } from "@siming-org/core";
@@ -682,6 +682,44 @@ var MIN_AI_CHECK_ITEM_LENGTH = 15;
682
682
  var VAGUE_AI_CHECK_BLACKLIST = ["\u5DF2\u5B8C\u6210", "\u901A\u8FC7", "\u5B8C\u6210", "done", "ok", "pass"];
683
683
 
684
684
  // src/client/checks/git-checks.ts
685
+ async function perRepoCheck(ctx, type, judge) {
686
+ const results = [];
687
+ for (const repo of ctx.repos) {
688
+ results.push({ repo, r: await judge(repo) });
689
+ }
690
+ const failed = results.filter((x) => x.r.status === "fail");
691
+ if (failed.length > 0) {
692
+ const failLines = failed.slice(0, 4).map((x) => `${x.repo}: ${x.r.detail}`);
693
+ const rest = results.filter((x) => x.r.status !== "fail").map((x) => `${x.repo}: ${x.r.status === "pass" ? "pass" : "N/A"}`);
694
+ const suffix = failed.length > 4 ? `\uFF08\u53E6\u6709 ${failed.length - 4} \u4ED3 fail \u89C1\u626B\u63CF\u8DEF\u5F84\u9010\u4ED3\u91CD\u67E5\uFF09` : "";
695
+ const okPart = rest.length > 0 ? `\uFF1B\u5176\u4F59\u4ED3\uFF1A${rest.join("\u3001")}` : "";
696
+ return {
697
+ type,
698
+ status: "fail",
699
+ // 尾附扫描详情:fail 时用户需核对 R 完整性(子目录启动漏仓诊断——scanned from 可观测启动位置)
700
+ detail: `${failed.length}/${results.length} \u4ED3\u672A\u8FC7\u2014\u2014${failLines.join("\uFF1B")}${suffix}${okPart}\u3002\u4FEE\u590D\uFF1A\u9010\u4ED3\u5904\u7406\u540E\u91CD\u8BD5\uFF08\u591A\u4ED3\u987B\u5168\u90E8\u9002\u914D\u76F8\u540C\u5206\u652F\u7BA1\u7406\uFF09
701
+ ${ctx.reposScanDetail}`
702
+ };
703
+ }
704
+ const allNa = results.every((x) => x.r.status === "not_applicable");
705
+ if (allNa) {
706
+ return {
707
+ type,
708
+ status: "not_applicable",
709
+ detail: `\u5168\u90E8 ${results.length} \u4ED3\u514D\u68C0\uFF1A${results.map((x) => `${x.repo}\uFF08${x.r.detail}\uFF09`).join("\uFF1B")}
710
+ ${ctx.reposScanDetail}`
711
+ };
712
+ }
713
+ const passLines = results.filter((x) => x.r.status === "pass").map((x) => `${x.repo}: ${x.r.detail}`);
714
+ const naPart = results.filter((x) => x.r.status === "not_applicable").map((x) => `${x.repo}\uFF08${x.r.detail}\uFF09`);
715
+ return {
716
+ type,
717
+ status: "pass",
718
+ // 尾附扫描详情:pass 同样需可观测 R 完整性(子目录启动扫到部分仓的静默假 pass 诊断)
719
+ detail: `\u5168\u90E8 ${results.length} \u4ED3\u901A\u8FC7\u2014\u2014${passLines.join("\uFF1B")}${naPart.length > 0 ? `\uFF1B\u514D\u68C0\u4ED3\uFF1A${naPart.join("\uFF1B")}` : ""}
720
+ ${ctx.reposScanDetail}`
721
+ };
722
+ }
685
723
  function naIfRepoUnavailable(ctx) {
686
724
  if (ctx.vcsLoadError !== void 0) {
687
725
  return { type: "", status: "fail", detail: `\u9879\u76EE vcs \u914D\u7F6E\u8BFB\u53D6\u5931\u8D25\uFF1A${ctx.vcsLoadError}\u2014\u2014\u65E0\u6CD5\u786E\u8BA4\u95E8\u7981\u542F\u7528\u72B6\u6001\uFF08\u62D2\u9759\u9ED8\u964D\u7EA7\uFF09\u3002\u4FEE\u590D\uFF1A\u786E\u8BA4 server \u53EF\u8FBE\u4E0E\u9879\u76EE\u914D\u7F6E\u540E\u91CD\u8DD1 task check` };
@@ -689,8 +727,8 @@ function naIfRepoUnavailable(ctx) {
689
727
  if (ctx.vcs.enabled === false) {
690
728
  return na("\u9879\u76EE vcs.enabled=false\uFF08\u58F0\u660E\u65E0\u5206\u652F\u6A21\u578B\uFF09\uFF0Cgit \u7C7B\u68C0\u67E5\u8C41\u514D");
691
729
  }
692
- if (ctx.repoPath === null) {
693
- return na(`\u4ED3\u5E93\u4E0D\u53EF\u7528\uFF1A${ctx.repoProbeDetail}`);
730
+ if (ctx.repos.length === 0) {
731
+ return na(`\u5DE5\u4F5C\u76EE\u5F55\u65E0 git \u4ED3\uFF08${ctx.reposScanDetail}\uFF09`);
694
732
  }
695
733
  return null;
696
734
  }
@@ -700,30 +738,32 @@ function na(reason) {
700
738
  function fail2(ctx, type, rootCause, fix) {
701
739
  return { type, status: "fail", detail: `${rootCause}\u3002\u4FEE\u590D\uFF1A${fix}\uFF08\u5F53\u524D nodeId=${ctx.nodeId}\uFF09` };
702
740
  }
703
- async function currentBranch(ctx) {
704
- const r = await ctx.runGit(["rev-parse", "--abbrev-ref", "HEAD"], ctx.repoPath);
741
+ async function currentBranch(ctx, repo) {
742
+ const r = await ctx.runGit(["rev-parse", "--abbrev-ref", "HEAD"], repo);
705
743
  return r.ok ? r.stdout.trim() : null;
706
744
  }
707
745
  async function checkBranchExists(ctx) {
708
746
  const type = "git-branch-exists";
709
747
  const guard = naIfRepoUnavailable(ctx);
710
748
  if (guard) return { ...guard, type };
711
- const branch = await currentBranch(ctx);
712
- if (branch === null) {
713
- return fail2(ctx, type, "\u65E0\u6CD5\u8BFB\u53D6\u5F53\u524D\u5206\u652F\uFF08git rev-parse --abbrev-ref HEAD \u5931\u8D25\uFF09", "\u786E\u8BA4\u5728\u4EFB\u52A1\u5206\u652F\u4E0A\u6267\u884C\uFF0C\u6216\u68C0\u67E5\u4ED3\u5E93\u72B6\u6001");
714
- }
715
- if (branch === "HEAD") {
716
- return fail2(ctx, type, "\u5904\u4E8E detached HEAD \u72B6\u6001\uFF08\u672A\u68C0\u51FA\u4EFB\u4F55\u5206\u652F\uFF09", `git checkout \u4EFB\u52A1\u5206\u652F\uFF08\u987B\u5339\u914D ${ctx.branchPattern} \u524D\u7F00\uFF09`);
717
- }
718
- if (!branch.startsWith(ctx.branchPattern)) {
719
- return fail2(ctx, type, `\u5F53\u524D\u5206\u652F\u300C${branch}\u300D\u4E0D\u5339\u914D\u4EFB\u52A1\u5206\u652F\u89C4\u5219\u300C${ctx.branchPattern} \u524D\u7F00\u300D`, `\u5207\u5230\u4EFB\u52A1\u5206\u652F\uFF08feature/Txxxxxxxx...\uFF09\u540E\u518D\u63A8\u8FDB`);
720
- }
721
- return { type, status: "pass", detail: `\u5F53\u524D\u5206\u652F ${branch}` };
749
+ return perRepoCheck(ctx, type, async (repo) => {
750
+ const branch = await currentBranch(ctx, repo);
751
+ if (branch === null) {
752
+ return { status: "fail", detail: "\u65E0\u6CD5\u8BFB\u53D6\u5F53\u524D\u5206\u652F\uFF08git rev-parse --abbrev-ref HEAD \u5931\u8D25\u2014\u2014\u7591\u4F3C\u635F\u574F\u4ED3\uFF09" };
753
+ }
754
+ if (branch === "HEAD") {
755
+ return { status: "fail", detail: `\u5904\u4E8E detached HEAD \u72B6\u6001\uFF08\u672A\u68C0\u51FA\u4EFB\u4F55\u5206\u652F\uFF09\u2014\u2014git checkout \u4EFB\u52A1\u5206\u652F\uFF08\u987B\u5339\u914D ${ctx.branchPattern} \u524D\u7F00\uFF09` };
756
+ }
757
+ if (!branch.startsWith(ctx.branchPattern)) {
758
+ return { status: "fail", detail: `\u5F53\u524D\u5206\u652F\u300C${branch}\u300D\u4E0D\u5339\u914D\u4EFB\u52A1\u5206\u652F\u89C4\u5219\u300C${ctx.branchPattern} \u524D\u7F00\u300D\u2014\u2014\u5207\u5230\u4EFB\u52A1\u5206\u652F\u540E\u518D\u63A8\u8FDB` };
759
+ }
760
+ return { status: "pass", detail: `\u5F53\u524D\u5206\u652F ${branch}` };
761
+ });
722
762
  }
723
- async function baseMergedIntoHead(ctx, base) {
724
- const f = await ctx.runGit(["fetch", "origin", base], ctx.repoPath);
763
+ async function baseMergedIntoHead(ctx, base, repo) {
764
+ const f = await ctx.runGit(["fetch", "origin", base], repo);
725
765
  if (!f.ok) return null;
726
- const r = await ctx.runGit(["merge-base", "--is-ancestor", `origin/${base}`, "HEAD"], ctx.repoPath);
766
+ const r = await ctx.runGit(["merge-base", "--is-ancestor", `origin/${base}`, "HEAD"], repo);
727
767
  return r.ok;
728
768
  }
729
769
  async function checkBaseMerged(ctx) {
@@ -737,14 +777,17 @@ async function checkBaseMerged(ctx) {
737
777
  if (ctx.baseBranch === null) {
738
778
  return fail2(ctx, type, "\u57FA\u7840\u5206\u652F\u672A\u77E5\uFF08ALIGN \u8BB0\u5F55\u672A\u5199 baseBranch \u4E14\u9879\u76EE\u672A\u914D\u7F6E vcs.baseBranch\uFF09", "record-set \u5199 ALIGN.baseBranch\uFF0C\u6216 siming project update --vcs-base-branch <\u5206\u652F>");
739
779
  }
740
- const merged = await baseMergedIntoHead(ctx, ctx.baseBranch);
741
- if (merged === null) {
742
- return fail2(ctx, type, `git fetch origin ${ctx.baseBranch} \u5931\u8D25\u2014\u2014\u65E0\u6CD5\u4EE5\u8FDC\u7A0B\u6700\u65B0\u5F15\u7528\u5224\u5B9A\uFF08\u62D2\u6309\u9648\u65E7 ref \u8BEF\u5224\uFF09`, "\u68C0\u67E5\u7F51\u7EDC/\u8FDC\u7A0B\u53EF\u8FBE\u540E\u91CD\u8BD5\uFF1B\u786E\u8BA4\u5206\u652F\u5B58\u5728\u4E8E origin");
743
- }
744
- if (!merged) {
745
- return fail2(ctx, type, `origin/${ctx.baseBranch} \u5C1A\u672A\u5408\u5165\u5F53\u524D\u5206\u652F`, `\u6309 ALIGN \u8282\u70B9\u8981\u6C42\u5408\u5E76\u57FA\u7840\u5206\u652F\u8FDC\u7A0B\u6700\u65B0\u4EE3\u7801\uFF08merge ${ctx.baseBranch} \u2192 \u5F53\u524D\u5206\u652F\uFF09\u540E\u91CD\u8BD5`);
746
- }
747
- return { type, status: "pass", detail: `origin/${ctx.baseBranch} \u5DF2\u5408\u5165 HEAD` };
780
+ const base = ctx.baseBranch;
781
+ return perRepoCheck(ctx, type, async (repo) => {
782
+ const merged = await baseMergedIntoHead(ctx, base, repo);
783
+ if (merged === null) {
784
+ return { status: "fail", detail: `git fetch origin ${base} \u5931\u8D25\u2014\u2014\u65E0\u6CD5\u4EE5\u8FDC\u7A0B\u6700\u65B0\u5F15\u7528\u5224\u5B9A\uFF08\u62D2\u6309\u9648\u65E7 ref \u8BEF\u5224\uFF09\uFF1B\u68C0\u67E5\u7F51\u7EDC/\u8FDC\u7A0B\u53EF\u8FBE\u540E\u91CD\u8BD5\uFF0C\u786E\u8BA4\u5206\u652F\u5B58\u5728\u4E8E origin` };
785
+ }
786
+ if (!merged) {
787
+ return { status: "fail", detail: `origin/${base} \u5C1A\u672A\u5408\u5165\u5F53\u524D\u5206\u652F\u2014\u2014\u6309 ALIGN \u8282\u70B9\u8981\u6C42\u5408\u5E76\u57FA\u7840\u5206\u652F\u8FDC\u7A0B\u6700\u65B0\u4EE3\u7801\uFF08merge ${base} \u2192 \u5F53\u524D\u5206\u652F\uFF09\u540E\u91CD\u8BD5` };
788
+ }
789
+ return { status: "pass", detail: `origin/${base} \u5DF2\u5408\u5165 HEAD` };
790
+ });
748
791
  }
749
792
  function findWaivedDecision(ctx, nodeId) {
750
793
  const record = ctx.nodeRecords[nodeId];
@@ -755,16 +798,18 @@ async function checkWorktreeClean(ctx) {
755
798
  const type = "git-worktree-clean";
756
799
  const guard = naIfRepoUnavailable(ctx);
757
800
  if (guard) return { ...guard, type };
758
- const r = await ctx.runGit(["status", "--porcelain"], ctx.repoPath);
759
- if (!r.ok) {
760
- return fail2(ctx, type, `git status \u5931\u8D25\uFF1A${firstLine(r.stderr)}`, "\u68C0\u67E5\u4ED3\u5E93\u53EF\u7528\u6027");
761
- }
762
- if (r.stdout.trim() !== "") {
763
- const count = r.stdout.trim().split("\n").length;
764
- const sample = r.stdout.trim().split("\n").slice(0, 3).join("; ");
765
- return fail2(ctx, type, `\u5DE5\u4F5C\u6811\u4E0D\u5E72\u51C0\uFF08${count} \u5904\u672A\u63D0\u4EA4\u53D8\u66F4\uFF1A${sample}\uFF09`, "\u5B8C\u6210\u672C\u8282\u70B9\u6210\u679C\u63D0\u4EA4\uFF08\u6216\u5199 .gitignore / \u8C41\u514D\u7559\u75D5\uFF09\u540E\u518D\u63A8\u8FDB");
766
- }
767
- return { type, status: "pass", detail: "\u5DE5\u4F5C\u6811\u5E72\u51C0" };
801
+ return perRepoCheck(ctx, type, async (repo) => {
802
+ const r = await ctx.runGit(["status", "--porcelain"], repo);
803
+ if (!r.ok) {
804
+ return { status: "fail", detail: `git status \u5931\u8D25\uFF1A${firstLine(r.stderr)}\u2014\u2014\u68C0\u67E5\u4ED3\u5E93\u53EF\u7528\u6027` };
805
+ }
806
+ if (r.stdout.trim() !== "") {
807
+ const count = r.stdout.trim().split("\n").length;
808
+ const sample = r.stdout.trim().split("\n").slice(0, 3).join("; ");
809
+ return { status: "fail", detail: `\u5DE5\u4F5C\u6811\u4E0D\u5E72\u51C0\uFF08${count} \u5904\u672A\u63D0\u4EA4\u53D8\u66F4\uFF1A${sample}\uFF09\u2014\u2014\u5B8C\u6210\u672C\u8282\u70B9\u6210\u679C\u63D0\u4EA4\uFF08\u6216\u5199 .gitignore / \u8C41\u514D\u7559\u75D5\uFF09\u540E\u518D\u63A8\u8FDB` };
810
+ }
811
+ return { status: "pass", detail: "\u5DE5\u4F5C\u6811\u5E72\u51C0" };
812
+ });
768
813
  }
769
814
  async function checkArchiveMerged(ctx) {
770
815
  const type = "git-archive-merged";
@@ -785,29 +830,31 @@ async function checkArchiveMerged(ctx) {
785
830
  return fail2(ctx, type, "\u57FA\u7840\u5206\u652F\u672A\u77E5\uFF08ACCEPT \u524D\u7F6E\uFF1AALIGN \u5E94\u5DF2\u843D\u76D8 baseBranch\uFF09", "record-set \u5199 ALIGN.baseBranch\uFF0C\u6216 siming project update --vcs-base-branch <\u5206\u652F>");
786
831
  }
787
832
  const base = ctx.baseBranch;
788
- const count = await ctx.runGit(["rev-list", "--count", `${base}..HEAD`], ctx.repoPath);
789
- if (count.ok && count.stdout.trim() === "0") {
790
- return { type, status: "not_applicable", detail: `\u4EFB\u52A1\u5206\u652F\u76F8\u5BF9 ${base} \u96F6\u63D0\u4EA4\uFF08\u65E0\u4EE3\u7801\u6539\u52A8\uFF0C\u65E0\u9700\u5408\u5E76\uFF09` };
791
- }
792
- const fetch2 = await ctx.runGit(["fetch", "origin", base], ctx.repoPath);
793
- if (!fetch2.ok) {
794
- return fail2(ctx, type, `git fetch origin ${base} \u5931\u8D25\u2014\u2014\u672C\u5730\u4E0E\u8FDC\u7A0B\u4E00\u81F4\u6027\u65E0\u4ECE\u5224\u5B9A\uFF08\u62D2\u6309\u9648\u65E7 ref \u8BEF\u5224\uFF09`, "\u68C0\u67E5\u7F51\u7EDC/\u8FDC\u7A0B\u53EF\u8FBE\u540E\u91CD\u8BD5");
795
- }
796
- const ancestor = await ctx.runGit(["merge-base", "--is-ancestor", "HEAD", base], ctx.repoPath);
797
- if (!ancestor.ok) {
798
- return fail2(ctx, type, `\u57FA\u7840\u5206\u652F ${base} \u5C1A\u672A\u5305\u542B\u4EFB\u52A1\u5206\u652F HEAD\uFF08\u672A\u5408\u5E76\uFF09`, `git checkout ${base} && git merge --no-ff <\u4EFB\u52A1\u5206\u652F> && git push`);
799
- }
800
- const merges = await ctx.runGit(["log", "--merges", "-1", "--format=%P", base], ctx.repoPath);
801
- const parents = merges.ok ? merges.stdout.trim().split(/\s+/) : [];
802
- if (parents.length !== 2) {
803
- return fail2(ctx, type, `\u672A\u68C0\u6D4B\u5230 --no-ff \u5408\u5E76\u63D0\u4EA4\uFF08\u6700\u8FD1\u4E00\u6B21\u5408\u5E76 parents=${parents.length}\uFF09`, "\u5408\u5E76\u5FC5\u987B\u4F7F\u7528 --no-ff\uFF08\u4FDD\u7559\u5408\u5E76\u8BB0\u5F55\uFF09\uFF1Agit merge --no-ff <\u4EFB\u52A1\u5206\u652F>");
804
- }
805
- const localBase = await ctx.runGit(["rev-parse", base], ctx.repoPath);
806
- const remoteBase = await ctx.runGit(["rev-parse", `origin/${base}`], ctx.repoPath);
807
- if (!localBase.ok || !remoteBase.ok || localBase.stdout.trim() !== remoteBase.stdout.trim()) {
808
- return fail2(ctx, type, `\u672C\u5730 ${base} \u4E0E origin/${base} \u4E0D\u4E00\u81F4\uFF08\u5408\u5E76\u7ED3\u679C\u672A\u63A8\u9001\u6216\u672A\u62C9\u53D6\uFF09`, `git push origin ${base}\uFF08\u6216\u5148 pull \u5BF9\u9F50\uFF09`);
809
- }
810
- return { type, status: "pass", detail: `\u4EFB\u52A1\u5206\u652F\u5DF2 --no-ff \u5408\u5165 ${base} \u4E14\u5DF2\u4E0E\u8FDC\u7A0B\u4E00\u81F4` };
833
+ return perRepoCheck(ctx, type, async (repo) => {
834
+ const count = await ctx.runGit(["rev-list", "--count", `${base}..HEAD`], repo);
835
+ if (count.ok && count.stdout.trim() === "0") {
836
+ return { status: "not_applicable", detail: `\u4EFB\u52A1\u5206\u652F\u76F8\u5BF9 ${base} \u96F6\u63D0\u4EA4\uFF08\u65E0\u4EE3\u7801\u6539\u52A8\uFF0C\u65E0\u9700\u5408\u5E76\uFF09` };
837
+ }
838
+ const fetch2 = await ctx.runGit(["fetch", "origin", base], repo);
839
+ if (!fetch2.ok) {
840
+ return { status: "fail", detail: `git fetch origin ${base} \u5931\u8D25\u2014\u2014\u672C\u5730\u4E0E\u8FDC\u7A0B\u4E00\u81F4\u6027\u65E0\u4ECE\u5224\u5B9A\uFF08\u62D2\u6309\u9648\u65E7 ref \u8BEF\u5224\uFF09\uFF1B\u68C0\u67E5\u7F51\u7EDC/\u8FDC\u7A0B\u53EF\u8FBE\u540E\u91CD\u8BD5` };
841
+ }
842
+ const ancestor = await ctx.runGit(["merge-base", "--is-ancestor", "HEAD", base], repo);
843
+ if (!ancestor.ok) {
844
+ return { status: "fail", detail: `\u57FA\u7840\u5206\u652F ${base} \u5C1A\u672A\u5305\u542B\u4EFB\u52A1\u5206\u652F HEAD\uFF08\u672A\u5408\u5E76\uFF09\u2014\u2014git checkout ${base} && git merge --no-ff <\u4EFB\u52A1\u5206\u652F> && git push` };
845
+ }
846
+ const merges = await ctx.runGit(["log", "--merges", "-1", "--format=%P", base], repo);
847
+ const parents = merges.ok ? merges.stdout.trim().split(/\s+/) : [];
848
+ if (parents.length !== 2) {
849
+ return { status: "fail", detail: `\u672A\u68C0\u6D4B\u5230 --no-ff \u5408\u5E76\u63D0\u4EA4\uFF08\u6700\u8FD1\u4E00\u6B21\u5408\u5E76 parents=${parents.length}\uFF09\u2014\u2014\u5408\u5E76\u5FC5\u987B\u4F7F\u7528 --no-ff\uFF08\u4FDD\u7559\u5408\u5E76\u8BB0\u5F55\uFF09` };
850
+ }
851
+ const localBase = await ctx.runGit(["rev-parse", base], repo);
852
+ const remoteBase = await ctx.runGit(["rev-parse", `origin/${base}`], repo);
853
+ if (!localBase.ok || !remoteBase.ok || localBase.stdout.trim() !== remoteBase.stdout.trim()) {
854
+ return { status: "fail", detail: `\u672C\u5730 ${base} \u4E0E origin/${base} \u4E0D\u4E00\u81F4\uFF08\u5408\u5E76\u7ED3\u679C\u672A\u63A8\u9001\u6216\u672A\u62C9\u53D6\uFF09\u2014\u2014git push origin ${base}\uFF08\u6216\u5148 pull \u5BF9\u9F50\uFF09` };
855
+ }
856
+ return { status: "pass", detail: `\u5DF2 --no-ff \u5408\u5165 ${base} \u4E14\u4E0E\u8FDC\u7A0B\u4E00\u81F4` };
857
+ });
811
858
  }
812
859
  async function checkStayOnBase(ctx) {
813
860
  const type = "git-stay-on-base";
@@ -822,14 +869,17 @@ async function checkStayOnBase(ctx) {
822
869
  if (ctx.baseBranch === null) {
823
870
  return fail2(ctx, type, "\u57FA\u7840\u5206\u652F\u672A\u77E5\uFF08ARCHIVE \u524D\u7F6E\uFF1AALIGN \u5E94\u5DF2\u843D\u76D8 baseBranch\uFF09", "record-set \u5199 ALIGN.baseBranch\uFF0C\u6216 siming project update --vcs-base-branch <\u5206\u652F>");
824
871
  }
825
- const branch = await currentBranch(ctx);
826
- if (branch === null) {
827
- return fail2(ctx, type, "\u65E0\u6CD5\u8BFB\u53D6\u5F53\u524D\u5206\u652F", "\u786E\u8BA4\u4ED3\u5E93\u72B6\u6001");
828
- }
829
- if (branch !== ctx.baseBranch) {
830
- return fail2(ctx, type, `\u5F52\u6863\u540E\u5E94\u505C\u7559\u57FA\u7840\u5206\u652F\uFF1A\u5F53\u524D\u5728\u300C${branch}\u300D\uFF0C\u671F\u671B\u300C${ctx.baseBranch}\u300D`, `git checkout ${ctx.baseBranch}\uFF08\u7981\u6B62\u7ACB\u5373\u5F00\u59CB\u4E0B\u4E00\u4EFB\u52A1\u5206\u652F\uFF09`);
831
- }
832
- return { type, status: "pass", detail: `\u5F53\u524D\u505C\u7559\u5728\u57FA\u7840\u5206\u652F ${branch}` };
872
+ const base = ctx.baseBranch;
873
+ return perRepoCheck(ctx, type, async (repo) => {
874
+ const branch = await currentBranch(ctx, repo);
875
+ if (branch === null) {
876
+ return { status: "fail", detail: "\u65E0\u6CD5\u8BFB\u53D6\u5F53\u524D\u5206\u652F\u2014\u2014\u786E\u8BA4\u4ED3\u5E93\u72B6\u6001" };
877
+ }
878
+ if (branch !== base) {
879
+ return { status: "fail", detail: `\u5F52\u6863\u540E\u5E94\u505C\u7559\u57FA\u7840\u5206\u652F\uFF1A\u5F53\u524D\u5728\u300C${branch}\u300D\uFF0C\u671F\u671B\u300C${base}\u300D\u2014\u2014git checkout ${base}\uFF08\u7981\u6B62\u7ACB\u5373\u5F00\u59CB\u4E0B\u4E00\u4EFB\u52A1\u5206\u652F\uFF09` };
880
+ }
881
+ return { status: "pass", detail: `\u505C\u7559\u5728\u57FA\u7840\u5206\u652F ${branch}` };
882
+ });
833
883
  }
834
884
  function firstLine(text) {
835
885
  return text.trim().split("\n")[0] ?? "";
@@ -869,18 +919,21 @@ async function checkNoFakeGreen(ctx) {
869
919
  if (ctx.baseBranch === null) {
870
920
  return fail3(type, "\u57FA\u7840\u5206\u652F\u672A\u77E5\uFF08ALIGN.baseBranch \u672A\u843D\u76D8\u4E14\u9879\u76EE\u672A\u914D\u7F6E\uFF09", "record-set \u5199 ALIGN.baseBranch\uFF0C\u6216 siming project update --vcs-base-branch <\u5206\u652F>");
871
921
  }
872
- const diff = await ctx.runGit(
873
- ["diff", `${ctx.baseBranch}...HEAD`, "--", "**/*.test.ts", "**/*.spec.ts", "**/tests/**"],
874
- ctx.repoPath
875
- );
876
- if (!diff.ok) {
877
- return fail3(type, `\u6D4B\u8BD5\u6587\u4EF6 diff \u5931\u8D25\uFF1A${firstLine2(diff.stderr)}`, "\u68C0\u67E5\u4ED3\u5E93\u4E0E\u57FA\u7840\u5206\u652F\u53EF\u7528\u6027");
878
- }
879
- const violations = scanTestDiff(diff.stdout);
880
- if (violations.length > 0) {
881
- return fail3(type, `\u6D4B\u8BD5\u5B8C\u6574\u6027\u8FDD\u89C4\uFF1A${violations.join("\uFF1B")}`, "\u8FD8\u539F\u6D4B\u8BD5\u6539\u52A8\uFF1B\u786E\u5C5E\u5408\u6CD5\u8C03\u6574\u987B\u7ECF\u7528\u6237\u6279\u51C6\u540E record-decision-add \u5199 topic=test-adjust-approved");
882
- }
883
- return { type, status: "pass", detail: "\u6D4B\u8BD5\u6587\u4EF6\u65E0 skip/only \u65B0\u589E\u4E0E\u6574\u5220\uFF08\u653E\u5BBD\u65AD\u8A00\u5F62\u6001\u4E0D\u5728\u673A\u5668\u68C0\u6D4B\u9762\uFF0C\u4F9D\u8D56 test-adjust-approved \u7559\u75D5\u628A\u5173\uFF09" };
922
+ const base = ctx.baseBranch;
923
+ return perRepoCheck(ctx, type, async (repo) => {
924
+ const diff = await ctx.runGit(
925
+ ["diff", `${base}...HEAD`, "--", "**/*.test.ts", "**/*.spec.ts", "**/tests/**"],
926
+ repo
927
+ );
928
+ if (!diff.ok) {
929
+ return { status: "fail", detail: `\u6D4B\u8BD5\u6587\u4EF6 diff \u5931\u8D25\uFF1A${firstLine2(diff.stderr)}\u2014\u2014\u68C0\u67E5\u4ED3\u5E93\u4E0E\u57FA\u7840\u5206\u652F\u53EF\u7528\u6027` };
930
+ }
931
+ const violations = scanTestDiff(diff.stdout);
932
+ if (violations.length > 0) {
933
+ return { status: "fail", detail: `\u6D4B\u8BD5\u5B8C\u6574\u6027\u8FDD\u89C4\uFF1A${violations.join("\uFF1B")}\u2014\u2014\u8FD8\u539F\u6D4B\u8BD5\u6539\u52A8\uFF1B\u786E\u5C5E\u5408\u6CD5\u8C03\u6574\u987B\u7ECF\u7528\u6237\u6279\u51C6\u540E record-decision-add \u5199 topic=test-adjust-approved` };
934
+ }
935
+ return { status: "pass", detail: "\u6D4B\u8BD5\u6587\u4EF6\u65E0 skip/only \u65B0\u589E\u4E0E\u6574\u5220\uFF08\u653E\u5BBD\u65AD\u8A00\u5F62\u6001\u4E0D\u5728\u673A\u5668\u68C0\u6D4B\u9762\uFF0C\u4F9D\u8D56 test-adjust-approved \u7559\u75D5\u628A\u5173\uFF09" };
936
+ });
884
937
  }
885
938
  function scanTestDiff(patch) {
886
939
  const violations = [];
@@ -918,15 +971,18 @@ async function checkBaseReMerged(ctx) {
918
971
  if (ctx.baseBranch === null) {
919
972
  return fail3(type, "\u57FA\u7840\u5206\u652F\u672A\u77E5\uFF08ALIGN.baseBranch \u672A\u843D\u76D8\u4E14\u9879\u76EE\u672A\u914D\u7F6E\uFF09", "record-set \u5199 ALIGN.baseBranch\uFF0C\u6216 siming project update --vcs-base-branch <\u5206\u652F>");
920
973
  }
921
- const fetch2 = await ctx.runGit(["fetch", "origin", ctx.baseBranch], ctx.repoPath);
922
- if (!fetch2.ok) {
923
- return fail3(type, `git fetch origin ${ctx.baseBranch} \u5931\u8D25\u2014\u2014\u65E0\u6CD5\u4EE5\u8FDC\u7A0B\u6700\u65B0\u5F15\u7528\u5224\u5B9A\uFF08\u62D2\u6309\u9648\u65E7 ref \u8BEF\u5224\uFF09`, "\u68C0\u67E5\u7F51\u7EDC/\u8FDC\u7A0B\u53EF\u8FBE\u540E\u91CD\u8BD5");
924
- }
925
- const r = await ctx.runGit(["merge-base", "--is-ancestor", `origin/${ctx.baseBranch}`, "HEAD"], ctx.repoPath);
926
- if (!r.ok) {
927
- return fail3(type, `origin/${ctx.baseBranch} \u589E\u91CF\u672A\u518D\u5408\u5165\u5F53\u524D\u5206\u652F\uFF08\u96C6\u6210\u524D\u57FA\u7840\u5206\u652F\u6709\u65B0\u63D0\u4EA4\uFF09`, `merge ${ctx.baseBranch} \u2192 \u5F53\u524D\u5206\u652F\uFF08\u6D88\u89E3\u6F02\u79FB\uFF09\u540E\u518D\u63A8\u8FDB`);
928
- }
929
- return { type, status: "pass", detail: `origin/${ctx.baseBranch} \u5DF2\u518D\u5408\u5165 HEAD` };
974
+ const base = ctx.baseBranch;
975
+ return perRepoCheck(ctx, type, async (repo) => {
976
+ const fetch2 = await ctx.runGit(["fetch", "origin", base], repo);
977
+ if (!fetch2.ok) {
978
+ return { status: "fail", detail: `git fetch origin ${base} \u5931\u8D25\u2014\u2014\u65E0\u6CD5\u4EE5\u8FDC\u7A0B\u6700\u65B0\u5F15\u7528\u5224\u5B9A\uFF08\u62D2\u6309\u9648\u65E7 ref \u8BEF\u5224\uFF09\uFF1B\u68C0\u67E5\u7F51\u7EDC/\u8FDC\u7A0B\u53EF\u8FBE\u540E\u91CD\u8BD5` };
979
+ }
980
+ const r = await ctx.runGit(["merge-base", "--is-ancestor", `origin/${base}`, "HEAD"], repo);
981
+ if (!r.ok) {
982
+ return { status: "fail", detail: `origin/${base} \u589E\u91CF\u672A\u518D\u5408\u5165\u5F53\u524D\u5206\u652F\uFF08\u96C6\u6210\u524D\u57FA\u7840\u5206\u652F\u6709\u65B0\u63D0\u4EA4\uFF09\u2014\u2014merge ${base} \u2192 \u5F53\u524D\u5206\u652F\uFF08\u6D88\u89E3\u6F02\u79FB\uFF09\u540E\u518D\u63A8\u8FDB` };
983
+ }
984
+ return { status: "pass", detail: `origin/${base} \u5DF2\u518D\u5408\u5165 HEAD` };
985
+ });
930
986
  }
931
987
  async function checkFixReviewPass(ctx) {
932
988
  const type = "record-fix-review-pass";
@@ -948,11 +1004,25 @@ async function checkVerifiedCommit(ctx) {
948
1004
  }
949
1005
  const guard = naIfRepoUnavailable(ctx);
950
1006
  if (guard) return { ...guard, type };
951
- const r = await ctx.runGit(["cat-file", "-e", sha], ctx.repoPath);
952
- if (!r.ok) {
953
- return fail3(type, `verifiedCommit\u300C${sha}\u300D\u5728\u4ED3\u5E93\u4E2D\u4E0D\u5B58\u5728\uFF08cat-file \u5931\u8D25\uFF09`, "record-set \u4FEE\u6B63 verifiedCommit \u4E3A\u771F\u5B9E\u5B58\u5728\u7684\u63D0\u4EA4\u53F7");
1007
+ const hitRepos = [];
1008
+ for (const repo of ctx.repos) {
1009
+ const r = await ctx.runGit(["cat-file", "-e", sha], repo);
1010
+ if (r.ok) hitRepos.push(repo);
1011
+ }
1012
+ if (hitRepos.length > 0) {
1013
+ return {
1014
+ type,
1015
+ status: "pass",
1016
+ detail: `\u9A8C\u8BC1\u7248\u672C ${sha} \u5B58\u5728\uFF08\u547D\u4E2D\u4ED3 ${hitRepos.join("\u3001")}\uFF09
1017
+ ${ctx.reposScanDetail}`
1018
+ };
954
1019
  }
955
- return { type, status: "pass", detail: `\u9A8C\u8BC1\u7248\u672C ${sha} \u5B58\u5728` };
1020
+ return fail3(
1021
+ type,
1022
+ `verifiedCommit\u300C${sha}\u300D\u5728 R \u5168\u90E8\u4ED3\u4E2D\u4E0D\u5B58\u5728\uFF08${ctx.repos.join("\u3001")}\uFF09`,
1023
+ `record-set \u4FEE\u6B63 verifiedCommit \u4E3A\u771F\u5B9E\u5B58\u5728\u7684\u63D0\u4EA4\u53F7
1024
+ ${ctx.reposScanDetail}`
1025
+ );
956
1026
  }
957
1027
  async function checkPrevNodesDone(ctx) {
958
1028
  const type = "record-prev-nodes-done";
@@ -997,24 +1067,58 @@ async function checkVersionConsistent(ctx) {
997
1067
  if (ctx.baseBranch === null) {
998
1068
  return fail3(type, "\u57FA\u7840\u5206\u652F\u672A\u77E5\uFF08ALIGN.baseBranch \u672A\u843D\u76D8\u4E14\u9879\u76EE\u672A\u914D\u7F6E\uFF09", "record-set \u5199 ALIGN.baseBranch\uFF0C\u6216 siming project update --vcs-base-branch <\u5206\u652F>");
999
1069
  }
1000
- const r = await ctx.runGit(["diff", "--name-only", `${sha}..${ctx.baseBranch}`], ctx.repoPath);
1001
- if (!r.ok) {
1002
- return fail3(type, `\u7248\u672C diff \u5931\u8D25\uFF1A${firstLine2(r.stderr)}`, "\u68C0\u67E5 verifiedCommit \u4E0E\u57FA\u7840\u5206\u652F\u53EF\u7528\u6027");
1070
+ const base = ctx.baseBranch;
1071
+ const hitRepos = [];
1072
+ for (const repo of ctx.repos) {
1073
+ const probe = await ctx.runGit(["cat-file", "-e", sha], repo);
1074
+ if (probe.ok) hitRepos.push(repo);
1075
+ }
1076
+ if (hitRepos.length === 0) {
1077
+ return fail3(
1078
+ type,
1079
+ `verifiedCommit\u300C${sha}\u300D\u5728 R \u5168\u90E8\u4ED3\u4E2D\u4E0D\u5B58\u5728\uFF08${ctx.repos.join("\u3001")}\uFF09`,
1080
+ `\u56DE\u8865 INTEGRATE record-set verifiedCommit \u4E3A\u4EFB\u52A1\u4ED3\u771F\u5B9E\u63D0\u4EA4\u53F7\u540E\u91CD\u8BD5
1081
+ ${ctx.reposScanDetail}`
1082
+ );
1003
1083
  }
1004
1084
  const exempt = (path) => ctx.docPaths.some((p) => {
1005
1085
  if (p.endsWith("/")) return path.startsWith(p);
1006
1086
  if (p.startsWith("*")) return path.endsWith(p.slice(1));
1007
1087
  return path === p;
1008
1088
  });
1009
- const leaked = r.stdout.split("\n").map((l) => l.trim()).filter((l) => l !== "" && !exempt(l));
1010
- if (leaked.length > 0) {
1089
+ const leakByRepo = [];
1090
+ const errRepos = [];
1091
+ for (const repo of hitRepos) {
1092
+ const r = await ctx.runGit(["diff", "--name-only", `${sha}..${base}`], repo);
1093
+ if (!r.ok) {
1094
+ errRepos.push(repo);
1095
+ continue;
1096
+ }
1097
+ const leaked = r.stdout.split("\n").map((l) => l.trim()).filter((l) => l !== "" && !exempt(l));
1098
+ if (leaked.length > 0) leakByRepo.push({ repo, leaked });
1099
+ }
1100
+ if (errRepos.length > 0) {
1101
+ return fail3(type, `\u7248\u672C diff \u5931\u8D25\uFF08\u4ED3 ${errRepos.join("\u3001")}\uFF09`, `\u68C0\u67E5 verifiedCommit \u4E0E\u57FA\u7840\u5206\u652F\u53EF\u7528\u6027
1102
+ ${ctx.reposScanDetail}`);
1103
+ }
1104
+ if (leakByRepo.length > 0) {
1105
+ const lines = leakByRepo.slice(0, 3).map((x) => `${x.repo}: ${x.leaked.slice(0, 5).join(", ")}${x.leaked.length > 5 ? ` \u7B49 ${x.leaked.length} \u4E2A` : ""}`);
1106
+ const suffix = leakByRepo.length > 3 ? `\uFF08\u53E6\u6709 ${leakByRepo.length - 3} \u4ED3\u6CC4\u6F0F\u89C1\u9010\u4ED3\u91CD\u67E5\uFF09` : "";
1011
1107
  return fail3(
1012
1108
  type,
1013
- `verifiedCommit \u4E0E ${ctx.baseBranch} \u5B58\u5728\u975E\u6587\u6863\u5DEE\u5F02\uFF08${leaked.slice(0, 5).join(", ")}${leaked.length > 5 ? ` \u7B49 ${leaked.length} \u4E2A` : ""}\uFF09`,
1014
- "\u4EE3\u7801\u6539\u52A8\u987B\u5408\u5E76\u8FDB\u57FA\u7840\u5206\u652F\uFF08\u542B\u5E76\u884C\u4EFB\u52A1 base \u524D\u8FDB\u573A\u666F\uFF1A\u91CD\u8D70\u5408\u5E76\u6216\u7ECF\u7528\u6237\u660E\u793A\u540E force \u63A8\u8FDB\u5E76\u7559\u75D5\uFF09"
1109
+ `verifiedCommit \u4E0E ${base} \u5B58\u5728\u975E\u6587\u6863\u5DEE\u5F02\u2014\u2014${lines.join("\uFF1B")}${suffix}`,
1110
+ `\u4EE3\u7801\u6539\u52A8\u987B\u5408\u5E76\u8FDB\u57FA\u7840\u5206\u652F\uFF08\u542B\u5E76\u884C\u4EFB\u52A1 base \u524D\u8FDB\u573A\u666F\uFF1A\u91CD\u8D70\u5408\u5E76\u6216\u7ECF\u7528\u6237\u660E\u793A\u540E force \u63A8\u8FDB\u5E76\u7559\u75D5\uFF09
1111
+ ${ctx.reposScanDetail}`
1015
1112
  );
1016
1113
  }
1017
- return { type, status: "pass", detail: `verifiedCommit ${sha} \u4E0E ${ctx.baseBranch} \u4E00\u81F4\uFF08\u6587\u6863\u8DEF\u5F84\u8C41\u514D ${ctx.docPaths.join(" ")}\uFF09` };
1114
+ const naRepos = ctx.repos.filter((r) => !hitRepos.includes(r));
1115
+ const naPart = naRepos.length > 0 ? `\uFF1B\u65E0\u951A\u70B9\u4ED3\uFF08\u4E0D\u542B\u8BE5 sha\uFF0C\u514D\u5224\uFF09\uFF1A${naRepos.join("\u3001")}` : "";
1116
+ return {
1117
+ type,
1118
+ status: "pass",
1119
+ detail: `verifiedCommit ${sha} \u4E0E ${base} \u4E00\u81F4\uFF08\u547D\u4E2D\u4ED3 ${hitRepos.join("\u3001")}\uFF1B\u6587\u6863\u8DEF\u5F84\u8C41\u514D ${ctx.docPaths.join(" ")}${naPart}\uFF09
1120
+ ${ctx.reposScanDetail}`
1121
+ };
1018
1122
  }
1019
1123
  async function checkDeferredIssues(ctx) {
1020
1124
  const type = "record-deferred-issues";
@@ -1024,11 +1128,15 @@ async function checkDeferredIssues(ctx) {
1024
1128
  }
1025
1129
  const loaded = await ctx.loadIssueIds();
1026
1130
  if (!loaded.ok) {
1027
- return fail3(type, `\u5173\u8054\u95EE\u9898\u53CD\u67E5\u5931\u8D25\uFF1A${loaded.error}`, "\u68C0\u67E5 server \u53EF\u7528\u6027\u540E\u91CD\u8BD5");
1131
+ return fail3(type, `\u95EE\u9898\u6C60\u53CD\u67E5\u5931\u8D25\uFF1A${loaded.error}`, "\u68C0\u67E5 server \u53EF\u7528\u6027\u540E\u91CD\u8BD5");
1028
1132
  }
1029
1133
  const missing = ids.filter((id) => !loaded.ids.has(id));
1030
1134
  if (missing.length > 0) {
1031
- return fail3(type, `\u5EF6\u671F\u95EE\u9898\u672A\u843D\u6C60\uFF1A${missing.join(", ")}`, "siming issue create \u5C06\u5EF6\u671F\u573A\u666F\u5F55\u5165\u95EE\u9898\u6C60\u540E\uFF0Crecord-set \u4FEE\u6B63 deferredIssues");
1135
+ return fail3(
1136
+ type,
1137
+ `\u5EF6\u671F\u95EE\u9898\u672A\u843D\u6C60\uFF1A${missing.join(", ")}`,
1138
+ "siming issue create \u5C06\u5EF6\u671F\u573A\u666F\u5F55\u5165\u4EFB\u52A1\u6240\u5C5E\u9879\u76EE\u7684\u95EE\u9898\u6C60\uFF08cancelled \u4E0D\u8BA1\u5165\uFF09\u540E\uFF0Crecord-set \u4FEE\u6B63 deferredIssues"
1139
+ );
1032
1140
  }
1033
1141
  return { type, status: "pass", detail: `\u5EF6\u671F\u95EE\u9898 ${ids.length} \u4E2A\u5747\u5DF2\u843D\u6C60` };
1034
1142
  }
@@ -1038,17 +1146,21 @@ async function checkEvidenceFiles(ctx) {
1038
1146
  if (files.length === 0) {
1039
1147
  return fail3(type, "\u672C\u8282\u70B9\u8BB0\u5F55\u672A\u5199 evidenceFiles\uFF08\u89C6\u89C9\u9A8C\u6536\u8BC1\u636E\u7F3A\u5931\uFF09", "record-set \u5199 evidenceFiles\uFF08\u622A\u56FE/\u5F55\u5C4F\u76F8\u5BF9\u8DEF\u5F84\u6E05\u5355\uFF09");
1040
1148
  }
1041
- if (ctx.repoPath === null) {
1042
- return { type, status: "not_applicable", detail: `\u4ED3\u5E93\u4E0D\u53EF\u7528\uFF1A${ctx.repoProbeDetail}` };
1043
- }
1149
+ const guard = naIfRepoUnavailable(ctx);
1150
+ if (guard) return { ...guard, type };
1044
1151
  const missing = [];
1152
+ const hits = [];
1045
1153
  for (const rel of files) {
1046
- if (!ctx.fileExists(`${ctx.repoPath}/${rel}`)) missing.push(rel);
1154
+ const hit = ctx.repos.find((repo) => ctx.fileExists(`${repo}/${rel}`));
1155
+ if (hit === void 0) missing.push(rel);
1156
+ else hits.push({ rel, repo: hit });
1047
1157
  }
1048
1158
  if (missing.length > 0) {
1049
- return fail3(type, `\u8BC1\u636E\u6587\u4EF6\u4E0D\u5B58\u5728\uFF1A${missing.join(", ")}`, "\u8865\u9F50\u8BC1\u636E\u6587\u4EF6\u6216 record-set \u4FEE\u6B63 evidenceFiles \u8DEF\u5F84");
1159
+ return fail3(type, `\u8BC1\u636E\u6587\u4EF6\u4E0D\u5B58\u5728\uFF08${missing.join(", ")}\u2014\u2014R \u5168\u90E8\u4ED3\u67E5\u627E\u65E0\u679C\uFF09`, `\u8865\u9F50\u8BC1\u636E\u6587\u4EF6\u6216 record-set \u4FEE\u6B63 evidenceFiles \u8DEF\u5F84
1160
+ ${ctx.reposScanDetail}`);
1050
1161
  }
1051
- return { type, status: "pass", detail: `\u8BC1\u636E\u6587\u4EF6 ${files.length} \u4E2A\u5747\u5B58\u5728` };
1162
+ return { type, status: "pass", detail: `\u8BC1\u636E\u6587\u4EF6 ${files.length} \u4E2A\u5747\u5B58\u5728\uFF08${hits.map((h) => `${h.rel} @ ${h.repo}`).join("\uFF1B")}\uFF09
1163
+ ${ctx.reposScanDetail}` };
1052
1164
  }
1053
1165
  async function checkFinalConverged(ctx) {
1054
1166
  const type = "record-final-converged";
@@ -1149,10 +1261,95 @@ function auditAiChecks(aiChecks, record) {
1149
1261
  return results;
1150
1262
  }
1151
1263
 
1264
+ // src/client/checks/issue-pool-loader.ts
1265
+ var POOL_STATUSES = "pending,partial,converted,done";
1266
+ var PAGE_LIMIT = 500;
1267
+ var MAX_PAGES = 20;
1268
+ async function loadProjectIssuePoolIds(client, projectId) {
1269
+ const ids = /* @__PURE__ */ new Set();
1270
+ let collected = 0;
1271
+ for (let page = 1; page <= MAX_PAGES; page++) {
1272
+ const r = await client.getJson(
1273
+ `/api/issues?projectId=${encodeURIComponent(projectId)}&status=${encodeURIComponent(POOL_STATUSES)}&limit=${PAGE_LIMIT}&page=${page}`
1274
+ );
1275
+ if (!r.success) return { ok: false, error: r.error.message };
1276
+ for (const item of r.data.items) {
1277
+ const id = item.issueId ?? item.id ?? "";
1278
+ if (id !== "") ids.add(id);
1279
+ }
1280
+ collected += r.data.items.length;
1281
+ if (collected >= r.data.total || r.data.items.length < r.data.limit) {
1282
+ return { ok: true, ids };
1283
+ }
1284
+ }
1285
+ return {
1286
+ ok: false,
1287
+ error: `\u95EE\u9898\u6C60\u5206\u9875\u8D85\u4E0A\u9650\uFF08>${MAX_PAGES} \u9875 \xD7 ${PAGE_LIMIT} \u6761\uFF09\u2014\u2014\u68C0\u67E5\u6570\u636E\u5F62\u6001\u540E\u91CD\u8BD5`
1288
+ };
1289
+ }
1290
+
1152
1291
  // src/client/checks/param-resolver.ts
1153
1292
  import { DEFAULT_VCS_DOC_PATHS } from "@siming-org/core";
1154
1293
  import { execFile } from "child_process";
1155
1294
  import { promisify } from "util";
1295
+
1296
+ // src/config/workspace-repos.ts
1297
+ import { existsSync as existsSync5, readdirSync, readFileSync as readFileSync5 } from "fs";
1298
+ import { join as join5 } from "path";
1299
+ var EXCLUDED_DIR_NAMES = /* @__PURE__ */ new Set(["temp", "node_modules", "dist", "build"]);
1300
+ var DEFAULT_SCAN_DEPTH = 1;
1301
+ var MAX_SCAN_DEPTH = 3;
1302
+ var WORKSPACE_DIR_NAME3 = ".siming";
1303
+ var DEV_JSON_FILE2 = "dev.json";
1304
+ function normalizeScanDepth(raw) {
1305
+ if (typeof raw !== "number" || !Number.isFinite(raw) || !Number.isInteger(raw)) {
1306
+ return DEFAULT_SCAN_DEPTH;
1307
+ }
1308
+ if (raw <= 0) return DEFAULT_SCAN_DEPTH;
1309
+ return Math.min(raw, MAX_SCAN_DEPTH);
1310
+ }
1311
+ function readScanDepth(cwd) {
1312
+ const path = join5(cwd, WORKSPACE_DIR_NAME3, DEV_JSON_FILE2);
1313
+ try {
1314
+ if (!existsSync5(path)) return DEFAULT_SCAN_DEPTH;
1315
+ const parsed = JSON.parse(readFileSync5(path, "utf-8"));
1316
+ return normalizeScanDepth(parsed.scanDepth);
1317
+ } catch {
1318
+ return DEFAULT_SCAN_DEPTH;
1319
+ }
1320
+ }
1321
+ function isGitRepo(dir) {
1322
+ return existsSync5(join5(dir, ".git"));
1323
+ }
1324
+ function isExcludedDir(name) {
1325
+ return EXCLUDED_DIR_NAMES.has(name) || name.startsWith(".");
1326
+ }
1327
+ function scanWorkspaceRepos(cwd, scanDepthOverride) {
1328
+ const scanDepth = scanDepthOverride !== void 0 ? normalizeScanDepth(scanDepthOverride) : readScanDepth(cwd);
1329
+ const repos = [];
1330
+ let scannedDirs = 0;
1331
+ const queue = [{ dir: cwd, depth: 0 }];
1332
+ while (queue.length > 0) {
1333
+ const { dir, depth } = queue.shift();
1334
+ if (isGitRepo(dir)) repos.push(dir);
1335
+ if (depth >= scanDepth) continue;
1336
+ let entries;
1337
+ try {
1338
+ entries = readdirSync(dir, { withFileTypes: true });
1339
+ } catch {
1340
+ continue;
1341
+ }
1342
+ for (const entry of entries) {
1343
+ if (!entry.isDirectory()) continue;
1344
+ scannedDirs++;
1345
+ if (isExcludedDir(entry.name)) continue;
1346
+ queue.push({ dir: join5(dir, entry.name), depth: depth + 1 });
1347
+ }
1348
+ }
1349
+ return { repos, scannedDirs, scanDepth };
1350
+ }
1351
+
1352
+ // src/client/checks/param-resolver.ts
1156
1353
  var execFileAsync = promisify(execFile);
1157
1354
  var defaultGitRunner = async (args, cwd) => {
1158
1355
  try {
@@ -1163,35 +1360,22 @@ var defaultGitRunner = async (args, cwd) => {
1163
1360
  return { ok: false, stdout: e.stdout ?? "", stderr: e.stderr ?? e.message ?? String(err2) };
1164
1361
  }
1165
1362
  };
1166
- async function resolveCheckContextWithRunner(base, vcs, cwd, runGit) {
1167
- const probe = vcs.repoPath !== void 0 ? await probeRepo(vcs.repoPath, runGit) : await probeRepo(cwd, runGit);
1363
+ async function resolveCheckContextWithRunner(base, vcs, cwd, scan) {
1364
+ const result = scan !== void 0 ? scan(cwd) : scanWorkspaceRepos(cwd);
1168
1365
  const alignRecord = base.nodeRecords["ALIGN"];
1169
1366
  const baseBranch = (alignRecord?.baseBranch !== void 0 && alignRecord.baseBranch !== "" ? alignRecord.baseBranch : void 0) ?? vcs.baseBranch ?? null;
1170
1367
  return {
1171
1368
  ...base,
1172
- repoPath: probe.repoPath,
1173
- repoProbeDetail: probe.detail,
1369
+ repos: result.repos,
1370
+ reposScanDetail: `scanned from: ${cwd}\uFF08\u5BBF\u4E3B\u542F\u52A8 cwd\u2014\u2014\u5B50\u76EE\u5F55\u542F\u52A8\u4F1A\u9759\u9ED8\u6F0F\u4ED3\uFF09\uFF1Brepos(${result.repos.length}): ${result.repos.join(", ") || "\u65E0"}\uFF1BscanDepth=${result.scanDepth}\uFF1BscannedDirs=${result.scannedDirs}`,
1174
1371
  baseBranch,
1175
1372
  branchPattern: vcs.branchPattern ?? "feature/",
1176
1373
  docPaths: vcs.docPaths ?? [...DEFAULT_VCS_DOC_PATHS]
1177
1374
  };
1178
1375
  }
1179
- async function probeRepo(candidate, runGit) {
1180
- const r = await runGit(["rev-parse", "--show-toplevel"], candidate);
1181
- if (!r.ok) {
1182
- return {
1183
- repoPath: null,
1184
- detail: `\u4ED3\u5E93\u63A2\u6D4B\u5931\u8D25\uFF1ArepoPath \u5019\u9009\u300C${candidate}\u300D\uFF08git rev-parse --show-toplevel \u5931\u8D25\uFF1A${firstLine3(r.stderr)}\uFF09`
1185
- };
1186
- }
1187
- return { repoPath: firstLine3(r.stdout), detail: "" };
1188
- }
1189
- function firstLine3(text) {
1190
- return text.trim().split("\n")[0] ?? "";
1191
- }
1192
1376
 
1193
1377
  // src/client/checks/runner.ts
1194
- import { existsSync as existsSync5 } from "fs";
1378
+ import { existsSync as existsSync6 } from "fs";
1195
1379
  function gateHasFailure(report) {
1196
1380
  return report.toolOutcomes.some((o) => o.status === "fail") || report.aiOutcomes.some((o) => o.status === "fail");
1197
1381
  }
@@ -1234,20 +1418,13 @@ async function runNodeGate(client, taskId) {
1234
1418
  vcs,
1235
1419
  ...vcsLoadError !== void 0 ? { vcsLoadError } : {},
1236
1420
  runGit: defaultGitRunner,
1237
- loadIssueIds: async () => {
1238
- const r = await client.getJson(
1239
- `/api/tasks/${encodeURIComponent(taskId)}/issues`
1240
- );
1241
- if (!r.success) return { ok: false, error: r.error.message };
1242
- const ids = new Set(r.data.items.map((i) => i.issueId ?? i.id ?? ""));
1243
- ids.delete("");
1244
- return { ok: true, ids };
1245
- },
1246
- fileExists: (p) => existsSync5(p)
1421
+ // B8 判定通道(T202610100001):同项目问题池存在性——旧任务绑定视图(GET
1422
+ // /api/tasks/:taskId/issues)对普通入池 issue 恒空集,详见 issue-pool-loader.ts 头注
1423
+ loadIssueIds: () => loadProjectIssuePoolIds(client, context.task.projectId),
1424
+ fileExists: (p) => existsSync6(p)
1247
1425
  },
1248
1426
  vcs,
1249
- process.cwd(),
1250
- defaultGitRunner
1427
+ process.cwd()
1251
1428
  );
1252
1429
  const toolOutcomes = [];
1253
1430
  for (const toolCheck of toolChecks) {
@@ -1576,7 +1753,7 @@ async function resolveArtifactBatchEntries(entries) {
1576
1753
  let content = inlineContent;
1577
1754
  if (filePath !== void 0) {
1578
1755
  try {
1579
- content = readFileSync5(filePath, "utf-8");
1756
+ content = readFileSync6(filePath, "utf-8");
1580
1757
  } catch (e) {
1581
1758
  localFailures.push({ index, message: `\u6587\u4EF6\u8BFB\u53D6\u5931\u8D25: ${filePath}\uFF08${e instanceof Error ? e.message : String(e)}\uFF09` });
1582
1759
  continue;
@@ -1662,7 +1839,7 @@ async function handleArchNoteAddBatch(client, taskId, texts) {
1662
1839
  }
1663
1840
 
1664
1841
  // src/client/handlers/dag.ts
1665
- import { readFileSync as readFileSync6 } from "fs";
1842
+ import { readFileSync as readFileSync7 } from "fs";
1666
1843
  import { parse as parseYaml } from "yaml";
1667
1844
  import {
1668
1845
  BIZ_CODE_MESSAGES,
@@ -1884,13 +2061,13 @@ async function handleUpgradeApply(client, templateId, decisions) {
1884
2061
 
1885
2062
  // src/client/handlers/auth.ts
1886
2063
  import {
1887
- existsSync as existsSync6,
1888
- readFileSync as readFileSync7,
2064
+ existsSync as existsSync7,
2065
+ readFileSync as readFileSync8,
1889
2066
  writeFileSync as writeFileSync4,
1890
2067
  renameSync as renameSync3,
1891
2068
  mkdirSync as mkdirSync4
1892
2069
  } from "fs";
1893
- import { join as join5 } from "path";
2070
+ import { join as join6 } from "path";
1894
2071
  import { isAbsolute as isAbsolute2 } from "path";
1895
2072
  async function handleWhoami(client) {
1896
2073
  const res = await client.getJson("/api/auth/whoami");
@@ -1973,12 +2150,12 @@ function writeWorkspaceLayer(token, kind, opts) {
1973
2150
  hint: "\u5728\u9879\u76EE\u5DE5\u4F5C\u533A\u6839\u76EE\u5F55\uFF08\u542B .siming/\uFF09\u6267\u884C\uFF0C\u6216\u5148\u521B\u5EFA .siming/ \u76EE\u5F55\uFF1B\u7528\u6237\u7EA7\u5168\u5C40\u914D\u7F6E\u53EF\u52A0 --global\uFF08\u4EFB\u610F\u76EE\u5F55\u53EF\u5199\uFF09"
1974
2151
  });
1975
2152
  }
1976
- const devJsonPath = join5(dir, ".siming", "dev.json");
2153
+ const devJsonPath = join6(dir, ".siming", "dev.json");
1977
2154
  let config = {};
1978
2155
  let hadIsolationKeys = false;
1979
- if (existsSync6(devJsonPath)) {
2156
+ if (existsSync7(devJsonPath)) {
1980
2157
  try {
1981
- config = JSON.parse(readFileSync7(devJsonPath, "utf-8"));
2158
+ config = JSON.parse(readFileSync8(devJsonPath, "utf-8"));
1982
2159
  hadIsolationKeys = "serverPort" in config || "dbPrefix" in config;
1983
2160
  } catch {
1984
2161
  return fail({
@@ -1997,7 +2174,7 @@ function writeWorkspaceLayer(token, kind, opts) {
1997
2174
  });
1998
2175
  }
1999
2176
  config.authToken = token;
2000
- mkdirSync4(join5(dir, ".siming"), { recursive: true });
2177
+ mkdirSync4(join6(dir, ".siming"), { recursive: true });
2001
2178
  const tmp = `${devJsonPath}.tmp`;
2002
2179
  writeFileSync4(tmp, JSON.stringify(config, null, 2) + "\n", "utf-8");
2003
2180
  renameSync3(tmp, devJsonPath);
@@ -2739,7 +2916,7 @@ function createMcpServer() {
2739
2916
  let fullText = content;
2740
2917
  if (file) {
2741
2918
  try {
2742
- fullText = readFileSync8(file, "utf-8");
2919
+ fullText = readFileSync9(file, "utf-8");
2743
2920
  } catch (e) {
2744
2921
  return localError(`\u6587\u4EF6\u8BFB\u53D6\u5931\u8D25: ${file}\uFF08${e instanceof Error ? e.message : String(e)}\uFF09`);
2745
2922
  }
@@ -2978,7 +3155,7 @@ async function mcpServeCommand() {
2978
3155
 
2979
3156
  // src/commands/task/command.ts
2980
3157
  import { Command as Command2 } from "commander";
2981
- import { readFileSync as readFileSync10 } from "fs";
3158
+ import { readFileSync as readFileSync11 } from "fs";
2982
3159
  import { z as z5 } from "zod";
2983
3160
  import {
2984
3161
  ARTIFACT_TYPES as ARTIFACT_TYPES3,
@@ -3092,7 +3269,7 @@ function renderResult(format, result, opts) {
3092
3269
  }
3093
3270
 
3094
3271
  // src/commands/opts.ts
3095
- import { readFileSync as readFileSync9 } from "fs";
3272
+ import { readFileSync as readFileSync10 } from "fs";
3096
3273
  import "commander";
3097
3274
  import { z as z4 } from "zod";
3098
3275
  import { canonicalizeReferencePath, createReferencesSchema } from "@siming-org/core";
@@ -3147,7 +3324,7 @@ function parseRefFlags(refs, mainDocName) {
3147
3324
  seen.add(canonicalizeReferencePath(relPath));
3148
3325
  let content;
3149
3326
  try {
3150
- content = readFileSync9(localPath, "utf-8");
3327
+ content = readFileSync10(localPath, "utf-8");
3151
3328
  } catch (e) {
3152
3329
  return fail({
3153
3330
  message: `--ref \u672C\u5730\u6587\u4EF6\u4E0D\u53EF\u8BFB\uFF1A"${localPath}"`,
@@ -3641,7 +3818,7 @@ function createTaskCommand() {
3641
3818
  let content;
3642
3819
  if (opts.file) {
3643
3820
  try {
3644
- content = readFileSync10(opts.file, "utf-8");
3821
+ content = readFileSync11(opts.file, "utf-8");
3645
3822
  } catch (e) {
3646
3823
  renderResult(opts.format, fail({ message: `\u6587\u4EF6\u8BFB\u53D6\u5931\u8D25: ${opts.file}\uFF08${e instanceof Error ? e.message : String(e)}\uFF09`, httpStatus: 0 }));
3647
3824
  return;
@@ -3896,18 +4073,18 @@ import { Command as Command3 } from "commander";
3896
4073
  import { SKILL_MAIN_DOC, SkillScopeSchema } from "@siming-org/core";
3897
4074
 
3898
4075
  // src/client/scaffold-templates.ts
3899
- import { existsSync as existsSync7, readdirSync, readFileSync as readFileSync11 } from "fs";
3900
- import { dirname as dirname3, join as join6 } from "path";
4076
+ import { existsSync as existsSync8, readdirSync as readdirSync2, readFileSync as readFileSync12 } from "fs";
4077
+ import { dirname as dirname3, join as join7 } from "path";
3901
4078
  import { fileURLToPath } from "url";
3902
- var SCAFFOLD_DIR = join6("templates", "project-skills");
4079
+ var SCAFFOLD_DIR = join7("templates", "project-skills");
3903
4080
  var KEBAB_CASE = /^[a-z0-9]+(-[a-z0-9]+)*$/;
3904
4081
  function resolveCliPackageRoot() {
3905
4082
  let dir = dirname3(fileURLToPath(import.meta.url));
3906
4083
  for (let depth = 0; depth < 10; depth += 1) {
3907
- const pkgFile = join6(dir, "package.json");
3908
- if (existsSync7(pkgFile)) {
4084
+ const pkgFile = join7(dir, "package.json");
4085
+ if (existsSync8(pkgFile)) {
3909
4086
  try {
3910
- const pkg = JSON.parse(readFileSync11(pkgFile, "utf-8"));
4087
+ const pkg = JSON.parse(readFileSync12(pkgFile, "utf-8"));
3911
4088
  if (pkg.name === "@siming-org/cli") return ok2(dir);
3912
4089
  } catch {
3913
4090
  }
@@ -3925,10 +4102,10 @@ function resolveCliPackageRoot() {
3925
4102
  function listScaffoldTemplates() {
3926
4103
  const root = resolveCliPackageRoot();
3927
4104
  if (!root.success) return root;
3928
- const dir = join6(root.data, SCAFFOLD_DIR);
4105
+ const dir = join7(root.data, SCAFFOLD_DIR);
3929
4106
  let entries;
3930
4107
  try {
3931
- entries = readdirSync(dir);
4108
+ entries = readdirSync2(dir);
3932
4109
  } catch {
3933
4110
  return fail({
3934
4111
  message: `\u9AA8\u67B6\u6A21\u677F\u76EE\u5F55\u7F3A\u5931\uFF1A${SCAFFOLD_DIR}`,
@@ -3987,7 +4164,7 @@ function loadScaffoldTemplate(name) {
3987
4164
  if (!root.success) return root;
3988
4165
  let text;
3989
4166
  try {
3990
- text = readFileSync11(join6(root.data, SCAFFOLD_DIR, `${name}.md`), "utf-8");
4167
+ text = readFileSync12(join7(root.data, SCAFFOLD_DIR, `${name}.md`), "utf-8");
3991
4168
  } catch (e) {
3992
4169
  return fail({
3993
4170
  message: `\u9AA8\u67B6\u6587\u4EF6\u4E0D\u53EF\u8BFB\uFF1A${SCAFFOLD_DIR}/${name}.md`,
@@ -4809,7 +4986,7 @@ function agentFields(a) {
4809
4986
  }
4810
4987
 
4811
4988
  // src/commands/dag/command.ts
4812
- import { readFileSync as readFileSync12 } from "fs";
4989
+ import { readFileSync as readFileSync13 } from "fs";
4813
4990
  import { Command as Command5 } from "commander";
4814
4991
  function createDagCommand() {
4815
4992
  const dag = new Command5("dag").description("DAG template & instance management");
@@ -4867,7 +5044,7 @@ function createDagCommand() {
4867
5044
  const client = createClient(opts.url);
4868
5045
  let text;
4869
5046
  try {
4870
- text = readFileSync12(file, "utf-8");
5047
+ text = readFileSync13(file, "utf-8");
4871
5048
  } catch (e) {
4872
5049
  renderResult("json", fail({
4873
5050
  message: `\u6587\u4EF6\u8BFB\u53D6\u5931\u8D25: ${file}\uFF08${e instanceof Error ? e.message : String(e)}\uFF09`,
@@ -5213,7 +5390,7 @@ function diffSummary(item) {
5213
5390
  }
5214
5391
 
5215
5392
  // src/commands/node/command.ts
5216
- import { readFileSync as readFileSync13 } from "fs";
5393
+ import { readFileSync as readFileSync14 } from "fs";
5217
5394
  import { Command as Command6 } from "commander";
5218
5395
  import { SkillScopeSchema as SkillScopeSchema2 } from "@siming-org/core";
5219
5396
 
@@ -5451,7 +5628,7 @@ function createNodeCommand() {
5451
5628
  let prompt = opts.prompt ?? "";
5452
5629
  if (opts.promptFile !== void 0) {
5453
5630
  try {
5454
- prompt = readFileSync13(opts.promptFile, "utf-8");
5631
+ prompt = readFileSync14(opts.promptFile, "utf-8");
5455
5632
  } catch (e) {
5456
5633
  renderResult("json", fail({
5457
5634
  message: `prompt \u6587\u4EF6\u8BFB\u53D6\u5931\u8D25: ${opts.promptFile}\uFF08${e instanceof Error ? e.message : String(e)}\uFF09`,
@@ -5496,7 +5673,7 @@ function createNodeCommand() {
5496
5673
  let prompt;
5497
5674
  if (opts.promptFile !== void 0) {
5498
5675
  try {
5499
- prompt = readFileSync13(opts.promptFile, "utf-8");
5676
+ prompt = readFileSync14(opts.promptFile, "utf-8");
5500
5677
  } catch (e) {
5501
5678
  renderResult("json", fail({
5502
5679
  message: `prompt \u6587\u4EF6\u8BFB\u53D6\u5931\u8D25: ${opts.promptFile}\uFF08${e instanceof Error ? e.message : String(e)}\uFF09`,
@@ -5511,7 +5688,7 @@ function createNodeCommand() {
5511
5688
  if (opts.checksFile !== void 0) {
5512
5689
  let parsed;
5513
5690
  try {
5514
- parsed = JSON.parse(readFileSync13(opts.checksFile, "utf-8"));
5691
+ parsed = JSON.parse(readFileSync14(opts.checksFile, "utf-8"));
5515
5692
  } catch (e) {
5516
5693
  renderResult("json", fail({
5517
5694
  message: `checks \u6587\u4EF6\u8BFB\u53D6/\u89E3\u6790\u5931\u8D25: ${opts.checksFile}\uFF08${e instanceof Error ? e.message : String(e)}\uFF09`,
@@ -5619,7 +5796,7 @@ function nodeFields2(n) {
5619
5796
  import { execFile as execFile2 } from "child_process";
5620
5797
  import { mkdtempSync, rmSync as rmSync2 } from "fs";
5621
5798
  import { tmpdir } from "os";
5622
- import { join as join7 } from "path";
5799
+ import { join as join8 } from "path";
5623
5800
  import { promisify as promisify2 } from "util";
5624
5801
  import { createInterface } from "readline/promises";
5625
5802
  import { Command as Command7 } from "commander";
@@ -6061,7 +6238,7 @@ ${conflicts.map((item) => ` ${item.kind}:${item.key} \u2014 ${item.reason ?? "\
6061
6238
  async function fetchManifest(pkgSpec, registry) {
6062
6239
  let dir;
6063
6240
  try {
6064
- dir = mkdtempSync(join7(tmpdir(), "siming-flow-"));
6241
+ dir = mkdtempSync(join8(tmpdir(), "siming-flow-"));
6065
6242
  } catch (error) {
6066
6243
  return fail({
6067
6244
  message: `\u4E34\u65F6\u76EE\u5F55\u521B\u5EFA\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`,
@@ -6098,7 +6275,7 @@ async function fetchManifest(pkgSpec, registry) {
6098
6275
  }
6099
6276
  const { stdout: manifestText } = await execFileAsync2(
6100
6277
  "tar",
6101
- ["-xOf", join7(dir, filename), "package/siming-nodes.json"],
6278
+ ["-xOf", join8(dir, filename), "package/siming-nodes.json"],
6102
6279
  { maxBuffer: MANIFEST_LIMITS.maxChars * 2 + 64 * 1024 }
6103
6280
  );
6104
6281
  const parsed = parseFlowManifest(manifestText);
@@ -6969,7 +7146,7 @@ function createProjectCommand() {
6969
7146
  const result = await handleGetProject(client, id);
6970
7147
  renderResult(opts.format, result, { fields: result.success ? projectFields(result.data) : [] });
6971
7148
  });
6972
- project.command("update <id>").description("Update a project (name/description/status/vcs gate config). vcs is replaced as a whole: any --vcs-* flag replaces the entire vcs object with only the provided fields").option("--url <url>", "server base URL").option("--name <name>", "new name").option("--description <text>", "new description").option("--vcs-enabled <bool>", "gate VCS checks for this project (true/false; false=all git checks N/A)").option("--vcs-repo-path <path>", "repository absolute path (default: MCP host cwd probing)").option("--vcs-base-branch <branch>", "base branch (2nd level of the base-branch resolution chain)").option("--vcs-branch-pattern <pattern>", "task branch prefix pattern for A1").option("--vcs-worktree-mode <bool>", "worktree parallel mode (true=A6 stay-on-base N/A)").option("--vcs-archive-to-base <bool>", "project declares merge-back-to-base archive flow (false=A5 N/A)").option("--vcs-doc-paths <paths>", "B7 exemption paths, comma separated (dirs need trailing /, glob like *.md)").action(async (id, opts) => {
7149
+ project.command("update <id>").description("Update a project (name/description/status/vcs gate config). vcs is replaced as a whole: any --vcs-* flag replaces the entire vcs object with only the provided fields").option("--url <url>", "server base URL").option("--name <name>", "new name").option("--description <text>", "new description").option("--vcs-enabled <bool>", "gate VCS checks for this project (true/false; false=all git checks N/A)").option("--vcs-repo-path <path>", "[deprecated] no longer read by gate resolution \u2014 task repos are discovered by scanning the working directory (T202610080003); flag kept writable for DB compatibility only").option("--vcs-base-branch <branch>", "base branch (2nd level of the base-branch resolution chain)").option("--vcs-branch-pattern <pattern>", "task branch prefix pattern for A1").option("--vcs-worktree-mode <bool>", "worktree parallel mode (true=A6 stay-on-base N/A)").option("--vcs-archive-to-base <bool>", "project declares merge-back-to-base archive flow (false=A5 N/A)").option("--vcs-doc-paths <paths>", "B7 exemption paths, comma separated (dirs need trailing /, glob like *.md)").action(async (id, opts) => {
6973
7150
  const client = createClient(opts.url);
6974
7151
  const parseBool = (v, flag) => {
6975
7152
  if (v === void 0) return void 0;
@@ -6993,6 +7170,7 @@ function createProjectCommand() {
6993
7170
  vcsProvided = true;
6994
7171
  }
6995
7172
  if (opts.vcsRepoPath !== void 0) {
7173
+ console.error(`[siming] deprecated: --vcs-repo-path \u5DF2\u9000\u5F79\u2014\u2014\u95E8\u7981\u4EFB\u52A1\u4ED3\u96C6\u5408 = \u5DE5\u4F5C\u76EE\u5F55\u626B\u63CF\u5168\u91CF\uFF08cwd + \u2264scanDepth \u5B50\u76EE\u5F55\uFF09\uFF0C\u8BE5\u5B57\u6BB5\u4E0D\u518D\u5F71\u54CD\u5224\u5B9A\uFF1BscanDepth \u53EF\u7ECF <\u5DE5\u4F5C\u76EE\u5F55>/.siming/dev.json \u914D\u7F6E\uFF08\u9ED8\u8BA4 1\uFF0C\u94B3\u5236 \u22643\uFF09`);
6996
7174
  vcsFields.repoPath = opts.vcsRepoPath;
6997
7175
  vcsProvided = true;
6998
7176
  }
@@ -7201,7 +7379,7 @@ function createConfigCommand() {
7201
7379
 
7202
7380
  // src/commands/export/command.ts
7203
7381
  import { Command as Command11 } from "commander";
7204
- import { readFileSync as readFileSync14 } from "fs";
7382
+ import { readFileSync as readFileSync15 } from "fs";
7205
7383
  import { parse as parseYaml2 } from "yaml";
7206
7384
 
7207
7385
  // src/client/handlers/export.ts
@@ -7872,7 +8050,7 @@ function createExportCommand() {
7872
8050
  async function runExportPlan(client, filePath, typesArg) {
7873
8051
  let raw;
7874
8052
  try {
7875
- const text = readFileSync14(filePath, "utf-8");
8053
+ const text = readFileSync15(filePath, "utf-8");
7876
8054
  raw = parseYaml2(text);
7877
8055
  } catch (e) {
7878
8056
  return fail({
@@ -7897,7 +8075,7 @@ async function runExportPlan(client, filePath, typesArg) {
7897
8075
  }
7898
8076
  function loadPlanFile(path) {
7899
8077
  try {
7900
- const text = readFileSync14(path, "utf-8");
8078
+ const text = readFileSync15(path, "utf-8");
7901
8079
  const parsed = JSON.parse(text);
7902
8080
  if (!Array.isArray(parsed.items)) {
7903
8081
  return fail({ message: `\u8BA1\u5212\u6587\u4EF6\u7ED3\u6784\u65E0\u6548\uFF1A\u7F3A\u5C11 items \u6570\u7EC4`, httpStatus: 0, hint: "\u8BA1\u5212\u6587\u4EF6\u7531 `siming export plan --format json > plan.json` \u751F\u6210" });
@@ -7960,14 +8138,14 @@ function renderReport(report, format) {
7960
8138
 
7961
8139
  // src/commands/install/command.ts
7962
8140
  import { Command as Command12 } from "commander";
7963
- import { existsSync as existsSync9 } from "fs";
8141
+ import { existsSync as existsSync10 } from "fs";
7964
8142
  import { createInterface as createInterface2 } from "readline/promises";
7965
- import { dirname as dirname5, join as join9 } from "path";
8143
+ import { dirname as dirname5, join as join10 } from "path";
7966
8144
  import { AGENT_MAIN_DOC as AGENT_MAIN_DOC5, SKILL_MAIN_DOC as SKILL_MAIN_DOC5, VERSION as VERSION3 } from "@siming-org/core";
7967
8145
 
7968
8146
  // src/commands/install/writer.ts
7969
- import { existsSync as existsSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync15, renameSync as renameSync4, rmSync as rmSync3, writeFileSync as writeFileSync5 } from "fs";
7970
- import { dirname as dirname4, join as join8 } from "path";
8147
+ import { existsSync as existsSync9, mkdirSync as mkdirSync5, readFileSync as readFileSync16, renameSync as renameSync4, rmSync as rmSync3, writeFileSync as writeFileSync5 } from "fs";
8148
+ import { dirname as dirname4, join as join9 } from "path";
7971
8149
  import { homedir as homedir4 } from "os";
7972
8150
  import { parse as parseYaml3, stringify as stringifyYaml } from "yaml";
7973
8151
  import {
@@ -7978,12 +8156,12 @@ import {
7978
8156
  } from "@siming-org/core";
7979
8157
  function agentsHomeDir() {
7980
8158
  const env = process.env.SIMING_AGENTS_HOME;
7981
- return env && env.length > 0 ? env : join8(homedir4(), ".agents");
8159
+ return env && env.length > 0 ? env : join9(homedir4(), ".agents");
7982
8160
  }
7983
8161
  function resolveInstallTargets(scope, workspaceDir) {
7984
8162
  if (scope === "global") {
7985
8163
  const dir = agentsHomeDir();
7986
- return { targets: { dir, mcpConfigPath: join8(dir, "mcp.json") } };
8164
+ return { targets: { dir, mcpConfigPath: join9(dir, "mcp.json") } };
7987
8165
  }
7988
8166
  const wd = workspaceDir ?? findWorkspaceDir();
7989
8167
  if (!wd) {
@@ -7991,7 +8169,7 @@ function resolveInstallTargets(scope, workspaceDir) {
7991
8169
  error: "scope=project \u9700\u8981\u5DE5\u4F5C\u533A\uFF08.siming/ \u76EE\u5F55\uFF09\u2014\u2014\u5148\u8FD0\u884C `siming init --project <key|id>` \u7ED1\u5B9A\u9879\u76EE\uFF0C\u6216\u5728\u9879\u76EE\u76EE\u5F55\u5185\u6267\u884C"
7992
8170
  };
7993
8171
  }
7994
- return { targets: { dir: join8(wd, ".agents"), mcpConfigPath: null } };
8172
+ return { targets: { dir: join9(wd, ".agents"), mcpConfigPath: null } };
7995
8173
  }
7996
8174
  function isSafeAssetName(name) {
7997
8175
  if (name.length === 0 || name === "." || name === "..") return false;
@@ -8011,7 +8189,7 @@ function validateReferencesLocally(mainDocName, references) {
8011
8189
  function writeAssetDirectory(assetDir, files) {
8012
8190
  rmSync3(assetDir, { recursive: true, force: true });
8013
8191
  for (const file of files) {
8014
- const target = join8(assetDir, ...file.relPath.split("/"));
8192
+ const target = join9(assetDir, ...file.relPath.split("/"));
8015
8193
  mkdirSync5(dirname4(target), { recursive: true });
8016
8194
  writeFileSync5(target, file.content, "utf-8");
8017
8195
  }
@@ -8028,7 +8206,7 @@ ${skill.content}
8028
8206
  `;
8029
8207
  }
8030
8208
  function skillTargetPath(dir, skill) {
8031
- return join8(dir, "skills", skill.name, "SKILL.md");
8209
+ return join9(dir, "skills", skill.name, "SKILL.md");
8032
8210
  }
8033
8211
  function permissionsToMatrix(permissions) {
8034
8212
  const matrix = {};
@@ -8064,13 +8242,13 @@ ${agent.systemPrompt}
8064
8242
  `;
8065
8243
  }
8066
8244
  function agentTargetPath(dir, agent) {
8067
- return join8(dir, "agents", agent.name, "agent.md");
8245
+ return join9(dir, "agents", agent.name, "agent.md");
8068
8246
  }
8069
8247
  function readSimingVersion(path) {
8070
- if (!existsSync8(path)) return null;
8248
+ if (!existsSync9(path)) return null;
8071
8249
  let text;
8072
8250
  try {
8073
- text = readFileSync15(path, "utf-8");
8251
+ text = readFileSync16(path, "utf-8");
8074
8252
  } catch {
8075
8253
  return null;
8076
8254
  }
@@ -8092,10 +8270,10 @@ function isPlainObject(v) {
8092
8270
  return typeof v === "object" && v !== null && !Array.isArray(v);
8093
8271
  }
8094
8272
  function readMcpConfig(path) {
8095
- if (!existsSync8(path)) return { state: "absent" };
8273
+ if (!existsSync9(path)) return { state: "absent" };
8096
8274
  let text;
8097
8275
  try {
8098
- text = readFileSync15(path, "utf-8");
8276
+ text = readFileSync16(path, "utf-8");
8099
8277
  } catch (e) {
8100
8278
  return { state: "corrupt", error: `\u8BFB\u53D6\u5931\u8D25: ${e instanceof Error ? e.message : String(e)}` };
8101
8279
  }
@@ -8332,7 +8510,7 @@ function compareSkill(s, dir) {
8332
8510
  if (!isSafeAssetName(s.name)) {
8333
8511
  return { ...base, action: "conflict", reason: `unsafe asset name "${s.name}"` };
8334
8512
  }
8335
- if (!existsSync9(path)) return { ...base, action: "install", reason: "not installed locally" };
8513
+ if (!existsSync10(path)) return { ...base, action: "install", reason: "not installed locally" };
8336
8514
  const marked = readSimingVersion(path);
8337
8515
  if (marked === null) {
8338
8516
  return { ...base, localVersion: "unknown", action: "conflict", reason: "no siming-version marker (third-party asset; use --force to overwrite)" };
@@ -8350,7 +8528,7 @@ function compareAgent(a, dir) {
8350
8528
  if (!isSafeAssetName(a.name)) {
8351
8529
  return { ...base, action: "conflict", reason: `unsafe asset name "${a.name}"` };
8352
8530
  }
8353
- if (!existsSync9(path)) return { ...base, action: "install", reason: "not installed locally" };
8531
+ if (!existsSync10(path)) return { ...base, action: "install", reason: "not installed locally" };
8354
8532
  const marked = readSimingVersion(path);
8355
8533
  if (marked === null) {
8356
8534
  return { ...base, localVersion: "unknown", action: "conflict", reason: "no siming-version marker (third-party asset; use --force to overwrite)" };
@@ -8443,7 +8621,7 @@ async function applyInstall(client, scope, projectId, items, opts) {
8443
8621
  results.push({ name: item.name, type: "skill", action: "failed", reason: `invalid reference doc from server: ${invalidRef}`, hint: "\u5F15\u7528\u6587\u6863\u975E\u6CD5\uFF08\u6570\u636E\u53EF\u80FD\u88AB\u7ED5\u8FC7\u6821\u9A8C\u5199\u5165\uFF09\uFF1B\u4FEE\u6B63 server \u6570\u636E\u540E\u91CD\u8BD5\uFF0C\u672C\u6761\u672A\u5199\u5165" });
8444
8622
  continue;
8445
8623
  }
8446
- const targetExists = existsSync9(targetPath);
8624
+ const targetExists = existsSync10(targetPath);
8447
8625
  writeAssetDirectory(dirname5(targetPath), [
8448
8626
  { relPath: SKILL_MAIN_DOC5, content: skillToMarkdown(r.data) },
8449
8627
  ...(r.data.references ?? []).map((ref) => ({ relPath: ref.path, content: ref.content }))
@@ -8479,7 +8657,7 @@ async function applyInstall(client, scope, projectId, items, opts) {
8479
8657
  results.push({ name: item.name, type: "agent", action: "failed", reason: `invalid reference doc from server: ${invalidRef}`, hint: "\u5F15\u7528\u6587\u6863\u975E\u6CD5\uFF08\u6570\u636E\u53EF\u80FD\u88AB\u7ED5\u8FC7\u6821\u9A8C\u5199\u5165\uFF09\uFF1B\u4FEE\u6B63 server \u6570\u636E\u540E\u91CD\u8BD5\uFF0C\u672C\u6761\u672A\u5199\u5165" });
8480
8658
  continue;
8481
8659
  }
8482
- const targetExists = existsSync9(targetPath);
8660
+ const targetExists = existsSync10(targetPath);
8483
8661
  writeAssetDirectory(dirname5(targetPath), [
8484
8662
  { relPath: AGENT_MAIN_DOC5, content: agentToMarkdown(r.data, realModel) },
8485
8663
  ...(r.data.references ?? []).map((ref) => ({ relPath: ref.path, content: ref.content }))
@@ -8503,8 +8681,8 @@ function buildInstallGuidance(scope, targets) {
8503
8681
  const lines = [];
8504
8682
  lines.push("\u2500\u2500 siming \u901A\u7528\u8D44\u4EA7\u8FC1\u79FB\u6307\u5F15\uFF08.agents \u5F00\u653E\u534F\u8BAE\u843D\u70B9\uFF09\u2500\u2500");
8505
8683
  lines.push(`[1] \u8D44\u4EA7\u4F4D\u7F6E\uFF08${scope === "global" ? "\u7528\u6237\u7EA7" : "\u9879\u76EE\u7EA7"} ${targets.dir}\uFF09\uFF1A`);
8506
- lines.push(` - skills: ${join9(targets.dir, "skills")}\uFF08\u6BCF\u4E2A skill \u4E00\u4E2A\u5B50\u76EE\u5F55\uFF0C\u542B SKILL.md \u4E0E\u5176\u5F15\u7528\u6587\u6863\uFF09`);
8507
- lines.push(` - agents: ${join9(targets.dir, "agents")}\uFF08\u6BCF\u4E2A agent \u4E00\u4E2A\u5B50\u76EE\u5F55\uFF0C\u542B agent.md \u4E0E\u5176\u5F15\u7528\u6587\u6863\uFF09`);
8684
+ lines.push(` - skills: ${join10(targets.dir, "skills")}\uFF08\u6BCF\u4E2A skill \u4E00\u4E2A\u5B50\u76EE\u5F55\uFF0C\u542B SKILL.md \u4E0E\u5176\u5F15\u7528\u6587\u6863\uFF09`);
8685
+ lines.push(` - agents: ${join10(targets.dir, "agents")}\uFF08\u6BCF\u4E2A agent \u4E00\u4E2A\u5B50\u76EE\u5F55\uFF0C\u542B agent.md \u4E0E\u5176\u5F15\u7528\u6587\u6863\uFF09`);
8508
8686
  if (targets.mcpConfigPath) {
8509
8687
  lines.push(` - MCP \u6CE8\u518C: ${targets.mcpConfigPath}\uFF08\u9876\u5C42 mcpServers.siming \u2192 stdio \u547D\u4EE4 "siming mcp-serve"\uFF09`);
8510
8688
  }
@@ -8890,7 +9068,8 @@ ${ROADMAP_TEXT}
8890
9068
 
8891
9069
  \u6D41\u7A0B\u6A21\u677F\u7684\u8282\u70B9\u63D0\u793A\u8BCD\u4E2D\uFF0C\u73AF\u5883\u76F8\u5173\u4FE1\u606F\u5168\u90E8\u53C2\u6570\u5316\u4E3A\u300C\u6309\u9879\u76EE\u58F0\u660E\u300D\uFF0C
8892
9070
  \u58F0\u660E\u503C\u843D\u70B9 = \u9879\u76EE\u4ED3\u5E93\u7684 AI \u5165\u53E3\u6587\u4EF6\uFF08\u9879\u76EE AGENTS.md\uFF09\u3002
8893
- \u4EE5\u4E0B 8 \u9879\u58F0\u660E\u4E0D\u9F50\u65F6\uFF0C\u6D41\u7A0B\u4F1A\u5728\u5BF9\u5E94\u73AF\u8282\u6682\u505C\u8BE2\u95EE\u6216\u964D\u7EA7\uFF1A
9071
+ \u4EE5\u4E0B 9 \u9879\u4E2D 1-8 \u4E3A\u73AF\u5883\u58F0\u660E\uFF0C\u4E0D\u9F50\u65F6\u6D41\u7A0B\u4F1A\u5728\u5BF9\u5E94\u73AF\u8282\u6682\u505C\u8BE2\u95EE\u6216\u964D\u7EA7\uFF1B
9072
+ \u7B2C 9 \u9879\u4E3A\u884C\u4E3A\u89C4\u5219\u91CD\u63D0\u793A\uFF08\u89C1\u8868\u683C\u540E\u8BF4\u660E\uFF09\uFF1A
8894
9073
 
8895
9074
  | # | \u58F0\u660E\u9879 | \u58F0\u660E\u5185\u5BB9 | \u7F3A\u5931\u540E\u679C |
8896
9075
  |---|--------|----------|----------|
@@ -8902,6 +9081,10 @@ ${ROADMAP_TEXT}
8902
9081
  | 6 | E2E \u552F\u4E00\u6267\u884C\u5165\u53E3 | E2E \u6D4B\u8BD5\u552F\u4E00\u5408\u6CD5\u7684\u6267\u884C\u547D\u4EE4/\u811A\u672C | E2E \u5F00\u53D1\u73AF\u8282\u65E0\u6CD5\u786E\u5B9A\u6267\u884C\u65B9\u5F0F\uFF0C\u6682\u505C\u8BE2\u95EE |
8903
9082
  | 7 | \u6D4B\u8BD5\u5B8C\u6574\u6027\u68C0\u67E5 | \u9632\u5220\u6D4B/\u7981 skip \u7684\u9759\u6001\u68C0\u67E5\u547D\u4EE4 | \u6D4B\u8BD5\u6536\u5C3E\u7F3A\u5C11\u95E8\u7981\u4F9D\u636E\uFF0C\u6682\u505C\u8BE2\u95EE |
8904
9083
  | 8 | \u547D\u4EE4\u65E5\u5FD7\u843D\u76D8 | \u6784\u5EFA/\u6D4B\u8BD5\u547D\u4EE4\u7684\u65E5\u5FD7\u5F52\u6863\u7EA6\u5B9A | \u547D\u4EE4\u6267\u884C\u65E0\u6CD5\u56DE\u6EAF\uFF0C\u5F52\u6863\u8282\u70B9\u8BC1\u636E\u4E0D\u8DB3 |
9084
+ | 9 | \u590D\u5BA1\u59D4\u6D3E\u89C4\u5219 | \u591A\u8F6E\u590D\u5BA1\u4F18\u5148\u540C\u4E00 reviewer \u4F1A\u8BDD\u7EED\u804A\uFF1B\u6362\u65B0\u4F1A\u8BDD\u65F6\u968F\u9644\u4E0A\u8F6E Findings \u4E0E\u5904\u7F6E\u72B6\u6001\uFF08\u8868\u8FF0\u5BF9\u9F50 workflow-discipline\u300C\u59D4\u6D3E\u7EAA\u5F8B\u300D\uFF09 | \u591A\u8F6E\u8BC4\u5BA1\u9000\u5316\u4E3A\u6BCF\u8F6E\u5168\u65B0\u5168\u91CF\u8BC4\u5BA1\uFF0C\u91CD\u590D\u6D88\u8017\u65F6\u95F4\u4E0E token |
9085
+
9086
+ \u7B2C 9 \u9879\u4E3A\u884C\u4E3A\u89C4\u5219\u91CD\u63D0\u793A\uFF1A\u6743\u5A01\u6E90\u662F workflow-discipline \u59D4\u6D3E\u7EAA\u5F8B\uFF08\u8282\u70B9\u52A0\u8F7D\uFF09\uFF0C
9087
+ \u5728\u9879\u76EE AGENTS.md \u91CD\u590D\u5199\u5165\u53EF\u63D0\u9AD8\u8DE8\u5BBF\u4E3B\u9075\u5FAA\u7387\uFF08\u5E38\u9A7B\u5165\u53E3\u5148\u4E8E\u8282\u70B9\u52A0\u8F7D\u751F\u6548\uFF09\u3002
8905
9088
 
8906
9089
  ----------------------------------------------------------------
8907
9090
  \u4E8C\u3001\u6D41\u7A0B\u6A21\u677F\u83B7\u53D6\u6307\u5F15
@@ -9092,8 +9275,8 @@ import { VERSION as VERSION4, SIMING_CONFIG_KEYS as SIMING_CONFIG_KEYS2 } from "
9092
9275
 
9093
9276
  // src/commands/server/daemon.ts
9094
9277
  import { execFileSync } from "child_process";
9095
- import { closeSync, existsSync as existsSync10, lstatSync, mkdirSync as mkdirSync6, openSync, readFileSync as readFileSync16, renameSync as renameSync5, rmSync as rmSync4, writeFileSync as writeFileSync6 } from "fs";
9096
- import { join as join10, resolve as resolve2 } from "path";
9278
+ import { closeSync, existsSync as existsSync11, lstatSync, mkdirSync as mkdirSync6, openSync, readFileSync as readFileSync17, renameSync as renameSync5, rmSync as rmSync4, writeFileSync as writeFileSync6 } from "fs";
9279
+ import { join as join11, resolve as resolve2 } from "path";
9097
9280
  import { spawn } from "child_process";
9098
9281
 
9099
9282
  // src/commands/server/probe.ts
@@ -9110,10 +9293,10 @@ function runtimeDir() {
9110
9293
  return process.env.SIMING_RUNTIME_DIR ?? "/tmp/siming";
9111
9294
  }
9112
9295
  function pidfilePath() {
9113
- return join10(runtimeDir(), "server.pid");
9296
+ return join11(runtimeDir(), "server.pid");
9114
9297
  }
9115
9298
  function logfilePath() {
9116
- return join10(runtimeDir(), "server.log");
9299
+ return join11(runtimeDir(), "server.log");
9117
9300
  }
9118
9301
  var READY_TIMEOUT_MS = 2e4;
9119
9302
  var STOP_GRACE_MS = 1e4;
@@ -9146,7 +9329,7 @@ function readPidFile() {
9146
9329
  try {
9147
9330
  const st = lstatSync(pidfilePath(), { throwIfNoEntry: false });
9148
9331
  if (st === void 0 || st.isSymbolicLink()) return null;
9149
- const parsed = JSON.parse(readFileSync16(pidfilePath(), "utf-8").trim());
9332
+ const parsed = JSON.parse(readFileSync17(pidfilePath(), "utf-8").trim());
9150
9333
  if (typeof parsed.pid !== "number" || typeof parsed.startedAt !== "number" || typeof parsed.port !== "number") {
9151
9334
  return null;
9152
9335
  }
@@ -9187,7 +9370,7 @@ function removePidFile(expectedPid) {
9187
9370
  }
9188
9371
  function readCmdline(pid) {
9189
9372
  try {
9190
- const raw = readFileSync16(`/proc/${pid}/cmdline`);
9373
+ const raw = readFileSync17(`/proc/${pid}/cmdline`);
9191
9374
  const joined = raw.toString().split("\0").filter((s) => s.length > 0).join(" ");
9192
9375
  if (joined.length > 0) return joined;
9193
9376
  } catch {
@@ -9216,7 +9399,7 @@ function isSimingDaemonCmdline(cmdline, expectedEntry) {
9216
9399
  }
9217
9400
  function readProcessStartMs(pid) {
9218
9401
  try {
9219
- const stat = readFileSync16(`/proc/${pid}/stat`, "utf-8");
9402
+ const stat = readFileSync17(`/proc/${pid}/stat`, "utf-8");
9220
9403
  const rest = stat.slice(stat.lastIndexOf(")") + 2);
9221
9404
  const fields = rest.split(" ");
9222
9405
  const starttimeJiffies = Number(fields[19]);
@@ -9245,7 +9428,7 @@ function readProcessStartMs(pid) {
9245
9428
  }
9246
9429
  function readBtimeFromProcStat() {
9247
9430
  try {
9248
- const stat = readFileSync16("/proc/stat", "utf-8");
9431
+ const stat = readFileSync17("/proc/stat", "utf-8");
9249
9432
  for (const line of stat.split("\n")) {
9250
9433
  if (line.startsWith("btime ")) {
9251
9434
  const v = Number(line.slice(6).trim());
@@ -9296,14 +9479,14 @@ function sleep(ms) {
9296
9479
  function readLogTail(lines = 30) {
9297
9480
  const st = lstatSync(logfilePath(), { throwIfNoEntry: false });
9298
9481
  if (st === void 0 || st.isSymbolicLink()) return null;
9299
- const content = readFileSync16(logfilePath(), "utf-8");
9482
+ const content = readFileSync17(logfilePath(), "utf-8");
9300
9483
  const all = content.split("\n");
9301
9484
  if (all.at(-1) === "") all.pop();
9302
9485
  return all.slice(-lines);
9303
9486
  }
9304
9487
  function spawnDaemon(configEnv) {
9305
9488
  const entry = resolve2(process.argv[1] ?? "");
9306
- if (entry.length === 0 || !existsSync10(entry)) {
9489
+ if (entry.length === 0 || !existsSync11(entry)) {
9307
9490
  throw new Error(`\u65E0\u6CD5\u5B9A\u4F4D siming \u5165\u53E3\u811A\u672C\uFF08process.argv[1]=${process.argv[1] ?? "(\u7A7A)"}\uFF09`);
9308
9491
  }
9309
9492
  if (entry.endsWith(".ts")) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@siming-org/cli",
3
- "version": "0.8.2",
3
+ "version": "0.8.4",
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.2",
31
- "@siming-org/server": "0.8.2"
30
+ "@siming-org/server": "0.8.4",
31
+ "@siming-org/core": "0.8.4"
32
32
  },
33
33
  "devDependencies": {
34
34
  "tsup": "^8.3.5",