kld-sdd 2.6.9 → 2.6.11
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/lib/init.js +370 -114
- package/package.json +2 -2
- package/skywalk-sdd/index.cjs +3 -2
- package/skywalk-sdd/ontology/cli.cjs +34 -7
- package/skywalk-sdd/ontology/naming-diagnose.cjs +103 -20
- package/skywalk-sdd/ontology/resolve-spec-root.cjs +102 -0
- package/skywalk-sdd/ontology/sdd-config.cjs +62 -16
- package/skywalk-sdd/ontology/workspace-layout.cjs +81 -0
- package/templates/git-hooks/commit-msg-sdd-trailer.cjs +20 -5
- package/templates/skills/kld-sdd/opsx-apply/SKILL.md +2 -1
- package/templates/skills/kld-sdd/opsx-archive/SKILL.md +3 -1
- package/templates/skills/kld-sdd/opsx-check/SKILL.md +3 -1
- package/templates/skills/kld-sdd/opsx-design/SKILL.md +3 -1
- package/templates/skills/kld-sdd/opsx-explore/SKILL.md +3 -1
- package/templates/skills/kld-sdd/opsx-propose/SKILL.md +3 -1
- package/templates/skills/kld-sdd/opsx-rules/SKILL.md +3 -1
- package/templates/skills/kld-sdd/opsx-spec/SKILL.md +3 -1
- package/templates/skills/kld-sdd/opsx-task/SKILL.md +3 -1
- package/templates/skills/kld-sdd/opsx-test/SKILL.md +3 -1
package/lib/init.js
CHANGED
|
@@ -687,14 +687,13 @@ function cleanupNativeOpenspecSkills(selectedTools = Object.keys(TOOL_CONFIGS))
|
|
|
687
687
|
}
|
|
688
688
|
|
|
689
689
|
/**
|
|
690
|
-
*
|
|
690
|
+
* 复制标准文档模版到项目(openspec-templates/)
|
|
691
691
|
*/
|
|
692
|
-
function copyTemplatesToProject() {
|
|
692
|
+
function copyTemplatesToProject(cwd = process.cwd()) {
|
|
693
693
|
console.log('📄 正在复制标准文档模版到项目...');
|
|
694
694
|
|
|
695
695
|
const pkgPath = getPackagePath();
|
|
696
696
|
const templatePath = path.join(pkgPath, 'templates', 'openspec');
|
|
697
|
-
const cwd = process.cwd();
|
|
698
697
|
const targetDir = path.join(cwd, 'openspec-templates');
|
|
699
698
|
|
|
700
699
|
if (!fs.existsSync(templatePath)) {
|
|
@@ -702,12 +701,10 @@ function copyTemplatesToProject() {
|
|
|
702
701
|
return false;
|
|
703
702
|
}
|
|
704
703
|
|
|
705
|
-
// 创建目标目录
|
|
706
704
|
if (!fs.existsSync(targetDir)) {
|
|
707
705
|
fs.mkdirSync(targetDir, { recursive: true });
|
|
708
706
|
}
|
|
709
707
|
|
|
710
|
-
// 复制模版文件
|
|
711
708
|
copyDir(templatePath, targetDir);
|
|
712
709
|
|
|
713
710
|
console.log(`✅ 标准文档模版已复制到: ${targetDir}`);
|
|
@@ -724,29 +721,24 @@ function copyTemplatesToProject() {
|
|
|
724
721
|
* 初始化全局 overview.md 到 openspec/specs/ 目录
|
|
725
722
|
* overview.md 是全局架构约束,所有 Capability 的设计都必须遵守
|
|
726
723
|
*/
|
|
727
|
-
function initGlobalOverview() {
|
|
724
|
+
function initGlobalOverview(cwd = process.cwd()) {
|
|
728
725
|
console.log('🌐 正在初始化全局架构约束 (overview.md)...');
|
|
729
726
|
|
|
730
727
|
const pkgPath = getPackagePath();
|
|
731
728
|
const overviewSource = path.join(pkgPath, 'templates', 'openspec', 'overview.md');
|
|
732
|
-
const cwd = process.cwd();
|
|
733
729
|
const targetDir = path.join(cwd, 'openspec', 'specs');
|
|
734
730
|
const targetFile = path.join(targetDir, 'overview.md');
|
|
735
731
|
|
|
736
|
-
// 检查源文件是否存在
|
|
737
732
|
if (!fs.existsSync(overviewSource)) {
|
|
738
733
|
console.log(`⚠️ overview.md 源文件不存在: ${overviewSource}`);
|
|
739
734
|
return false;
|
|
740
735
|
}
|
|
741
736
|
|
|
742
|
-
// 创建目标目录
|
|
743
737
|
if (!fs.existsSync(targetDir)) {
|
|
744
738
|
fs.mkdirSync(targetDir, { recursive: true });
|
|
745
739
|
}
|
|
746
740
|
|
|
747
|
-
// 检查目标文件是否已存在
|
|
748
741
|
if (fs.existsSync(targetFile)) {
|
|
749
|
-
// 读取现有文件,检查是否需要更新
|
|
750
742
|
const existingContent = fs.readFileSync(targetFile, 'utf-8');
|
|
751
743
|
const newContent = fs.readFileSync(overviewSource, 'utf-8');
|
|
752
744
|
|
|
@@ -755,13 +747,11 @@ function initGlobalOverview() {
|
|
|
755
747
|
return true;
|
|
756
748
|
}
|
|
757
749
|
|
|
758
|
-
// 备份现有文件
|
|
759
750
|
const backupFile = path.join(targetDir, 'overview.md.backup');
|
|
760
751
|
fs.copyFileSync(targetFile, backupFile);
|
|
761
752
|
console.log(` ℹ️ 已备份现有 overview.md 到 ${backupFile}`);
|
|
762
753
|
}
|
|
763
754
|
|
|
764
|
-
// 复制 overview.md
|
|
765
755
|
fs.copyFileSync(overviewSource, targetFile);
|
|
766
756
|
|
|
767
757
|
console.log(`✅ 全局架构约束已初始化: ${targetFile}`);
|
|
@@ -857,14 +847,22 @@ function deployTelemetryDataDir(targetCwd = process.cwd()) {
|
|
|
857
847
|
console.log(' ✓ 部署 skywalk-sdd/apply-worktree-finish.cjs(Apply 收尾脚本)');
|
|
858
848
|
}
|
|
859
849
|
|
|
850
|
+
const openspecShimSrc = path.join(pkgPath, 'skywalk-sdd', 'openspec-shim.cjs');
|
|
851
|
+
const openspecShimDst = path.join(dataDir, 'openspec-shim.cjs');
|
|
852
|
+
if (fs.existsSync(openspecShimSrc)) {
|
|
853
|
+
fs.copyFileSync(openspecShimSrc, openspecShimDst);
|
|
854
|
+
console.log(' ✓ 部署 skywalk-sdd/openspec-shim.cjs(openspec 包裹包路径 shim)');
|
|
855
|
+
}
|
|
856
|
+
|
|
860
857
|
console.log(' ✓ 调用方式: node skywalk-sdd/log.cjs start|end|metrics|semantic-identity|semantic-reconcile|semantic-check');
|
|
858
|
+
console.log(' ✓ openspec: node skywalk-sdd/openspec-shim.cjs list(自动 cd 到 *-sdd-specs)');
|
|
861
859
|
console.log(' ✓ Spec Context: node skywalk-sdd/context-client.cjs --query="<自然语言需求>" --target-stage=spec');
|
|
862
860
|
console.log(' ✓ Apply worktree: record-base 在 §1.5;收尾 apply-worktree-finish.cjs --change=<name>');
|
|
863
861
|
console.log('✅ Telemetry 已就绪(数据存储在 skywalk-sdd/,无需配置 MCP)');
|
|
864
862
|
return true;
|
|
865
863
|
}
|
|
866
864
|
|
|
867
|
-
function installGitHookShim(cwd, hookName, scriptPath) {
|
|
865
|
+
function installGitHookShim(cwd, hookName, scriptPath, options = {}) {
|
|
868
866
|
const hooksDir = path.join(cwd, '.git', 'hooks');
|
|
869
867
|
if (!fs.existsSync(hooksDir)) {
|
|
870
868
|
return;
|
|
@@ -872,11 +870,20 @@ function installGitHookShim(cwd, hookName, scriptPath) {
|
|
|
872
870
|
|
|
873
871
|
const hookPath = path.join(hooksDir, hookName);
|
|
874
872
|
const marker = 'KLD SDD quality gate';
|
|
873
|
+
// Git 把 commit-msg 文件路径放在 $1;--project 等额外参数必须跟在 "$@" 后面,
|
|
874
|
+
// 否则 trailer 脚本会把 --project=… 误当成 message 文件(argv[2])。
|
|
875
|
+
const extraArgs = options.extraArgs || '';
|
|
876
|
+
const nodeLine = extraArgs
|
|
877
|
+
? ` node "${scriptPath}" "$@" ${extraArgs}`
|
|
878
|
+
: ` node "${scriptPath}" "$@"`;
|
|
875
879
|
const shim = [
|
|
876
880
|
'#!/bin/sh',
|
|
877
881
|
`# ${marker}`,
|
|
878
882
|
`if [ -f "${scriptPath}" ]; then`,
|
|
879
|
-
|
|
883
|
+
nodeLine,
|
|
884
|
+
'else',
|
|
885
|
+
` echo "[kld-sdd] Hook 脚本不存在: ${scriptPath}" >&2`,
|
|
886
|
+
' exit 1',
|
|
880
887
|
'fi',
|
|
881
888
|
'',
|
|
882
889
|
].join('\n');
|
|
@@ -884,10 +891,21 @@ function installGitHookShim(cwd, hookName, scriptPath) {
|
|
|
884
891
|
if (fs.existsSync(hookPath)) {
|
|
885
892
|
const existing = fs.readFileSync(hookPath, 'utf8');
|
|
886
893
|
if (existing.includes(marker)) {
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
894
|
+
// 已是 SDD shim:若指向路径变化(如改为引用 spec 仓),允许覆盖升级
|
|
895
|
+
if (existing.includes(scriptPath) && (!extraArgs || existing.includes(extraArgs.trim()))) {
|
|
896
|
+
console.log(` ✓ .git/hooks/${hookName} 已包含 SDD 质量门禁`);
|
|
897
|
+
return;
|
|
898
|
+
}
|
|
899
|
+
fs.writeFileSync(hookPath, shim, 'utf8');
|
|
900
|
+
try {
|
|
901
|
+
fs.chmodSync(hookPath, 0o755);
|
|
902
|
+
} catch {
|
|
903
|
+
// ignore
|
|
904
|
+
}
|
|
905
|
+
console.log(` ✓ 更新 .git/hooks/${hookName} SDD 质量门禁`);
|
|
906
|
+
return;
|
|
890
907
|
}
|
|
908
|
+
console.log(` ℹ️ .git/hooks/${hookName} 已存在,已保留不覆盖;可手动调用 ${scriptPath}`);
|
|
891
909
|
return;
|
|
892
910
|
}
|
|
893
911
|
|
|
@@ -900,14 +918,52 @@ function installGitHookShim(cwd, hookName, scriptPath) {
|
|
|
900
918
|
console.log(` ✓ 安装 .git/hooks/${hookName} SDD 质量门禁`);
|
|
901
919
|
}
|
|
902
920
|
|
|
921
|
+
/**
|
|
922
|
+
* 确保 spec 包裹包内有 commit-msg 脚本(供代码仓 Hook 远程引用)。
|
|
923
|
+
*/
|
|
924
|
+
function ensureSpecCommitMsgScript(specRepoRoot, pkgPath = getPackagePath()) {
|
|
925
|
+
const specRoot = path.resolve(specRepoRoot);
|
|
926
|
+
const scriptPath = path.join(specRoot, 'skywalk-sdd', 'git-hooks', 'commit-msg-sdd-trailer.cjs');
|
|
927
|
+
if (fs.existsSync(scriptPath)) return { ok: true, scriptPath };
|
|
928
|
+
|
|
929
|
+
const src = path.join(pkgPath, 'templates', 'git-hooks', 'commit-msg-sdd-trailer.cjs');
|
|
930
|
+
if (!fs.existsSync(src)) {
|
|
931
|
+
return { ok: false, message: `commit-msg 模板缺失: ${src}` };
|
|
932
|
+
}
|
|
933
|
+
const ontologySrc = path.join(pkgPath, 'skywalk-sdd', 'ontology');
|
|
934
|
+
const ontologyDst = path.join(specRoot, 'skywalk-sdd', 'ontology');
|
|
935
|
+
if (fs.existsSync(ontologySrc) && !fs.existsSync(path.join(ontologyDst, 'change-key.cjs'))) {
|
|
936
|
+
copyDir(ontologySrc, ontologyDst);
|
|
937
|
+
}
|
|
938
|
+
fs.mkdirSync(path.dirname(scriptPath), { recursive: true });
|
|
939
|
+
fs.copyFileSync(src, scriptPath);
|
|
940
|
+
return { ok: true, scriptPath, deployed: true };
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
/**
|
|
944
|
+
* 代码仓 commit-msg:只写 .git/hooks,脚本与 ontology 一律用 spec 仓那一份。
|
|
945
|
+
*/
|
|
946
|
+
function installCodeRepoCommitMsgHook(codeRepoRoot, specRepoRoot, options = {}) {
|
|
947
|
+
const cwd = path.resolve(codeRepoRoot);
|
|
948
|
+
const ensured = ensureSpecCommitMsgScript(specRepoRoot, options.pkgPath || getPackagePath());
|
|
949
|
+
if (!ensured.ok) {
|
|
950
|
+
console.log(` ⚠️ ${ensured.message}`);
|
|
951
|
+
return false;
|
|
952
|
+
}
|
|
953
|
+
installGitHookShim(cwd, 'commit-msg', ensured.scriptPath, {
|
|
954
|
+
extraArgs: `--project=${cwd}`,
|
|
955
|
+
});
|
|
956
|
+
return true;
|
|
957
|
+
}
|
|
958
|
+
|
|
903
959
|
/**
|
|
904
960
|
* 部署 Git hooks / CI 兜底模板
|
|
905
961
|
* 这些脚本只做质量门禁和 CI 补充记录,不替代 OPSX 主采集链路。
|
|
906
962
|
*
|
|
907
963
|
* @param {string} [targetCwd]
|
|
908
964
|
* @param {{ mode?: 'full'|'commit-msg-only' }} [options]
|
|
909
|
-
* full: spec
|
|
910
|
-
* commit-msg-only:
|
|
965
|
+
* full: spec 包裹包(pre-commit/pre-push/commit-msg + CI)
|
|
966
|
+
* commit-msg-only: 单仓 Git 根(本仓落 skywalk-sdd/git-hooks;多仓代码仓请用 installCodeRepoCommitMsgHook)
|
|
911
967
|
*/
|
|
912
968
|
function deployQualityGateTemplates(targetCwd = process.cwd(), options = {}) {
|
|
913
969
|
const pkgPath = getPackagePath();
|
|
@@ -948,12 +1004,12 @@ function deployQualityGateTemplates(targetCwd = process.cwd(), options = {}) {
|
|
|
948
1004
|
}
|
|
949
1005
|
|
|
950
1006
|
/**
|
|
951
|
-
*
|
|
1007
|
+
* 代码仓轻量接入:只写 .sdd.yaml + sdd.specPath + .git/hooks/commit-msg。
|
|
1008
|
+
* 不在代码仓落 skywalk-sdd/——Hook 脚本与 ontology 引用 spec 包裹包那一份。
|
|
952
1009
|
*/
|
|
953
1010
|
function attachCodeRepoLite(codeRepoRoot, specRepoRoot, options = {}) {
|
|
954
1011
|
const cwd = path.resolve(codeRepoRoot);
|
|
955
1012
|
const specRoot = path.resolve(specRepoRoot);
|
|
956
|
-
const pkgPath = options.pkgPath || getPackagePath();
|
|
957
1013
|
const label = path.basename(cwd);
|
|
958
1014
|
|
|
959
1015
|
if (!workspaceLayout.isGitRepo(cwd)) {
|
|
@@ -963,16 +1019,7 @@ function attachCodeRepoLite(codeRepoRoot, specRepoRoot, options = {}) {
|
|
|
963
1019
|
return { ok: false, repo: label, message: `spec 路径不是 Git 仓库: ${specRoot}` };
|
|
964
1020
|
}
|
|
965
1021
|
|
|
966
|
-
console.log(`🔗 轻量接入代码仓(无 skills): ${label}`);
|
|
967
|
-
|
|
968
|
-
// Hook 依赖 ontology + git-hooks;不部署完整 telemetry/skills
|
|
969
|
-
const dataDir = path.join(cwd, 'skywalk-sdd');
|
|
970
|
-
const ontologySrc = path.join(pkgPath, 'skywalk-sdd', 'ontology');
|
|
971
|
-
const ontologyDst = path.join(dataDir, 'ontology');
|
|
972
|
-
if (fs.existsSync(ontologySrc)) {
|
|
973
|
-
copyDir(ontologySrc, ontologyDst);
|
|
974
|
-
}
|
|
975
|
-
deployQualityGateTemplates(cwd, { mode: 'commit-msg-only' });
|
|
1022
|
+
console.log(`🔗 轻量接入代码仓(无 skywalk-sdd/、无 skills): ${label}`);
|
|
976
1023
|
|
|
977
1024
|
const remote = sddConfig.gitRemoteUrl(specRoot) || 'git@gitlab.example.com:biz/xxx-sdd-specs.git';
|
|
978
1025
|
const sddYamlPath = path.join(cwd, '.sdd.yaml');
|
|
@@ -998,6 +1045,9 @@ function attachCodeRepoLite(codeRepoRoot, specRepoRoot, options = {}) {
|
|
|
998
1045
|
}
|
|
999
1046
|
console.log(` ✓ sdd.specPath = ${linked.path}`);
|
|
1000
1047
|
|
|
1048
|
+
installCodeRepoCommitMsgHook(cwd, specRoot, options);
|
|
1049
|
+
console.log(' ✓ commit-msg → spec 仓 skywalk-sdd/git-hooks/(代码仓不落 skywalk-sdd/)');
|
|
1050
|
+
|
|
1001
1051
|
return { ok: true, repo: label, path: cwd, specPath: linked.path };
|
|
1002
1052
|
}
|
|
1003
1053
|
|
|
@@ -1065,32 +1115,190 @@ function deployDotSddYaml(cwd = process.cwd(), pkgPath = getPackagePath()) {
|
|
|
1065
1115
|
}
|
|
1066
1116
|
|
|
1067
1117
|
/**
|
|
1068
|
-
*
|
|
1118
|
+
* 单仓声明 layout: mono,并记录仓内统一包裹目录相对路径。
|
|
1069
1119
|
* commit-msg Hook 靠它跳过「spec 工作区干净」检查并只写 Spec-Change。
|
|
1070
1120
|
*/
|
|
1071
|
-
function deployMonoSddYaml(cwd = process.cwd()) {
|
|
1121
|
+
function deployMonoSddYaml(cwd = process.cwd(), options = {}) {
|
|
1072
1122
|
const target = path.join(cwd, '.sdd.yaml');
|
|
1123
|
+
const specRel = options.specPathRelative
|
|
1124
|
+
? String(options.specPathRelative).replace(/\\/g, '/')
|
|
1125
|
+
: '';
|
|
1126
|
+
|
|
1073
1127
|
if (fs.existsSync(target)) {
|
|
1074
1128
|
const existing = fs.readFileSync(target, 'utf8');
|
|
1075
1129
|
if (/^layout:\s*mono\s*$/m.test(existing)) {
|
|
1130
|
+
if (specRel && !new RegExp(`^spec_path:\\s*${specRel.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\s*$`, 'm').test(existing)) {
|
|
1131
|
+
// 已有 mono 但缺/错 spec_path:补写相对路径
|
|
1132
|
+
let next = existing.replace(/\s*$/, '');
|
|
1133
|
+
if (/^spec_path:\s*.+$/m.test(next)) {
|
|
1134
|
+
next = next.replace(/^spec_path:\s*.+$/m, `spec_path: ${specRel}`);
|
|
1135
|
+
} else {
|
|
1136
|
+
next = `${next}\nspec_path: ${specRel}`;
|
|
1137
|
+
}
|
|
1138
|
+
fs.writeFileSync(target, `${next}\n`, 'utf8');
|
|
1139
|
+
console.log(` ✓ 已更新 .sdd.yaml spec_path → ${specRel}`);
|
|
1140
|
+
return true;
|
|
1141
|
+
}
|
|
1076
1142
|
console.log(' ✓ .sdd.yaml 已声明 layout: mono,跳过');
|
|
1077
1143
|
return true;
|
|
1078
1144
|
}
|
|
1079
|
-
console.log('⚠️ .sdd.yaml 已存在但未声明 layout: mono
|
|
1145
|
+
console.log('⚠️ .sdd.yaml 已存在但未声明 layout: mono;单仓请手动补 `layout: mono`');
|
|
1080
1146
|
return false;
|
|
1081
1147
|
}
|
|
1082
1148
|
const lines = [
|
|
1083
|
-
'#
|
|
1084
|
-
'#
|
|
1149
|
+
'# 单仓布局:业务代码与 SDD 包裹包在同一个 Git 仓库',
|
|
1150
|
+
'# SDD 内容统一在 spec_path 目录内(openspec / modules / sdd.config / 模版)',
|
|
1151
|
+
'# commit-msg 只写 Spec-Change(同仓一次 commit,无需 Spec-Revision 指针)',
|
|
1085
1152
|
'version: 1',
|
|
1086
1153
|
'layout: mono',
|
|
1087
|
-
'',
|
|
1088
1154
|
];
|
|
1155
|
+
if (specRel) lines.push(`spec_path: ${specRel}`);
|
|
1156
|
+
lines.push('');
|
|
1089
1157
|
fs.writeFileSync(target, lines.join('\n'), 'utf8');
|
|
1090
|
-
console.log(`✅ 已创建 .sdd.yaml(layout: mono): ${target}`);
|
|
1158
|
+
console.log(`✅ 已创建 .sdd.yaml(layout: mono${specRel ? `, spec_path: ${specRel}` : ''}): ${target}`);
|
|
1091
1159
|
return true;
|
|
1092
1160
|
}
|
|
1093
1161
|
|
|
1162
|
+
/**
|
|
1163
|
+
* 向统一 SDD 包裹目录写入完整内容(多仓兄弟仓 / 单仓内部子目录共用)。
|
|
1164
|
+
* 不在此部署编辑器 skills——skills 只装工作目录或单仓 Git 根。
|
|
1165
|
+
*/
|
|
1166
|
+
async function populateSpecPackage(specRoot, options = {}) {
|
|
1167
|
+
const root = path.resolve(specRoot);
|
|
1168
|
+
const skipOpenspec = Boolean(options.skipOpenspec);
|
|
1169
|
+
const asIndependentGit = Boolean(options.asIndependentGit);
|
|
1170
|
+
console.log(`📦 正在填充 SDD 包裹包: ${root}`);
|
|
1171
|
+
|
|
1172
|
+
if (!skipOpenspec) {
|
|
1173
|
+
const prev = process.cwd();
|
|
1174
|
+
try {
|
|
1175
|
+
process.chdir(root);
|
|
1176
|
+
// 包裹包内只建 openspec 目录结构,不把编辑器配置写进文档仓
|
|
1177
|
+
await runOpenspecInit([]);
|
|
1178
|
+
} finally {
|
|
1179
|
+
process.chdir(prev);
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
deployTelemetryDataDir(root);
|
|
1184
|
+
if (asIndependentGit || workspaceLayout.isGitRepo(root)) {
|
|
1185
|
+
deployQualityGateTemplates(root, { mode: 'full' });
|
|
1186
|
+
}
|
|
1187
|
+
deployModulesYaml(root);
|
|
1188
|
+
deploySddConfigYaml(root);
|
|
1189
|
+
copyTemplatesToProject(root);
|
|
1190
|
+
initGlobalOverview(root);
|
|
1191
|
+
deploySddGuideManual(root);
|
|
1192
|
+
console.log(`✅ SDD 包裹包已就绪: ${path.basename(root)}`);
|
|
1193
|
+
return { ok: true, path: root };
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
/**
|
|
1197
|
+
* 在工作区 / Git 根写入 .sdd-spec-root,供 shell 与 skills 引用相对包裹包路径。
|
|
1198
|
+
*/
|
|
1199
|
+
function writeSddSpecRootHint(anchorDir, specPackageAbs) {
|
|
1200
|
+
const anchor = path.resolve(anchorDir);
|
|
1201
|
+
const specAbs = path.resolve(specPackageAbs);
|
|
1202
|
+
const rel = path.relative(anchor, specAbs).replace(/\\/g, '/');
|
|
1203
|
+
if (!rel || rel.startsWith('..')) return null;
|
|
1204
|
+
const filePath = path.join(anchor, '.sdd-spec-root');
|
|
1205
|
+
fs.writeFileSync(filePath, `${rel}\n`, 'utf8');
|
|
1206
|
+
console.log(` ✓ 已写入 .sdd-spec-root → ${rel}`);
|
|
1207
|
+
return filePath;
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
/**
|
|
1211
|
+
* 工作区 / 单仓 Git 根的 skywalk-sdd/ 改为指向包裹包内唯一实体(符号链接)。
|
|
1212
|
+
* skills 仍可用 `node skywalk-sdd/log.cjs`,实体文件只在 *-sdd-specs/skywalk-sdd/。
|
|
1213
|
+
* 链接失败时回退为薄转发脚本(不复制 ontology)。
|
|
1214
|
+
*/
|
|
1215
|
+
function deploySkywalkForwarders(anchorDir, specPackageAbs) {
|
|
1216
|
+
const anchor = path.resolve(anchorDir);
|
|
1217
|
+
const specAbs = path.resolve(specPackageAbs);
|
|
1218
|
+
const relSpec = path.relative(anchor, specAbs).replace(/\\/g, '/');
|
|
1219
|
+
const skywalkDir = path.join(anchor, 'skywalk-sdd');
|
|
1220
|
+
const targetSkywalk = path.join(specAbs, 'skywalk-sdd');
|
|
1221
|
+
fs.mkdirSync(path.join(skywalkDir, 'ontology'), { recursive: true });
|
|
1222
|
+
|
|
1223
|
+
const writeForwarder = (destRel, targetAbsPath) => {
|
|
1224
|
+
const dest = path.join(skywalkDir, destRel);
|
|
1225
|
+
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
1226
|
+
const relFromDestDir = path.relative(path.dirname(dest), targetAbsPath).replace(/\\/g, '/');
|
|
1227
|
+
const body = [
|
|
1228
|
+
'#!/usr/bin/env node',
|
|
1229
|
+
"'use strict';",
|
|
1230
|
+
"const { spawnSync } = require('child_process');",
|
|
1231
|
+
"const path = require('path');",
|
|
1232
|
+
`const target = path.resolve(__dirname, ${JSON.stringify(relFromDestDir)});`,
|
|
1233
|
+
'const r = spawnSync(process.execPath, [target, ...process.argv.slice(2)], { stdio: \'inherit\' });',
|
|
1234
|
+
'process.exit(r.status === null ? 1 : r.status);',
|
|
1235
|
+
'',
|
|
1236
|
+
].join('\n');
|
|
1237
|
+
fs.writeFileSync(dest, body, 'utf8');
|
|
1238
|
+
};
|
|
1239
|
+
|
|
1240
|
+
const entries = [
|
|
1241
|
+
'log.cjs',
|
|
1242
|
+
'openspec-shim.cjs',
|
|
1243
|
+
'context-client.cjs',
|
|
1244
|
+
'apply-worktree-finish.cjs',
|
|
1245
|
+
];
|
|
1246
|
+
for (const name of entries) {
|
|
1247
|
+
writeForwarder(name, path.join(targetSkywalk, name));
|
|
1248
|
+
}
|
|
1249
|
+
writeForwarder(path.join('ontology', 'cli.cjs'), path.join(targetSkywalk, 'ontology', 'cli.cjs'));
|
|
1250
|
+
console.log(` ✓ skywalk-sdd/ 转发脚本 → ${relSpec}/skywalk-sdd/(实体在包裹包)`);
|
|
1251
|
+
return { ok: true, mode: 'forwarders', relSpec };
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
function linkSkywalkToSpecPackage(anchorDir, specPackageAbs) {
|
|
1255
|
+
const anchor = path.resolve(anchorDir);
|
|
1256
|
+
const targetAbs = path.join(path.resolve(specPackageAbs), 'skywalk-sdd');
|
|
1257
|
+
const linkAbs = path.join(anchor, 'skywalk-sdd');
|
|
1258
|
+
|
|
1259
|
+
if (!fs.existsSync(targetAbs)) {
|
|
1260
|
+
console.log(' ⚠️ 包裹包尚无 skywalk-sdd/,跳过工作区链接');
|
|
1261
|
+
return { ok: false, message: 'spec skywalk-sdd missing' };
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
try {
|
|
1265
|
+
let st = null;
|
|
1266
|
+
try {
|
|
1267
|
+
st = fs.lstatSync(linkAbs);
|
|
1268
|
+
} catch (err) {
|
|
1269
|
+
if (!err || err.code !== 'ENOENT') throw err;
|
|
1270
|
+
}
|
|
1271
|
+
if (st) {
|
|
1272
|
+
if (st.isSymbolicLink()) {
|
|
1273
|
+
const current = fs.realpathSync(linkAbs);
|
|
1274
|
+
if (current === fs.realpathSync(targetAbs)) {
|
|
1275
|
+
console.log(' ✓ skywalk-sdd/ 已链接到包裹包(唯一实体)');
|
|
1276
|
+
return { ok: true, mode: 'symlink', linkAbs, targetAbs };
|
|
1277
|
+
}
|
|
1278
|
+
fs.unlinkSync(linkAbs);
|
|
1279
|
+
} else if (st.isDirectory()) {
|
|
1280
|
+
// 旧完整副本 → 删除后改链接(权威数据在包裹包)
|
|
1281
|
+
fs.rmSync(linkAbs, { recursive: true, force: true });
|
|
1282
|
+
} else {
|
|
1283
|
+
fs.unlinkSync(linkAbs);
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
} catch (err) {
|
|
1287
|
+
console.log(` ⚠️ 清理旧 skywalk-sdd/ 失败: ${err.message}`);
|
|
1288
|
+
return deploySkywalkForwarders(anchor, specPackageAbs);
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
const rel = path.relative(anchor, targetAbs);
|
|
1292
|
+
try {
|
|
1293
|
+
fs.symlinkSync(rel, linkAbs, process.platform === 'win32' ? 'junction' : 'dir');
|
|
1294
|
+
console.log(` ✓ skywalk-sdd/ → ${rel.replace(/\\/g, '/')}(唯一实体在包裹包)`);
|
|
1295
|
+
return { ok: true, mode: 'symlink', linkAbs, targetAbs, rel };
|
|
1296
|
+
} catch (err) {
|
|
1297
|
+
console.log(` ⚠️ 符号链接失败 (${err.message}),回退为转发脚本`);
|
|
1298
|
+
return deploySkywalkForwarders(anchor, specPackageAbs);
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1094
1302
|
/**
|
|
1095
1303
|
* 检测当前项目已初始化的 AI 编辑器
|
|
1096
1304
|
*/
|
|
@@ -1121,6 +1329,8 @@ function updateGitignore() {
|
|
|
1121
1329
|
'.agents/commands/personal-*',
|
|
1122
1330
|
'skywalk-sdd/events/',
|
|
1123
1331
|
'skywalk-sdd/state/',
|
|
1332
|
+
'**/skywalk-sdd/events/',
|
|
1333
|
+
'**/skywalk-sdd/state/',
|
|
1124
1334
|
'.worktrees/'
|
|
1125
1335
|
];
|
|
1126
1336
|
|
|
@@ -1134,9 +1344,11 @@ function updateGitignore() {
|
|
|
1134
1344
|
.workbuddy/commands/personal-*
|
|
1135
1345
|
.agents/commands/personal-*
|
|
1136
1346
|
|
|
1137
|
-
# SDD Telemetry
|
|
1347
|
+
# SDD Telemetry 数据(实体在 *-sdd-specs/skywalk-sdd/;工作区可能是 symlink)
|
|
1138
1348
|
skywalk-sdd/events/
|
|
1139
1349
|
skywalk-sdd/state/
|
|
1350
|
+
**/skywalk-sdd/events/
|
|
1351
|
+
**/skywalk-sdd/state/
|
|
1140
1352
|
|
|
1141
1353
|
# SDD Apply 隔离 worktree(本地临时目录)
|
|
1142
1354
|
.worktrees/
|
|
@@ -1274,32 +1486,21 @@ async function main() {
|
|
|
1274
1486
|
}
|
|
1275
1487
|
|
|
1276
1488
|
const workspaceRoot = process.cwd();
|
|
1277
|
-
|
|
1489
|
+
let layout = workspaceLayout.detectWorkspaceLayout(workspaceRoot);
|
|
1490
|
+
let specPackage = layout.specRepo
|
|
1491
|
+
? { name: layout.specRepo.name, abs: layout.specRepo.abs, created: false, isGit: true }
|
|
1492
|
+
: null;
|
|
1493
|
+
|
|
1278
1494
|
if (layout.isWorkspace) {
|
|
1279
1495
|
console.log('📂 检测到个人工作目录布局(子目录 Git 仓库)');
|
|
1280
|
-
console.log(` Spec: ${
|
|
1496
|
+
console.log(` Spec: ${specPackage ? specPackage.name : '(未发现,将自动创建包裹包)'}`);
|
|
1281
1497
|
console.log(` 代码仓: ${layout.codeRepos.map((c) => c.name).join(', ') || '(无)'}`);
|
|
1282
|
-
console.log(' → skills
|
|
1498
|
+
console.log(' → skills 只部署到本工作目录;SDD 文档统一进 *-sdd-specs 包裹包');
|
|
1283
1499
|
console.log();
|
|
1284
1500
|
}
|
|
1285
1501
|
|
|
1286
|
-
// 1. openspec init:工作区模式下若有 spec 仓则在其内执行
|
|
1287
|
-
if (!skipOpenspec) {
|
|
1288
|
-
if (layout.isWorkspace && layout.specRepo) {
|
|
1289
|
-
const prev = process.cwd();
|
|
1290
|
-
try {
|
|
1291
|
-
process.chdir(layout.specRepo.abs);
|
|
1292
|
-
await runOpenspecInit(selectedTools);
|
|
1293
|
-
} finally {
|
|
1294
|
-
process.chdir(prev);
|
|
1295
|
-
}
|
|
1296
|
-
} else {
|
|
1297
|
-
await runOpenspecInit(selectedTools);
|
|
1298
|
-
}
|
|
1299
|
-
}
|
|
1300
|
-
|
|
1301
1502
|
if (!skipTemplate) {
|
|
1302
|
-
//
|
|
1503
|
+
// skills / 编辑器产物:永远只装在当前工作目录一次
|
|
1303
1504
|
cleanupNativeOpenspecCommands(selectedTools);
|
|
1304
1505
|
cleanupLegacyBundledOpsxSkills(selectedTools);
|
|
1305
1506
|
deployOpsxSkills(selectedTools);
|
|
@@ -1307,49 +1508,95 @@ async function main() {
|
|
|
1307
1508
|
deployProfileArtifacts(selectedTools, workspaceRoot, getPackagePath());
|
|
1308
1509
|
|
|
1309
1510
|
if (layout.isWorkspace) {
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
try {
|
|
1316
|
-
process.chdir(layout.specRepo.abs);
|
|
1317
|
-
deployTelemetryDataDir(layout.specRepo.abs);
|
|
1318
|
-
deployQualityGateTemplates(layout.specRepo.abs, { mode: 'full' });
|
|
1319
|
-
deployModulesYaml(layout.specRepo.abs);
|
|
1320
|
-
deploySddConfigYaml(layout.specRepo.abs);
|
|
1321
|
-
copyTemplatesToProject();
|
|
1322
|
-
initGlobalOverview();
|
|
1323
|
-
deploySddGuideManual(layout.specRepo.abs);
|
|
1324
|
-
} finally {
|
|
1325
|
-
process.chdir(prev);
|
|
1326
|
-
}
|
|
1511
|
+
if (!specPackage) {
|
|
1512
|
+
console.log('📦 未发现 spec 仓,正在创建统一 SDD 包裹包(独立 Git)...');
|
|
1513
|
+
specPackage = workspaceLayout.ensureSpecPackage(workspaceRoot, { initGit: true });
|
|
1514
|
+
console.log(` ✓ ${specPackage.created ? '已创建' : '已复用'}: ${specPackage.name}`);
|
|
1515
|
+
}
|
|
1327
1516
|
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1517
|
+
await populateSpecPackage(specPackage.abs, {
|
|
1518
|
+
skipOpenspec,
|
|
1519
|
+
asIndependentGit: true,
|
|
1520
|
+
});
|
|
1521
|
+
writeSddSpecRootHint(workspaceRoot, specPackage.abs);
|
|
1522
|
+
// 工作区不复制 skywalk-sdd 实体,只链到包裹包(skills 路径仍可用)
|
|
1523
|
+
linkSkywalkToSpecPackage(workspaceRoot, specPackage.abs);
|
|
1524
|
+
|
|
1525
|
+
// 重新探测,刷新 layout.specRepo / codeRepos
|
|
1526
|
+
layout = workspaceLayout.detectWorkspaceLayout(workspaceRoot);
|
|
1527
|
+
if (!layout.specRepo) {
|
|
1528
|
+
layout.specRepo = { name: specPackage.name, abs: specPackage.abs };
|
|
1337
1529
|
}
|
|
1530
|
+
|
|
1531
|
+
console.log();
|
|
1532
|
+
console.log('🔗 正在为子代码仓做轻量接入(不安装 skills)...');
|
|
1533
|
+
for (const repo of layout.codeRepos) {
|
|
1534
|
+
attachCodeRepoLite(repo.abs, specPackage.abs);
|
|
1535
|
+
}
|
|
1536
|
+
const wsFile = workspaceLayout.writeWorkspaceFile(workspaceRoot, layout);
|
|
1537
|
+
console.log(`✅ 工作区清单: ${wsFile}`);
|
|
1338
1538
|
} else {
|
|
1339
|
-
//
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1539
|
+
// 单仓:Git 根只放代码 + skills + Hook;SDD 内容进统一包裹子目录
|
|
1540
|
+
const isGit = workspaceLayout.isGitRepo(workspaceRoot);
|
|
1541
|
+
|
|
1542
|
+
if (isGit) {
|
|
1543
|
+
console.log('📦 单仓模式:创建/复用仓内统一 SDD 包裹目录...');
|
|
1544
|
+
specPackage = workspaceLayout.ensureSpecPackage(workspaceRoot, { initGit: false });
|
|
1545
|
+
console.log(` ✓ ${specPackage.created ? '已创建' : '已复用'}: ${specPackage.name}`);
|
|
1546
|
+
|
|
1547
|
+
await populateSpecPackage(specPackage.abs, {
|
|
1548
|
+
skipOpenspec,
|
|
1549
|
+
asIndependentGit: false,
|
|
1550
|
+
});
|
|
1551
|
+
writeSddSpecRootHint(workspaceRoot, specPackage.abs);
|
|
1552
|
+
linkSkywalkToSpecPackage(workspaceRoot, specPackage.abs);
|
|
1553
|
+
|
|
1554
|
+
deployMonoSddYaml(workspaceRoot, { specPathRelative: specPackage.name });
|
|
1555
|
+
// Hook 装在 Git 根;经 symlink 写入包裹包内的 git-hooks
|
|
1556
|
+
deployQualityGateTemplates(workspaceRoot, { mode: 'commit-msg-only' });
|
|
1557
|
+
const linked = sddConfig.setSpecPath(workspaceRoot, specPackage.abs, {
|
|
1558
|
+
allowNestedPackage: true,
|
|
1559
|
+
});
|
|
1560
|
+
if (linked.ok) {
|
|
1561
|
+
console.log(` ✓ sdd.specPath = ${linked.path}`);
|
|
1562
|
+
} else {
|
|
1563
|
+
console.log(` ⚠️ 未能写入 sdd.specPath: ${linked.message}`);
|
|
1564
|
+
}
|
|
1347
1565
|
} else {
|
|
1566
|
+
// 非 Git 目录:仍创建包裹包,便于随后 git init
|
|
1567
|
+
console.log('📦 当前目录不是 Git 仓:仍创建 SDD 包裹包(请稍后 git init)...');
|
|
1568
|
+
specPackage = workspaceLayout.ensureSpecPackage(workspaceRoot, { initGit: false });
|
|
1569
|
+
await populateSpecPackage(specPackage.abs, {
|
|
1570
|
+
skipOpenspec,
|
|
1571
|
+
asIndependentGit: false,
|
|
1572
|
+
});
|
|
1573
|
+
writeSddSpecRootHint(workspaceRoot, specPackage.abs);
|
|
1574
|
+
linkSkywalkToSpecPackage(workspaceRoot, specPackage.abs);
|
|
1348
1575
|
deployDotSddYaml(workspaceRoot);
|
|
1349
1576
|
}
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1577
|
+
}
|
|
1578
|
+
} else if (!skipOpenspec) {
|
|
1579
|
+
// 仅 openspec、跳过模版时:仍尊重包裹包,避免在工作区根平铺
|
|
1580
|
+
if (layout.isWorkspace) {
|
|
1581
|
+
if (!specPackage) {
|
|
1582
|
+
specPackage = workspaceLayout.ensureSpecPackage(workspaceRoot, { initGit: true });
|
|
1583
|
+
}
|
|
1584
|
+
const prev = process.cwd();
|
|
1585
|
+
try {
|
|
1586
|
+
process.chdir(specPackage.abs);
|
|
1587
|
+
await runOpenspecInit([]);
|
|
1588
|
+
} finally {
|
|
1589
|
+
process.chdir(prev);
|
|
1590
|
+
}
|
|
1591
|
+
} else {
|
|
1592
|
+
specPackage = workspaceLayout.ensureSpecPackage(workspaceRoot, { initGit: false });
|
|
1593
|
+
const prev = process.cwd();
|
|
1594
|
+
try {
|
|
1595
|
+
process.chdir(specPackage.abs);
|
|
1596
|
+
await runOpenspecInit([]);
|
|
1597
|
+
} finally {
|
|
1598
|
+
process.chdir(prev);
|
|
1599
|
+
}
|
|
1353
1600
|
}
|
|
1354
1601
|
}
|
|
1355
1602
|
|
|
@@ -1369,23 +1616,27 @@ async function main() {
|
|
|
1369
1616
|
console.log('工作区部署结果:');
|
|
1370
1617
|
console.log(' 🎯 工作目录 .*/skills/opsx-*/ # skills 只装这一份');
|
|
1371
1618
|
console.log(' 📋 .sdd-workspace.yaml # 子仓编排清单');
|
|
1372
|
-
|
|
1373
|
-
|
|
1619
|
+
console.log(' 🔗 skywalk-sdd/ → *-sdd-specs/skywalk-sdd/ # 符号链接,实体只在包裹包');
|
|
1620
|
+
if (specPackage) {
|
|
1621
|
+
console.log(` 📄 ${specPackage.name}/ # 统一 SDD 包裹包(独立 Git)`);
|
|
1622
|
+
console.log(' modules.yaml / sdd.config.yaml / openspec / openspec-templates / skywalk-sdd');
|
|
1374
1623
|
}
|
|
1375
1624
|
for (const repo of layout.codeRepos) {
|
|
1376
|
-
console.log(` 🔗 ${repo.name}/ ← commit-msg Hook + .sdd.yaml(无 skills)`);
|
|
1625
|
+
console.log(` 🔗 ${repo.name}/ ← commit-msg Hook + .sdd.yaml(无 skywalk-sdd/、无 skills)`);
|
|
1377
1626
|
}
|
|
1378
1627
|
console.log();
|
|
1379
1628
|
console.log('新代码仓加入后执行:');
|
|
1380
1629
|
console.log(' kld-sdd sync-repos');
|
|
1381
1630
|
console.log('Trailer 仍在各代码仓 git commit 时由 Hook 写入。');
|
|
1382
1631
|
} else {
|
|
1383
|
-
console.log('
|
|
1384
|
-
console.log('
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1632
|
+
console.log('单仓部署结果:');
|
|
1633
|
+
console.log(' 🎯 .*/skills/opsx-*/ # SDD skills(装在 Git 根)');
|
|
1634
|
+
if (specPackage) {
|
|
1635
|
+
console.log(` 📄 ${specPackage.name}/ # 统一 SDD 包裹包(仓内子目录)`);
|
|
1636
|
+
console.log(' modules.yaml / sdd.config.yaml / openspec / openspec-templates / skywalk-sdd');
|
|
1637
|
+
}
|
|
1638
|
+
console.log(' 🔗 .sdd.yaml (layout: mono) + commit-msg Hook');
|
|
1639
|
+
console.log(' 🔗 skywalk-sdd/ → *-sdd-specs/skywalk-sdd/ # 符号链接,实体只在包裹包');
|
|
1389
1640
|
}
|
|
1390
1641
|
if (selectedTools.includes('kunlunzhima')) {
|
|
1391
1642
|
console.log(' 📎 .kunlunzhima/commands/opsx/ # KunlunZhima OPSX command bridge(11 个)');
|
|
@@ -1397,11 +1648,6 @@ async function main() {
|
|
|
1397
1648
|
if (selectedTools.includes('claude')) {
|
|
1398
1649
|
console.log(' 🪝 .claude/hooks/ # Claude Code SDD Hook Pack(可选增强)');
|
|
1399
1650
|
}
|
|
1400
|
-
if (!layout.isWorkspace) {
|
|
1401
|
-
console.log(' 📊 skywalk-sdd/ # SDD Telemetry 数据目录');
|
|
1402
|
-
console.log(' 🧰 skywalk-sdd/git-hooks/ # Git hooks 质量门禁模板');
|
|
1403
|
-
console.log(' 🧪 skywalk-sdd/ci/ # CI 兜底采集模板');
|
|
1404
|
-
}
|
|
1405
1651
|
console.log();
|
|
1406
1652
|
|
|
1407
1653
|
// 统一的 skill 格式说明
|
|
@@ -1420,8 +1666,10 @@ async function main() {
|
|
|
1420
1666
|
|
|
1421
1667
|
console.log();
|
|
1422
1668
|
console.log('后续步骤:');
|
|
1423
|
-
if (layout.isWorkspace &&
|
|
1424
|
-
console.log(` 0.
|
|
1669
|
+
if (layout.isWorkspace && specPackage) {
|
|
1670
|
+
console.log(` 0. 文档类命令请以包裹包为 --project(例: --project=${specPackage.name})`);
|
|
1671
|
+
} else if (specPackage) {
|
|
1672
|
+
console.log(` 0. 文档类命令请以包裹包为 --project(例: --project=${specPackage.name})`);
|
|
1425
1673
|
}
|
|
1426
1674
|
console.log(' 1. 激活 opsx-propose skill,输入变更名称开始创建文档');
|
|
1427
1675
|
console.log(' 2. 按顺序执行 propose → spec → design → task');
|
|
@@ -1438,8 +1686,12 @@ async function main() {
|
|
|
1438
1686
|
}
|
|
1439
1687
|
console.log();
|
|
1440
1688
|
console.log('📊 SDD Telemetry(嵌入在 skill 流程中,自动执行,无需配置):');
|
|
1441
|
-
|
|
1442
|
-
|
|
1689
|
+
if (specPackage) {
|
|
1690
|
+
console.log(` - 文档侧度量在 ${specPackage.name}/skywalk-sdd/events/`);
|
|
1691
|
+
} else {
|
|
1692
|
+
console.log(' - 度量数据自动采集到 skywalk-sdd/events/');
|
|
1693
|
+
}
|
|
1694
|
+
console.log(' - 运行 node skywalk-sdd/log.cjs metrics --project=<包裹包> 查看四维度指标');
|
|
1443
1695
|
console.log();
|
|
1444
1696
|
|
|
1445
1697
|
rl.close();
|
|
@@ -1458,6 +1710,10 @@ module.exports = {
|
|
|
1458
1710
|
deploySddConfigYaml,
|
|
1459
1711
|
deployDotSddYaml,
|
|
1460
1712
|
deployMonoSddYaml,
|
|
1713
|
+
populateSpecPackage,
|
|
1714
|
+
writeSddSpecRootHint,
|
|
1715
|
+
linkSkywalkToSpecPackage,
|
|
1716
|
+
deploySkywalkForwarders,
|
|
1461
1717
|
deployQualityGateTemplates,
|
|
1462
1718
|
deployTelemetryDataDir,
|
|
1463
1719
|
attachCodeRepoLite,
|