@siming-org/cli 0.8.1 → 0.8.3
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
|
@@ -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
|
|
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
|
|
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.
|
|
693
|
-
return na(`\
|
|
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"],
|
|
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
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
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],
|
|
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"],
|
|
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
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
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
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
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
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
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
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
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
|
|
873
|
-
|
|
874
|
-
ctx.
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
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
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
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
|
|
952
|
-
|
|
953
|
-
|
|
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
|
|
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
|
|
1001
|
-
|
|
1002
|
-
|
|
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
|
|
1010
|
-
|
|
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 ${
|
|
1014
|
-
|
|
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
|
-
|
|
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";
|
|
@@ -1038,17 +1142,21 @@ async function checkEvidenceFiles(ctx) {
|
|
|
1038
1142
|
if (files.length === 0) {
|
|
1039
1143
|
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
1144
|
}
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
}
|
|
1145
|
+
const guard = naIfRepoUnavailable(ctx);
|
|
1146
|
+
if (guard) return { ...guard, type };
|
|
1044
1147
|
const missing = [];
|
|
1148
|
+
const hits = [];
|
|
1045
1149
|
for (const rel of files) {
|
|
1046
|
-
|
|
1150
|
+
const hit = ctx.repos.find((repo) => ctx.fileExists(`${repo}/${rel}`));
|
|
1151
|
+
if (hit === void 0) missing.push(rel);
|
|
1152
|
+
else hits.push({ rel, repo: hit });
|
|
1047
1153
|
}
|
|
1048
1154
|
if (missing.length > 0) {
|
|
1049
|
-
return fail3(type, `\u8BC1\u636E\u6587\u4EF6\u4E0D\u5B58\u5728\
|
|
1155
|
+
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
|
|
1156
|
+
${ctx.reposScanDetail}`);
|
|
1050
1157
|
}
|
|
1051
|
-
return { type, status: "pass", detail: `\u8BC1\u636E\u6587\u4EF6 ${files.length} \u4E2A\u5747\u5B58\u5728
|
|
1158
|
+
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
|
|
1159
|
+
${ctx.reposScanDetail}` };
|
|
1052
1160
|
}
|
|
1053
1161
|
async function checkFinalConverged(ctx) {
|
|
1054
1162
|
const type = "record-final-converged";
|
|
@@ -1153,6 +1261,64 @@ function auditAiChecks(aiChecks, record) {
|
|
|
1153
1261
|
import { DEFAULT_VCS_DOC_PATHS } from "@siming-org/core";
|
|
1154
1262
|
import { execFile } from "child_process";
|
|
1155
1263
|
import { promisify } from "util";
|
|
1264
|
+
|
|
1265
|
+
// src/config/workspace-repos.ts
|
|
1266
|
+
import { existsSync as existsSync5, readdirSync, readFileSync as readFileSync5 } from "fs";
|
|
1267
|
+
import { join as join5 } from "path";
|
|
1268
|
+
var EXCLUDED_DIR_NAMES = /* @__PURE__ */ new Set(["temp", "node_modules", "dist", "build"]);
|
|
1269
|
+
var DEFAULT_SCAN_DEPTH = 1;
|
|
1270
|
+
var MAX_SCAN_DEPTH = 3;
|
|
1271
|
+
var WORKSPACE_DIR_NAME3 = ".siming";
|
|
1272
|
+
var DEV_JSON_FILE2 = "dev.json";
|
|
1273
|
+
function normalizeScanDepth(raw) {
|
|
1274
|
+
if (typeof raw !== "number" || !Number.isFinite(raw) || !Number.isInteger(raw)) {
|
|
1275
|
+
return DEFAULT_SCAN_DEPTH;
|
|
1276
|
+
}
|
|
1277
|
+
if (raw <= 0) return DEFAULT_SCAN_DEPTH;
|
|
1278
|
+
return Math.min(raw, MAX_SCAN_DEPTH);
|
|
1279
|
+
}
|
|
1280
|
+
function readScanDepth(cwd) {
|
|
1281
|
+
const path = join5(cwd, WORKSPACE_DIR_NAME3, DEV_JSON_FILE2);
|
|
1282
|
+
try {
|
|
1283
|
+
if (!existsSync5(path)) return DEFAULT_SCAN_DEPTH;
|
|
1284
|
+
const parsed = JSON.parse(readFileSync5(path, "utf-8"));
|
|
1285
|
+
return normalizeScanDepth(parsed.scanDepth);
|
|
1286
|
+
} catch {
|
|
1287
|
+
return DEFAULT_SCAN_DEPTH;
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
function isGitRepo(dir) {
|
|
1291
|
+
return existsSync5(join5(dir, ".git"));
|
|
1292
|
+
}
|
|
1293
|
+
function isExcludedDir(name) {
|
|
1294
|
+
return EXCLUDED_DIR_NAMES.has(name) || name.startsWith(".");
|
|
1295
|
+
}
|
|
1296
|
+
function scanWorkspaceRepos(cwd, scanDepthOverride) {
|
|
1297
|
+
const scanDepth = scanDepthOverride !== void 0 ? normalizeScanDepth(scanDepthOverride) : readScanDepth(cwd);
|
|
1298
|
+
const repos = [];
|
|
1299
|
+
let scannedDirs = 0;
|
|
1300
|
+
const queue = [{ dir: cwd, depth: 0 }];
|
|
1301
|
+
while (queue.length > 0) {
|
|
1302
|
+
const { dir, depth } = queue.shift();
|
|
1303
|
+
if (isGitRepo(dir)) repos.push(dir);
|
|
1304
|
+
if (depth >= scanDepth) continue;
|
|
1305
|
+
let entries;
|
|
1306
|
+
try {
|
|
1307
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
1308
|
+
} catch {
|
|
1309
|
+
continue;
|
|
1310
|
+
}
|
|
1311
|
+
for (const entry of entries) {
|
|
1312
|
+
if (!entry.isDirectory()) continue;
|
|
1313
|
+
scannedDirs++;
|
|
1314
|
+
if (isExcludedDir(entry.name)) continue;
|
|
1315
|
+
queue.push({ dir: join5(dir, entry.name), depth: depth + 1 });
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
return { repos, scannedDirs, scanDepth };
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
// src/client/checks/param-resolver.ts
|
|
1156
1322
|
var execFileAsync = promisify(execFile);
|
|
1157
1323
|
var defaultGitRunner = async (args, cwd) => {
|
|
1158
1324
|
try {
|
|
@@ -1163,35 +1329,22 @@ var defaultGitRunner = async (args, cwd) => {
|
|
|
1163
1329
|
return { ok: false, stdout: e.stdout ?? "", stderr: e.stderr ?? e.message ?? String(err2) };
|
|
1164
1330
|
}
|
|
1165
1331
|
};
|
|
1166
|
-
async function resolveCheckContextWithRunner(base, vcs, cwd,
|
|
1167
|
-
const
|
|
1332
|
+
async function resolveCheckContextWithRunner(base, vcs, cwd, scan) {
|
|
1333
|
+
const result = scan !== void 0 ? scan(cwd) : scanWorkspaceRepos(cwd);
|
|
1168
1334
|
const alignRecord = base.nodeRecords["ALIGN"];
|
|
1169
1335
|
const baseBranch = (alignRecord?.baseBranch !== void 0 && alignRecord.baseBranch !== "" ? alignRecord.baseBranch : void 0) ?? vcs.baseBranch ?? null;
|
|
1170
1336
|
return {
|
|
1171
1337
|
...base,
|
|
1172
|
-
|
|
1173
|
-
|
|
1338
|
+
repos: result.repos,
|
|
1339
|
+
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
1340
|
baseBranch,
|
|
1175
1341
|
branchPattern: vcs.branchPattern ?? "feature/",
|
|
1176
1342
|
docPaths: vcs.docPaths ?? [...DEFAULT_VCS_DOC_PATHS]
|
|
1177
1343
|
};
|
|
1178
1344
|
}
|
|
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
1345
|
|
|
1193
1346
|
// src/client/checks/runner.ts
|
|
1194
|
-
import { existsSync as
|
|
1347
|
+
import { existsSync as existsSync6 } from "fs";
|
|
1195
1348
|
function gateHasFailure(report) {
|
|
1196
1349
|
return report.toolOutcomes.some((o) => o.status === "fail") || report.aiOutcomes.some((o) => o.status === "fail");
|
|
1197
1350
|
}
|
|
@@ -1243,11 +1396,10 @@ async function runNodeGate(client, taskId) {
|
|
|
1243
1396
|
ids.delete("");
|
|
1244
1397
|
return { ok: true, ids };
|
|
1245
1398
|
},
|
|
1246
|
-
fileExists: (p) =>
|
|
1399
|
+
fileExists: (p) => existsSync6(p)
|
|
1247
1400
|
},
|
|
1248
1401
|
vcs,
|
|
1249
|
-
process.cwd()
|
|
1250
|
-
defaultGitRunner
|
|
1402
|
+
process.cwd()
|
|
1251
1403
|
);
|
|
1252
1404
|
const toolOutcomes = [];
|
|
1253
1405
|
for (const toolCheck of toolChecks) {
|
|
@@ -1576,7 +1728,7 @@ async function resolveArtifactBatchEntries(entries) {
|
|
|
1576
1728
|
let content = inlineContent;
|
|
1577
1729
|
if (filePath !== void 0) {
|
|
1578
1730
|
try {
|
|
1579
|
-
content =
|
|
1731
|
+
content = readFileSync6(filePath, "utf-8");
|
|
1580
1732
|
} catch (e) {
|
|
1581
1733
|
localFailures.push({ index, message: `\u6587\u4EF6\u8BFB\u53D6\u5931\u8D25: ${filePath}\uFF08${e instanceof Error ? e.message : String(e)}\uFF09` });
|
|
1582
1734
|
continue;
|
|
@@ -1662,7 +1814,7 @@ async function handleArchNoteAddBatch(client, taskId, texts) {
|
|
|
1662
1814
|
}
|
|
1663
1815
|
|
|
1664
1816
|
// src/client/handlers/dag.ts
|
|
1665
|
-
import { readFileSync as
|
|
1817
|
+
import { readFileSync as readFileSync7 } from "fs";
|
|
1666
1818
|
import { parse as parseYaml } from "yaml";
|
|
1667
1819
|
import {
|
|
1668
1820
|
BIZ_CODE_MESSAGES,
|
|
@@ -1884,13 +2036,13 @@ async function handleUpgradeApply(client, templateId, decisions) {
|
|
|
1884
2036
|
|
|
1885
2037
|
// src/client/handlers/auth.ts
|
|
1886
2038
|
import {
|
|
1887
|
-
existsSync as
|
|
1888
|
-
readFileSync as
|
|
2039
|
+
existsSync as existsSync7,
|
|
2040
|
+
readFileSync as readFileSync8,
|
|
1889
2041
|
writeFileSync as writeFileSync4,
|
|
1890
2042
|
renameSync as renameSync3,
|
|
1891
2043
|
mkdirSync as mkdirSync4
|
|
1892
2044
|
} from "fs";
|
|
1893
|
-
import { join as
|
|
2045
|
+
import { join as join6 } from "path";
|
|
1894
2046
|
import { isAbsolute as isAbsolute2 } from "path";
|
|
1895
2047
|
async function handleWhoami(client) {
|
|
1896
2048
|
const res = await client.getJson("/api/auth/whoami");
|
|
@@ -1973,12 +2125,12 @@ function writeWorkspaceLayer(token, kind, opts) {
|
|
|
1973
2125
|
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
2126
|
});
|
|
1975
2127
|
}
|
|
1976
|
-
const devJsonPath =
|
|
2128
|
+
const devJsonPath = join6(dir, ".siming", "dev.json");
|
|
1977
2129
|
let config = {};
|
|
1978
2130
|
let hadIsolationKeys = false;
|
|
1979
|
-
if (
|
|
2131
|
+
if (existsSync7(devJsonPath)) {
|
|
1980
2132
|
try {
|
|
1981
|
-
config = JSON.parse(
|
|
2133
|
+
config = JSON.parse(readFileSync8(devJsonPath, "utf-8"));
|
|
1982
2134
|
hadIsolationKeys = "serverPort" in config || "dbPrefix" in config;
|
|
1983
2135
|
} catch {
|
|
1984
2136
|
return fail({
|
|
@@ -1997,7 +2149,7 @@ function writeWorkspaceLayer(token, kind, opts) {
|
|
|
1997
2149
|
});
|
|
1998
2150
|
}
|
|
1999
2151
|
config.authToken = token;
|
|
2000
|
-
mkdirSync4(
|
|
2152
|
+
mkdirSync4(join6(dir, ".siming"), { recursive: true });
|
|
2001
2153
|
const tmp = `${devJsonPath}.tmp`;
|
|
2002
2154
|
writeFileSync4(tmp, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
2003
2155
|
renameSync3(tmp, devJsonPath);
|
|
@@ -2739,7 +2891,7 @@ function createMcpServer() {
|
|
|
2739
2891
|
let fullText = content;
|
|
2740
2892
|
if (file) {
|
|
2741
2893
|
try {
|
|
2742
|
-
fullText =
|
|
2894
|
+
fullText = readFileSync9(file, "utf-8");
|
|
2743
2895
|
} catch (e) {
|
|
2744
2896
|
return localError(`\u6587\u4EF6\u8BFB\u53D6\u5931\u8D25: ${file}\uFF08${e instanceof Error ? e.message : String(e)}\uFF09`);
|
|
2745
2897
|
}
|
|
@@ -2978,7 +3130,7 @@ async function mcpServeCommand() {
|
|
|
2978
3130
|
|
|
2979
3131
|
// src/commands/task/command.ts
|
|
2980
3132
|
import { Command as Command2 } from "commander";
|
|
2981
|
-
import { readFileSync as
|
|
3133
|
+
import { readFileSync as readFileSync11 } from "fs";
|
|
2982
3134
|
import { z as z5 } from "zod";
|
|
2983
3135
|
import {
|
|
2984
3136
|
ARTIFACT_TYPES as ARTIFACT_TYPES3,
|
|
@@ -3092,7 +3244,7 @@ function renderResult(format, result, opts) {
|
|
|
3092
3244
|
}
|
|
3093
3245
|
|
|
3094
3246
|
// src/commands/opts.ts
|
|
3095
|
-
import { readFileSync as
|
|
3247
|
+
import { readFileSync as readFileSync10 } from "fs";
|
|
3096
3248
|
import "commander";
|
|
3097
3249
|
import { z as z4 } from "zod";
|
|
3098
3250
|
import { canonicalizeReferencePath, createReferencesSchema } from "@siming-org/core";
|
|
@@ -3147,7 +3299,7 @@ function parseRefFlags(refs, mainDocName) {
|
|
|
3147
3299
|
seen.add(canonicalizeReferencePath(relPath));
|
|
3148
3300
|
let content;
|
|
3149
3301
|
try {
|
|
3150
|
-
content =
|
|
3302
|
+
content = readFileSync10(localPath, "utf-8");
|
|
3151
3303
|
} catch (e) {
|
|
3152
3304
|
return fail({
|
|
3153
3305
|
message: `--ref \u672C\u5730\u6587\u4EF6\u4E0D\u53EF\u8BFB\uFF1A"${localPath}"`,
|
|
@@ -3641,7 +3793,7 @@ function createTaskCommand() {
|
|
|
3641
3793
|
let content;
|
|
3642
3794
|
if (opts.file) {
|
|
3643
3795
|
try {
|
|
3644
|
-
content =
|
|
3796
|
+
content = readFileSync11(opts.file, "utf-8");
|
|
3645
3797
|
} catch (e) {
|
|
3646
3798
|
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
3799
|
return;
|
|
@@ -3896,18 +4048,18 @@ import { Command as Command3 } from "commander";
|
|
|
3896
4048
|
import { SKILL_MAIN_DOC, SkillScopeSchema } from "@siming-org/core";
|
|
3897
4049
|
|
|
3898
4050
|
// src/client/scaffold-templates.ts
|
|
3899
|
-
import { existsSync as
|
|
3900
|
-
import { dirname as dirname3, join as
|
|
4051
|
+
import { existsSync as existsSync8, readdirSync as readdirSync2, readFileSync as readFileSync12 } from "fs";
|
|
4052
|
+
import { dirname as dirname3, join as join7 } from "path";
|
|
3901
4053
|
import { fileURLToPath } from "url";
|
|
3902
|
-
var SCAFFOLD_DIR =
|
|
4054
|
+
var SCAFFOLD_DIR = join7("templates", "project-skills");
|
|
3903
4055
|
var KEBAB_CASE = /^[a-z0-9]+(-[a-z0-9]+)*$/;
|
|
3904
4056
|
function resolveCliPackageRoot() {
|
|
3905
4057
|
let dir = dirname3(fileURLToPath(import.meta.url));
|
|
3906
4058
|
for (let depth = 0; depth < 10; depth += 1) {
|
|
3907
|
-
const pkgFile =
|
|
3908
|
-
if (
|
|
4059
|
+
const pkgFile = join7(dir, "package.json");
|
|
4060
|
+
if (existsSync8(pkgFile)) {
|
|
3909
4061
|
try {
|
|
3910
|
-
const pkg = JSON.parse(
|
|
4062
|
+
const pkg = JSON.parse(readFileSync12(pkgFile, "utf-8"));
|
|
3911
4063
|
if (pkg.name === "@siming-org/cli") return ok2(dir);
|
|
3912
4064
|
} catch {
|
|
3913
4065
|
}
|
|
@@ -3925,10 +4077,10 @@ function resolveCliPackageRoot() {
|
|
|
3925
4077
|
function listScaffoldTemplates() {
|
|
3926
4078
|
const root = resolveCliPackageRoot();
|
|
3927
4079
|
if (!root.success) return root;
|
|
3928
|
-
const dir =
|
|
4080
|
+
const dir = join7(root.data, SCAFFOLD_DIR);
|
|
3929
4081
|
let entries;
|
|
3930
4082
|
try {
|
|
3931
|
-
entries =
|
|
4083
|
+
entries = readdirSync2(dir);
|
|
3932
4084
|
} catch {
|
|
3933
4085
|
return fail({
|
|
3934
4086
|
message: `\u9AA8\u67B6\u6A21\u677F\u76EE\u5F55\u7F3A\u5931\uFF1A${SCAFFOLD_DIR}`,
|
|
@@ -3987,7 +4139,7 @@ function loadScaffoldTemplate(name) {
|
|
|
3987
4139
|
if (!root.success) return root;
|
|
3988
4140
|
let text;
|
|
3989
4141
|
try {
|
|
3990
|
-
text =
|
|
4142
|
+
text = readFileSync12(join7(root.data, SCAFFOLD_DIR, `${name}.md`), "utf-8");
|
|
3991
4143
|
} catch (e) {
|
|
3992
4144
|
return fail({
|
|
3993
4145
|
message: `\u9AA8\u67B6\u6587\u4EF6\u4E0D\u53EF\u8BFB\uFF1A${SCAFFOLD_DIR}/${name}.md`,
|
|
@@ -4809,7 +4961,7 @@ function agentFields(a) {
|
|
|
4809
4961
|
}
|
|
4810
4962
|
|
|
4811
4963
|
// src/commands/dag/command.ts
|
|
4812
|
-
import { readFileSync as
|
|
4964
|
+
import { readFileSync as readFileSync13 } from "fs";
|
|
4813
4965
|
import { Command as Command5 } from "commander";
|
|
4814
4966
|
function createDagCommand() {
|
|
4815
4967
|
const dag = new Command5("dag").description("DAG template & instance management");
|
|
@@ -4867,7 +5019,7 @@ function createDagCommand() {
|
|
|
4867
5019
|
const client = createClient(opts.url);
|
|
4868
5020
|
let text;
|
|
4869
5021
|
try {
|
|
4870
|
-
text =
|
|
5022
|
+
text = readFileSync13(file, "utf-8");
|
|
4871
5023
|
} catch (e) {
|
|
4872
5024
|
renderResult("json", fail({
|
|
4873
5025
|
message: `\u6587\u4EF6\u8BFB\u53D6\u5931\u8D25: ${file}\uFF08${e instanceof Error ? e.message : String(e)}\uFF09`,
|
|
@@ -5213,7 +5365,7 @@ function diffSummary(item) {
|
|
|
5213
5365
|
}
|
|
5214
5366
|
|
|
5215
5367
|
// src/commands/node/command.ts
|
|
5216
|
-
import { readFileSync as
|
|
5368
|
+
import { readFileSync as readFileSync14 } from "fs";
|
|
5217
5369
|
import { Command as Command6 } from "commander";
|
|
5218
5370
|
import { SkillScopeSchema as SkillScopeSchema2 } from "@siming-org/core";
|
|
5219
5371
|
|
|
@@ -5451,7 +5603,7 @@ function createNodeCommand() {
|
|
|
5451
5603
|
let prompt = opts.prompt ?? "";
|
|
5452
5604
|
if (opts.promptFile !== void 0) {
|
|
5453
5605
|
try {
|
|
5454
|
-
prompt =
|
|
5606
|
+
prompt = readFileSync14(opts.promptFile, "utf-8");
|
|
5455
5607
|
} catch (e) {
|
|
5456
5608
|
renderResult("json", fail({
|
|
5457
5609
|
message: `prompt \u6587\u4EF6\u8BFB\u53D6\u5931\u8D25: ${opts.promptFile}\uFF08${e instanceof Error ? e.message : String(e)}\uFF09`,
|
|
@@ -5496,7 +5648,7 @@ function createNodeCommand() {
|
|
|
5496
5648
|
let prompt;
|
|
5497
5649
|
if (opts.promptFile !== void 0) {
|
|
5498
5650
|
try {
|
|
5499
|
-
prompt =
|
|
5651
|
+
prompt = readFileSync14(opts.promptFile, "utf-8");
|
|
5500
5652
|
} catch (e) {
|
|
5501
5653
|
renderResult("json", fail({
|
|
5502
5654
|
message: `prompt \u6587\u4EF6\u8BFB\u53D6\u5931\u8D25: ${opts.promptFile}\uFF08${e instanceof Error ? e.message : String(e)}\uFF09`,
|
|
@@ -5511,7 +5663,7 @@ function createNodeCommand() {
|
|
|
5511
5663
|
if (opts.checksFile !== void 0) {
|
|
5512
5664
|
let parsed;
|
|
5513
5665
|
try {
|
|
5514
|
-
parsed = JSON.parse(
|
|
5666
|
+
parsed = JSON.parse(readFileSync14(opts.checksFile, "utf-8"));
|
|
5515
5667
|
} catch (e) {
|
|
5516
5668
|
renderResult("json", fail({
|
|
5517
5669
|
message: `checks \u6587\u4EF6\u8BFB\u53D6/\u89E3\u6790\u5931\u8D25: ${opts.checksFile}\uFF08${e instanceof Error ? e.message : String(e)}\uFF09`,
|
|
@@ -5619,7 +5771,7 @@ function nodeFields2(n) {
|
|
|
5619
5771
|
import { execFile as execFile2 } from "child_process";
|
|
5620
5772
|
import { mkdtempSync, rmSync as rmSync2 } from "fs";
|
|
5621
5773
|
import { tmpdir } from "os";
|
|
5622
|
-
import { join as
|
|
5774
|
+
import { join as join8 } from "path";
|
|
5623
5775
|
import { promisify as promisify2 } from "util";
|
|
5624
5776
|
import { createInterface } from "readline/promises";
|
|
5625
5777
|
import { Command as Command7 } from "commander";
|
|
@@ -6061,7 +6213,7 @@ ${conflicts.map((item) => ` ${item.kind}:${item.key} \u2014 ${item.reason ?? "\
|
|
|
6061
6213
|
async function fetchManifest(pkgSpec, registry) {
|
|
6062
6214
|
let dir;
|
|
6063
6215
|
try {
|
|
6064
|
-
dir = mkdtempSync(
|
|
6216
|
+
dir = mkdtempSync(join8(tmpdir(), "siming-flow-"));
|
|
6065
6217
|
} catch (error) {
|
|
6066
6218
|
return fail({
|
|
6067
6219
|
message: `\u4E34\u65F6\u76EE\u5F55\u521B\u5EFA\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`,
|
|
@@ -6098,7 +6250,7 @@ async function fetchManifest(pkgSpec, registry) {
|
|
|
6098
6250
|
}
|
|
6099
6251
|
const { stdout: manifestText } = await execFileAsync2(
|
|
6100
6252
|
"tar",
|
|
6101
|
-
["-xOf",
|
|
6253
|
+
["-xOf", join8(dir, filename), "package/siming-nodes.json"],
|
|
6102
6254
|
{ maxBuffer: MANIFEST_LIMITS.maxChars * 2 + 64 * 1024 }
|
|
6103
6255
|
);
|
|
6104
6256
|
const parsed = parseFlowManifest(manifestText);
|
|
@@ -6969,7 +7121,7 @@ function createProjectCommand() {
|
|
|
6969
7121
|
const result = await handleGetProject(client, id);
|
|
6970
7122
|
renderResult(opts.format, result, { fields: result.success ? projectFields(result.data) : [] });
|
|
6971
7123
|
});
|
|
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>", "
|
|
7124
|
+
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
7125
|
const client = createClient(opts.url);
|
|
6974
7126
|
const parseBool = (v, flag) => {
|
|
6975
7127
|
if (v === void 0) return void 0;
|
|
@@ -6993,6 +7145,7 @@ function createProjectCommand() {
|
|
|
6993
7145
|
vcsProvided = true;
|
|
6994
7146
|
}
|
|
6995
7147
|
if (opts.vcsRepoPath !== void 0) {
|
|
7148
|
+
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
7149
|
vcsFields.repoPath = opts.vcsRepoPath;
|
|
6997
7150
|
vcsProvided = true;
|
|
6998
7151
|
}
|
|
@@ -7201,7 +7354,7 @@ function createConfigCommand() {
|
|
|
7201
7354
|
|
|
7202
7355
|
// src/commands/export/command.ts
|
|
7203
7356
|
import { Command as Command11 } from "commander";
|
|
7204
|
-
import { readFileSync as
|
|
7357
|
+
import { readFileSync as readFileSync15 } from "fs";
|
|
7205
7358
|
import { parse as parseYaml2 } from "yaml";
|
|
7206
7359
|
|
|
7207
7360
|
// src/client/handlers/export.ts
|
|
@@ -7872,7 +8025,7 @@ function createExportCommand() {
|
|
|
7872
8025
|
async function runExportPlan(client, filePath, typesArg) {
|
|
7873
8026
|
let raw;
|
|
7874
8027
|
try {
|
|
7875
|
-
const text =
|
|
8028
|
+
const text = readFileSync15(filePath, "utf-8");
|
|
7876
8029
|
raw = parseYaml2(text);
|
|
7877
8030
|
} catch (e) {
|
|
7878
8031
|
return fail({
|
|
@@ -7897,7 +8050,7 @@ async function runExportPlan(client, filePath, typesArg) {
|
|
|
7897
8050
|
}
|
|
7898
8051
|
function loadPlanFile(path) {
|
|
7899
8052
|
try {
|
|
7900
|
-
const text =
|
|
8053
|
+
const text = readFileSync15(path, "utf-8");
|
|
7901
8054
|
const parsed = JSON.parse(text);
|
|
7902
8055
|
if (!Array.isArray(parsed.items)) {
|
|
7903
8056
|
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 +8113,14 @@ function renderReport(report, format) {
|
|
|
7960
8113
|
|
|
7961
8114
|
// src/commands/install/command.ts
|
|
7962
8115
|
import { Command as Command12 } from "commander";
|
|
7963
|
-
import { existsSync as
|
|
8116
|
+
import { existsSync as existsSync10 } from "fs";
|
|
7964
8117
|
import { createInterface as createInterface2 } from "readline/promises";
|
|
7965
|
-
import { dirname as dirname5, join as
|
|
8118
|
+
import { dirname as dirname5, join as join10 } from "path";
|
|
7966
8119
|
import { AGENT_MAIN_DOC as AGENT_MAIN_DOC5, SKILL_MAIN_DOC as SKILL_MAIN_DOC5, VERSION as VERSION3 } from "@siming-org/core";
|
|
7967
8120
|
|
|
7968
8121
|
// src/commands/install/writer.ts
|
|
7969
|
-
import { existsSync as
|
|
7970
|
-
import { dirname as dirname4, join as
|
|
8122
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync5, readFileSync as readFileSync16, renameSync as renameSync4, rmSync as rmSync3, writeFileSync as writeFileSync5 } from "fs";
|
|
8123
|
+
import { dirname as dirname4, join as join9 } from "path";
|
|
7971
8124
|
import { homedir as homedir4 } from "os";
|
|
7972
8125
|
import { parse as parseYaml3, stringify as stringifyYaml } from "yaml";
|
|
7973
8126
|
import {
|
|
@@ -7978,12 +8131,12 @@ import {
|
|
|
7978
8131
|
} from "@siming-org/core";
|
|
7979
8132
|
function agentsHomeDir() {
|
|
7980
8133
|
const env = process.env.SIMING_AGENTS_HOME;
|
|
7981
|
-
return env && env.length > 0 ? env :
|
|
8134
|
+
return env && env.length > 0 ? env : join9(homedir4(), ".agents");
|
|
7982
8135
|
}
|
|
7983
8136
|
function resolveInstallTargets(scope, workspaceDir) {
|
|
7984
8137
|
if (scope === "global") {
|
|
7985
8138
|
const dir = agentsHomeDir();
|
|
7986
|
-
return { targets: { dir, mcpConfigPath:
|
|
8139
|
+
return { targets: { dir, mcpConfigPath: join9(dir, "mcp.json") } };
|
|
7987
8140
|
}
|
|
7988
8141
|
const wd = workspaceDir ?? findWorkspaceDir();
|
|
7989
8142
|
if (!wd) {
|
|
@@ -7991,7 +8144,7 @@ function resolveInstallTargets(scope, workspaceDir) {
|
|
|
7991
8144
|
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
8145
|
};
|
|
7993
8146
|
}
|
|
7994
|
-
return { targets: { dir:
|
|
8147
|
+
return { targets: { dir: join9(wd, ".agents"), mcpConfigPath: null } };
|
|
7995
8148
|
}
|
|
7996
8149
|
function isSafeAssetName(name) {
|
|
7997
8150
|
if (name.length === 0 || name === "." || name === "..") return false;
|
|
@@ -8011,7 +8164,7 @@ function validateReferencesLocally(mainDocName, references) {
|
|
|
8011
8164
|
function writeAssetDirectory(assetDir, files) {
|
|
8012
8165
|
rmSync3(assetDir, { recursive: true, force: true });
|
|
8013
8166
|
for (const file of files) {
|
|
8014
|
-
const target =
|
|
8167
|
+
const target = join9(assetDir, ...file.relPath.split("/"));
|
|
8015
8168
|
mkdirSync5(dirname4(target), { recursive: true });
|
|
8016
8169
|
writeFileSync5(target, file.content, "utf-8");
|
|
8017
8170
|
}
|
|
@@ -8028,7 +8181,7 @@ ${skill.content}
|
|
|
8028
8181
|
`;
|
|
8029
8182
|
}
|
|
8030
8183
|
function skillTargetPath(dir, skill) {
|
|
8031
|
-
return
|
|
8184
|
+
return join9(dir, "skills", skill.name, "SKILL.md");
|
|
8032
8185
|
}
|
|
8033
8186
|
function permissionsToMatrix(permissions) {
|
|
8034
8187
|
const matrix = {};
|
|
@@ -8064,13 +8217,13 @@ ${agent.systemPrompt}
|
|
|
8064
8217
|
`;
|
|
8065
8218
|
}
|
|
8066
8219
|
function agentTargetPath(dir, agent) {
|
|
8067
|
-
return
|
|
8220
|
+
return join9(dir, "agents", agent.name, "agent.md");
|
|
8068
8221
|
}
|
|
8069
8222
|
function readSimingVersion(path) {
|
|
8070
|
-
if (!
|
|
8223
|
+
if (!existsSync9(path)) return null;
|
|
8071
8224
|
let text;
|
|
8072
8225
|
try {
|
|
8073
|
-
text =
|
|
8226
|
+
text = readFileSync16(path, "utf-8");
|
|
8074
8227
|
} catch {
|
|
8075
8228
|
return null;
|
|
8076
8229
|
}
|
|
@@ -8092,10 +8245,10 @@ function isPlainObject(v) {
|
|
|
8092
8245
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
8093
8246
|
}
|
|
8094
8247
|
function readMcpConfig(path) {
|
|
8095
|
-
if (!
|
|
8248
|
+
if (!existsSync9(path)) return { state: "absent" };
|
|
8096
8249
|
let text;
|
|
8097
8250
|
try {
|
|
8098
|
-
text =
|
|
8251
|
+
text = readFileSync16(path, "utf-8");
|
|
8099
8252
|
} catch (e) {
|
|
8100
8253
|
return { state: "corrupt", error: `\u8BFB\u53D6\u5931\u8D25: ${e instanceof Error ? e.message : String(e)}` };
|
|
8101
8254
|
}
|
|
@@ -8332,7 +8485,7 @@ function compareSkill(s, dir) {
|
|
|
8332
8485
|
if (!isSafeAssetName(s.name)) {
|
|
8333
8486
|
return { ...base, action: "conflict", reason: `unsafe asset name "${s.name}"` };
|
|
8334
8487
|
}
|
|
8335
|
-
if (!
|
|
8488
|
+
if (!existsSync10(path)) return { ...base, action: "install", reason: "not installed locally" };
|
|
8336
8489
|
const marked = readSimingVersion(path);
|
|
8337
8490
|
if (marked === null) {
|
|
8338
8491
|
return { ...base, localVersion: "unknown", action: "conflict", reason: "no siming-version marker (third-party asset; use --force to overwrite)" };
|
|
@@ -8350,7 +8503,7 @@ function compareAgent(a, dir) {
|
|
|
8350
8503
|
if (!isSafeAssetName(a.name)) {
|
|
8351
8504
|
return { ...base, action: "conflict", reason: `unsafe asset name "${a.name}"` };
|
|
8352
8505
|
}
|
|
8353
|
-
if (!
|
|
8506
|
+
if (!existsSync10(path)) return { ...base, action: "install", reason: "not installed locally" };
|
|
8354
8507
|
const marked = readSimingVersion(path);
|
|
8355
8508
|
if (marked === null) {
|
|
8356
8509
|
return { ...base, localVersion: "unknown", action: "conflict", reason: "no siming-version marker (third-party asset; use --force to overwrite)" };
|
|
@@ -8443,7 +8596,7 @@ async function applyInstall(client, scope, projectId, items, opts) {
|
|
|
8443
8596
|
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
8597
|
continue;
|
|
8445
8598
|
}
|
|
8446
|
-
const targetExists =
|
|
8599
|
+
const targetExists = existsSync10(targetPath);
|
|
8447
8600
|
writeAssetDirectory(dirname5(targetPath), [
|
|
8448
8601
|
{ relPath: SKILL_MAIN_DOC5, content: skillToMarkdown(r.data) },
|
|
8449
8602
|
...(r.data.references ?? []).map((ref) => ({ relPath: ref.path, content: ref.content }))
|
|
@@ -8479,7 +8632,7 @@ async function applyInstall(client, scope, projectId, items, opts) {
|
|
|
8479
8632
|
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
8633
|
continue;
|
|
8481
8634
|
}
|
|
8482
|
-
const targetExists =
|
|
8635
|
+
const targetExists = existsSync10(targetPath);
|
|
8483
8636
|
writeAssetDirectory(dirname5(targetPath), [
|
|
8484
8637
|
{ relPath: AGENT_MAIN_DOC5, content: agentToMarkdown(r.data, realModel) },
|
|
8485
8638
|
...(r.data.references ?? []).map((ref) => ({ relPath: ref.path, content: ref.content }))
|
|
@@ -8503,8 +8656,8 @@ function buildInstallGuidance(scope, targets) {
|
|
|
8503
8656
|
const lines = [];
|
|
8504
8657
|
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
8658
|
lines.push(`[1] \u8D44\u4EA7\u4F4D\u7F6E\uFF08${scope === "global" ? "\u7528\u6237\u7EA7" : "\u9879\u76EE\u7EA7"} ${targets.dir}\uFF09\uFF1A`);
|
|
8506
|
-
lines.push(` - skills: ${
|
|
8507
|
-
lines.push(` - agents: ${
|
|
8659
|
+
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`);
|
|
8660
|
+
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
8661
|
if (targets.mcpConfigPath) {
|
|
8509
8662
|
lines.push(` - MCP \u6CE8\u518C: ${targets.mcpConfigPath}\uFF08\u9876\u5C42 mcpServers.siming \u2192 stdio \u547D\u4EE4 "siming mcp-serve"\uFF09`);
|
|
8510
8663
|
}
|
|
@@ -8890,7 +9043,8 @@ ${ROADMAP_TEXT}
|
|
|
8890
9043
|
|
|
8891
9044
|
\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
9045
|
\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
|
|
9046
|
+
\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
|
|
9047
|
+
\u7B2C 9 \u9879\u4E3A\u884C\u4E3A\u89C4\u5219\u91CD\u63D0\u793A\uFF08\u89C1\u8868\u683C\u540E\u8BF4\u660E\uFF09\uFF1A
|
|
8894
9048
|
|
|
8895
9049
|
| # | \u58F0\u660E\u9879 | \u58F0\u660E\u5185\u5BB9 | \u7F3A\u5931\u540E\u679C |
|
|
8896
9050
|
|---|--------|----------|----------|
|
|
@@ -8902,6 +9056,10 @@ ${ROADMAP_TEXT}
|
|
|
8902
9056
|
| 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
9057
|
| 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
9058
|
| 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 |
|
|
9059
|
+
| 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 |
|
|
9060
|
+
|
|
9061
|
+
\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
|
|
9062
|
+
\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
9063
|
|
|
8906
9064
|
----------------------------------------------------------------
|
|
8907
9065
|
\u4E8C\u3001\u6D41\u7A0B\u6A21\u677F\u83B7\u53D6\u6307\u5F15
|
|
@@ -9038,7 +9196,7 @@ async function handleUpdateEnums(client, category, body) {
|
|
|
9038
9196
|
// src/commands/settings/command.ts
|
|
9039
9197
|
function createSettingsCommand() {
|
|
9040
9198
|
const settings = new Command16("settings").description("Settings (enum registries)");
|
|
9041
|
-
withCommonOpts(settings.command("enums [category]"), "fancy").description("Show enum registry (all
|
|
9199
|
+
withCommonOpts(settings.command("enums [category]"), "fancy").description("Show enum registry (all categories, or one category)").action(async (category, opts) => {
|
|
9042
9200
|
const client = createClient(opts.url);
|
|
9043
9201
|
const catR = category ? EnumRegistryCategorySchema.safeParse(category) : null;
|
|
9044
9202
|
if (category && !catR?.success) {
|
|
@@ -9092,8 +9250,8 @@ import { VERSION as VERSION4, SIMING_CONFIG_KEYS as SIMING_CONFIG_KEYS2 } from "
|
|
|
9092
9250
|
|
|
9093
9251
|
// src/commands/server/daemon.ts
|
|
9094
9252
|
import { execFileSync } from "child_process";
|
|
9095
|
-
import { closeSync, existsSync as
|
|
9096
|
-
import { join as
|
|
9253
|
+
import { closeSync, existsSync as existsSync11, lstatSync, mkdirSync as mkdirSync6, openSync, readFileSync as readFileSync17, renameSync as renameSync5, rmSync as rmSync4, writeFileSync as writeFileSync6 } from "fs";
|
|
9254
|
+
import { join as join11, resolve as resolve2 } from "path";
|
|
9097
9255
|
import { spawn } from "child_process";
|
|
9098
9256
|
|
|
9099
9257
|
// src/commands/server/probe.ts
|
|
@@ -9110,10 +9268,10 @@ function runtimeDir() {
|
|
|
9110
9268
|
return process.env.SIMING_RUNTIME_DIR ?? "/tmp/siming";
|
|
9111
9269
|
}
|
|
9112
9270
|
function pidfilePath() {
|
|
9113
|
-
return
|
|
9271
|
+
return join11(runtimeDir(), "server.pid");
|
|
9114
9272
|
}
|
|
9115
9273
|
function logfilePath() {
|
|
9116
|
-
return
|
|
9274
|
+
return join11(runtimeDir(), "server.log");
|
|
9117
9275
|
}
|
|
9118
9276
|
var READY_TIMEOUT_MS = 2e4;
|
|
9119
9277
|
var STOP_GRACE_MS = 1e4;
|
|
@@ -9146,7 +9304,7 @@ function readPidFile() {
|
|
|
9146
9304
|
try {
|
|
9147
9305
|
const st = lstatSync(pidfilePath(), { throwIfNoEntry: false });
|
|
9148
9306
|
if (st === void 0 || st.isSymbolicLink()) return null;
|
|
9149
|
-
const parsed = JSON.parse(
|
|
9307
|
+
const parsed = JSON.parse(readFileSync17(pidfilePath(), "utf-8").trim());
|
|
9150
9308
|
if (typeof parsed.pid !== "number" || typeof parsed.startedAt !== "number" || typeof parsed.port !== "number") {
|
|
9151
9309
|
return null;
|
|
9152
9310
|
}
|
|
@@ -9187,7 +9345,7 @@ function removePidFile(expectedPid) {
|
|
|
9187
9345
|
}
|
|
9188
9346
|
function readCmdline(pid) {
|
|
9189
9347
|
try {
|
|
9190
|
-
const raw =
|
|
9348
|
+
const raw = readFileSync17(`/proc/${pid}/cmdline`);
|
|
9191
9349
|
const joined = raw.toString().split("\0").filter((s) => s.length > 0).join(" ");
|
|
9192
9350
|
if (joined.length > 0) return joined;
|
|
9193
9351
|
} catch {
|
|
@@ -9216,7 +9374,7 @@ function isSimingDaemonCmdline(cmdline, expectedEntry) {
|
|
|
9216
9374
|
}
|
|
9217
9375
|
function readProcessStartMs(pid) {
|
|
9218
9376
|
try {
|
|
9219
|
-
const stat =
|
|
9377
|
+
const stat = readFileSync17(`/proc/${pid}/stat`, "utf-8");
|
|
9220
9378
|
const rest = stat.slice(stat.lastIndexOf(")") + 2);
|
|
9221
9379
|
const fields = rest.split(" ");
|
|
9222
9380
|
const starttimeJiffies = Number(fields[19]);
|
|
@@ -9245,7 +9403,7 @@ function readProcessStartMs(pid) {
|
|
|
9245
9403
|
}
|
|
9246
9404
|
function readBtimeFromProcStat() {
|
|
9247
9405
|
try {
|
|
9248
|
-
const stat =
|
|
9406
|
+
const stat = readFileSync17("/proc/stat", "utf-8");
|
|
9249
9407
|
for (const line of stat.split("\n")) {
|
|
9250
9408
|
if (line.startsWith("btime ")) {
|
|
9251
9409
|
const v = Number(line.slice(6).trim());
|
|
@@ -9296,14 +9454,14 @@ function sleep(ms) {
|
|
|
9296
9454
|
function readLogTail(lines = 30) {
|
|
9297
9455
|
const st = lstatSync(logfilePath(), { throwIfNoEntry: false });
|
|
9298
9456
|
if (st === void 0 || st.isSymbolicLink()) return null;
|
|
9299
|
-
const content =
|
|
9457
|
+
const content = readFileSync17(logfilePath(), "utf-8");
|
|
9300
9458
|
const all = content.split("\n");
|
|
9301
9459
|
if (all.at(-1) === "") all.pop();
|
|
9302
9460
|
return all.slice(-lines);
|
|
9303
9461
|
}
|
|
9304
9462
|
function spawnDaemon(configEnv) {
|
|
9305
9463
|
const entry = resolve2(process.argv[1] ?? "");
|
|
9306
|
-
if (entry.length === 0 || !
|
|
9464
|
+
if (entry.length === 0 || !existsSync11(entry)) {
|
|
9307
9465
|
throw new Error(`\u65E0\u6CD5\u5B9A\u4F4D siming \u5165\u53E3\u811A\u672C\uFF08process.argv[1]=${process.argv[1] ?? "(\u7A7A)"}\uFF09`);
|
|
9308
9466
|
}
|
|
9309
9467
|
if (entry.endsWith(".ts")) {
|