@sfmc-bds/cli 0.2.0-beta.7 → 0.2.0-beta.8
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/argv-parse.d.ts +0 -2
- package/dist/argv-parse.d.ts.map +1 -1
- package/dist/argv-parse.js +1 -5
- package/dist/argv-parse.js.map +2 -2
- package/dist/cli-gate.d.ts.map +1 -1
- package/dist/cli-gate.js +0 -2
- package/dist/cli-gate.js.map +2 -2
- package/dist/command-surface.d.ts +2 -12
- package/dist/command-surface.d.ts.map +1 -1
- package/dist/command-surface.js +2 -32
- package/dist/command-surface.js.map +2 -2
- package/dist/i18n/locales/en.d.ts +3 -25
- package/dist/i18n/locales/en.d.ts.map +1 -1
- package/dist/i18n/locales/en.js +3 -27
- package/dist/i18n/locales/en.js.map +2 -2
- package/dist/i18n/locales/zh-CN.d.ts.map +1 -1
- package/dist/i18n/locales/zh-CN.js +3 -27
- package/dist/i18n/locales/zh-CN.js.map +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -4
- package/dist/index.js.map +2 -2
- package/dist/main.js +3 -6
- package/dist/main.js.map +2 -2
- package/dist/module-commands.d.ts +5 -18
- package/dist/module-commands.d.ts.map +1 -1
- package/dist/module-commands.js +89 -87
- package/dist/module-commands.js.map +2 -2
- package/dist/module-pack-build.d.ts.map +1 -1
- package/dist/module-pack-build.js +4 -0
- package/dist/module-pack-build.js.map +2 -2
- package/dist/module-toggle.d.ts +33 -0
- package/dist/module-toggle.d.ts.map +1 -0
- package/dist/module-toggle.js +28 -0
- package/dist/module-toggle.js.map +7 -0
- package/dist/pack-lifecycle.d.ts.map +1 -1
- package/dist/pack-lifecycle.js +4 -0
- package/dist/pack-lifecycle.js.map +2 -2
- package/dist/remote-agent.js +5 -5
- package/dist/remote-agent.js.map +2 -2
- package/dist/repl.d.ts +0 -2
- package/dist/repl.d.ts.map +1 -1
- package/dist/repl.js +0 -9
- package/dist/repl.js.map +2 -2
- package/dist/runtime.d.ts +4 -13
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +15 -27
- package/dist/runtime.js.map +2 -2
- package/dist/services.d.ts +0 -2
- package/dist/services.d.ts.map +1 -1
- package/dist/services.js +0 -4
- package/dist/services.js.map +2 -2
- package/package.json +6 -6
- package/dist/module-publish.d.ts +0 -69
- package/dist/module-publish.d.ts.map +0 -1
- package/dist/module-publish.js +0 -478
- package/dist/module-publish.js.map +0 -7
- package/dist/module-watch.d.ts +0 -32
- package/dist/module-watch.d.ts.map +0 -1
- package/dist/module-watch.js +0 -171
- package/dist/module-watch.js.map +0 -7
package/dist/module-publish.js
DELETED
|
@@ -1,478 +0,0 @@
|
|
|
1
|
-
import { spawn } from "node:child_process";
|
|
2
|
-
import fs from "node:fs/promises";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import process from "node:process";
|
|
5
|
-
import { c } from "./theme.js";
|
|
6
|
-
import { t } from "./i18n/index.js";
|
|
7
|
-
const DEFAULT_GH_REPO = "Tanya7z/sfmc-modules";
|
|
8
|
-
function parsePublishFlags(args) {
|
|
9
|
-
const flags = {
|
|
10
|
-
dryRun: false,
|
|
11
|
-
bump: null,
|
|
12
|
-
customVersion: null,
|
|
13
|
-
scope: null,
|
|
14
|
-
skipIndexPr: false,
|
|
15
|
-
tag: "latest",
|
|
16
|
-
access: "public",
|
|
17
|
-
ghRepo: DEFAULT_GH_REPO,
|
|
18
|
-
ghPush: false,
|
|
19
|
-
ghForkRemote: "sfmc-modules-fork"
|
|
20
|
-
};
|
|
21
|
-
for (let i = 0; i < args.length; i++) {
|
|
22
|
-
const a = args[i];
|
|
23
|
-
if (a === "--dry-run") flags.dryRun = true;
|
|
24
|
-
else if (a === "--bump") flags.bump = args[++i] ?? null;
|
|
25
|
-
else if (a?.startsWith("--bump=")) flags.bump = a.slice("--bump=".length);
|
|
26
|
-
else if (a === "--scope") flags.scope = args[++i] ?? null;
|
|
27
|
-
else if (a?.startsWith("--scope=")) flags.scope = a.slice("--scope=".length);
|
|
28
|
-
else if (a === "--tag") flags.tag = args[++i] ?? "latest";
|
|
29
|
-
else if (a?.startsWith("--tag=")) flags.tag = a.slice("--tag=".length);
|
|
30
|
-
else if (a === "--skip-index-pr") flags.skipIndexPr = true;
|
|
31
|
-
else if (a === "--gh-repo") flags.ghRepo = args[++i] ?? DEFAULT_GH_REPO;
|
|
32
|
-
else if (a?.startsWith("--gh-repo=")) flags.ghRepo = a.slice("--gh-repo=".length);
|
|
33
|
-
else if (a === "--gh-push") flags.ghPush = true;
|
|
34
|
-
else if (a === "--gh-fork-remote") flags.ghForkRemote = args[++i] ?? "sfmc-modules-fork";
|
|
35
|
-
else if (a?.startsWith("--gh-fork-remote=")) flags.ghForkRemote = a.slice("--gh-fork-remote=".length);
|
|
36
|
-
else if (a === "--access" && (args[i + 1] === "public" || args[i + 1] === "restricted")) {
|
|
37
|
-
flags.access = args[++i];
|
|
38
|
-
} else if (a === "--access=public") flags.access = "public";
|
|
39
|
-
else if (a === "--access=restricted") flags.access = "restricted";
|
|
40
|
-
else if (a === "--help" || a === "-h") return flags;
|
|
41
|
-
}
|
|
42
|
-
return flags;
|
|
43
|
-
}
|
|
44
|
-
function runNpm(args, opts = {}) {
|
|
45
|
-
const isWin = process.platform === "win32";
|
|
46
|
-
const cmd = isWin ? "cmd.exe" : "npm";
|
|
47
|
-
const fullArgs = isWin ? ["/c", "npm", ...args] : args;
|
|
48
|
-
return new Promise((resolve) => {
|
|
49
|
-
const proc = spawn(cmd, fullArgs, {
|
|
50
|
-
cwd: opts.cwd ?? process.cwd(),
|
|
51
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
52
|
-
env: process.env
|
|
53
|
-
});
|
|
54
|
-
let stdout = "";
|
|
55
|
-
let stderr = "";
|
|
56
|
-
proc.stdout?.on("data", (d) => {
|
|
57
|
-
stdout += d.toString();
|
|
58
|
-
});
|
|
59
|
-
proc.stderr?.on("data", (d) => {
|
|
60
|
-
stderr += d.toString();
|
|
61
|
-
});
|
|
62
|
-
proc.on("exit", (code) => resolve({ code, stdout, stderr }));
|
|
63
|
-
proc.on("error", (e) => resolve({ code: -1, stdout, stderr: `${stderr}${e.message}` }));
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
async function detectNpmUser() {
|
|
67
|
-
const r = await runNpm(["whoami"]);
|
|
68
|
-
if (r.code === 0) {
|
|
69
|
-
const user = (r.stdout || r.stderr).trim().split(/\r?\n/)[0] ?? "";
|
|
70
|
-
if (user) return { ok: true, user };
|
|
71
|
-
return { ok: false, stderr: "npm whoami \u65E0\u8F93\u51FA" };
|
|
72
|
-
}
|
|
73
|
-
return { ok: false, stderr: r.stderr.trim() || "npm whoami \u5931\u8D25" };
|
|
74
|
-
}
|
|
75
|
-
function defaultScopeFor(user) {
|
|
76
|
-
return user.startsWith("@") ? user.slice(1) : user;
|
|
77
|
-
}
|
|
78
|
-
function translateNpmPublishError(pkgName, stderr) {
|
|
79
|
-
const text = String(stderr || "");
|
|
80
|
-
if (/ENEEDAUTH|not logged in/i.test(text)) {
|
|
81
|
-
return `[publish] \u672A\u767B\u5F55 npm\u3002\u8FD0\u884C \`npm login --auth-type=web\` \u540E\u91CD\u8BD5\uFF1B\u6216\u4E34\u65F6\u8BBE NPM_TOKEN\u3002`;
|
|
82
|
-
}
|
|
83
|
-
if (/EOTP|one-time password/i.test(text)) {
|
|
84
|
-
return `[publish] \u9700\u8981 2FA \u7801\u3002\u5728\u7EC8\u7AEF\u8F93\u5165 OTP\uFF08\u63A8\u8350\u7528 WebAuthn / security key\uFF09\u3002`;
|
|
85
|
-
}
|
|
86
|
-
if (/need to confirm/i.test(text) || /Confirm email/i.test(text)) {
|
|
87
|
-
return `[publish] \u9996\u6B21\u5728\u8BE5 scope \u53D1\u5305\uFF1Bnpm \u8981\u6C42\u90AE\u7BB1\u786E\u8BA4\u3002\u6253\u5F00 https://www.npmjs.com/settings/<yourname>/ \u786E\u8BA4\u90AE\u7BB1\u540E\u91CD\u8BD5\u3002`;
|
|
88
|
-
}
|
|
89
|
-
if (/You do not have permission to publish/i.test(text)) {
|
|
90
|
-
return `[publish] \u65E0\u6743\u9650\u53D1\u5230 "${pkgName}"\u3002\u5E38\u89C1\u539F\u56E0\uFF1A(a) \u4F60\u9996\u6B21\u5728\u8BE5 scope \u53D1\u5305\u3001\u90AE\u7BB1\u672A\u786E\u8BA4\uFF1B(b) \u5305\u540D\u5DF2\u88AB\u4ED6\u4EBA\u5360\u7528\u3002`;
|
|
91
|
-
}
|
|
92
|
-
if (/402 Payment Required/i.test(text)) {
|
|
93
|
-
return `[publish] \u79C1\u6709\u5305\u9700\u8981\u4ED8\u8D39 npm \u8D26\u53F7\u3002\u6539\u7528 \`--access public\` \u6216\u6362\u516C\u5F00 scope\u3002`;
|
|
94
|
-
}
|
|
95
|
-
if (/Package name too similar/i.test(text)) {
|
|
96
|
-
return `[publish] \u5305\u540D\u592A\u63A5\u8FD1\u5DF2\u5B58\u5728\u5305\uFF1B\u5EFA\u8BAE\u6539\u540D\uFF08rename \u811A\u672C\u5DF2\u5728\u6A21\u677F\u4ED3\u63D0\u4F9B\uFF09\u3002`;
|
|
97
|
-
}
|
|
98
|
-
if (/ERESOLVE/i.test(text)) {
|
|
99
|
-
return `[publish] \u4F9D\u8D56\u51B2\u7A81\uFF08ERESOLVE\uFF09\u3002\u63D0\u793A\uFF1A\u7528 --legacy-peer-deps \u91CD\u8BD5\uFF0C\u6216\u786E\u8BA4 SDK/\u5BBF\u4E3B\u7248\u672C\u517C\u5BB9\u3002`;
|
|
100
|
-
}
|
|
101
|
-
if (/ETIMEDOUT|ECONNRESET|ENOTFOUND/i.test(text)) {
|
|
102
|
-
return `[publish] npm \u7F51\u7EDC\u9519\u8BEF\u3002\u68C0\u67E5\u4EE3\u7406 / \u7F51\u7EDC\uFF1B\u6216\u79BB\u7EBF\u7528 \`sfmc mod install --from local:./x.tgz\`\u3002`;
|
|
103
|
-
}
|
|
104
|
-
return `[publish] npm publish ${pkgName} \u5931\u8D25\uFF1A
|
|
105
|
-
${text.trim()}`;
|
|
106
|
-
}
|
|
107
|
-
async function runPrecheck(cwd) {
|
|
108
|
-
const warnings = [];
|
|
109
|
-
const errors = [];
|
|
110
|
-
const manifestPath = path.join(cwd, "sapi", "manifest.json");
|
|
111
|
-
try {
|
|
112
|
-
const text = await fs.readFile(manifestPath, "utf8");
|
|
113
|
-
const manifest = JSON.parse(text);
|
|
114
|
-
if (manifest.schemaVersion !== 2) errors.push(`manifest schemaVersion \u5FC5\u987B\u662F 2\uFF08\u5F53\u524D ${manifest.schemaVersion ?? "\u672A\u8BBE\u7F6E"}\uFF09`);
|
|
115
|
-
if (!manifest.id) errors.push("manifest.id \u7F3A\u5931");
|
|
116
|
-
if (!manifest.configKey) errors.push("manifest.configKey \u7F3A\u5931");
|
|
117
|
-
} catch (e) {
|
|
118
|
-
errors.push(`manifest.json \u8BFB\u53D6\u5931\u8D25: ${e.message}`);
|
|
119
|
-
}
|
|
120
|
-
try {
|
|
121
|
-
const pkg = JSON.parse(await fs.readFile(path.join(cwd, "package.json"), "utf8"));
|
|
122
|
-
if (!pkg.name) errors.push("package.json#name \u7F3A\u5931");
|
|
123
|
-
if (pkg.private === true) {
|
|
124
|
-
errors.push(`package.json private=true\uFF0C\u65E0\u6CD5 npm publish\uFF1B\u8BF7\u5220\u9664 private \u5B57\u6BB5`);
|
|
125
|
-
}
|
|
126
|
-
if (typeof pkg.name === "string" && pkg.name.startsWith("@sfmc-bds/") && !process.env.SFMC_OFFICIAL_PUBLISH) {
|
|
127
|
-
errors.push(
|
|
128
|
-
`\u7981\u6B62\u5411 @sfmc-bds/* \u53D1\u5305\uFF08\u975E\u5B98\u65B9\uFF09\u3002\u8BF7\u6539\u7528 @<user>/sfmc-module-<id>\uFF0C\u6216\u8BBE\u7F6E SFMC_OFFICIAL_PUBLISH=1`
|
|
129
|
-
);
|
|
130
|
-
}
|
|
131
|
-
if (!Array.isArray(pkg.files) || !pkg.files.includes("sapi")) {
|
|
132
|
-
warnings.push(`package.json#files \u4E0D\u542B "sapi"\uFF1Bnpm pack \u4F1A\u6253\u51FA\u7A7A tarball\u3002\u5EFA\u8BAE\u52A0 ["sapi", "test"]\u3002`);
|
|
133
|
-
}
|
|
134
|
-
} catch (e) {
|
|
135
|
-
errors.push(`package.json \u8BFB\u53D6\u5931\u8D25: ${e.message}`);
|
|
136
|
-
}
|
|
137
|
-
const r = await runNpm(["pack", "--dry-run"], { cwd });
|
|
138
|
-
const tarballFiles = parseTarballListing(r.stdout);
|
|
139
|
-
if (r.code !== 0) {
|
|
140
|
-
errors.push(`npm pack --dry-run \u5931\u8D25\uFF1A${r.stderr.trim()}`);
|
|
141
|
-
}
|
|
142
|
-
const mustHave = ["package/package.json"];
|
|
143
|
-
for (const f of mustHave) {
|
|
144
|
-
if (!tarballFiles.some((t2) => t2.endsWith(f))) {
|
|
145
|
-
warnings.push(`tarball \u7F3A\u5C11\u5173\u952E\u6587\u4EF6 ${f}\uFF08npm pack \u884C\u4E3A\u5F02\u5E38\uFF09`);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
return { ok: errors.length === 0, warnings, errors, tarballFiles };
|
|
149
|
-
}
|
|
150
|
-
function parseTarballListing(stdout) {
|
|
151
|
-
const files = [];
|
|
152
|
-
const re = /^npm notice\s+Filename:\s+(.+)$/gm;
|
|
153
|
-
for (const m of stdout.matchAll(re)) files.push(m[1].trim());
|
|
154
|
-
return files;
|
|
155
|
-
}
|
|
156
|
-
function bumpSemver(current, level, custom) {
|
|
157
|
-
if (level === "custom" && custom) {
|
|
158
|
-
if (!/^\d+\.\d+\.\d+(-[\w.]+)?$/.test(custom)) {
|
|
159
|
-
throw new Error(`invalid custom version: ${custom}`);
|
|
160
|
-
}
|
|
161
|
-
return custom;
|
|
162
|
-
}
|
|
163
|
-
const m = /^(\d+)\.(\d+)\.(\d+)/.exec(current);
|
|
164
|
-
if (!m) throw new Error(`\u65E0\u6CD5\u89E3\u6790\u5F53\u524D\u7248\u672C: ${current}`);
|
|
165
|
-
const [maj, min, pat] = [Number(m[1]), Number(m[2]), Number(m[3])];
|
|
166
|
-
if (level === "major") return `${maj + 1}.0.0`;
|
|
167
|
-
if (level === "minor") return `${maj}.${min + 1}.0`;
|
|
168
|
-
if (level === "patch") return `${maj}.${min}.${pat + 1}`;
|
|
169
|
-
throw new Error(`bump level \u7F3A\u5931\u6216\u65E0\u6548: ${String(level)}`);
|
|
170
|
-
}
|
|
171
|
-
async function writePackageVersion(cwd, next) {
|
|
172
|
-
const pkgPath = path.join(cwd, "package.json");
|
|
173
|
-
const pkg = JSON.parse(await fs.readFile(pkgPath, "utf8"));
|
|
174
|
-
pkg.version = next;
|
|
175
|
-
await fs.writeFile(pkgPath, `${JSON.stringify(pkg, null, 2)}
|
|
176
|
-
`, "utf8");
|
|
177
|
-
}
|
|
178
|
-
async function readPackageVersion(cwd) {
|
|
179
|
-
const pkg = JSON.parse(await fs.readFile(path.join(cwd, "package.json"), "utf8"));
|
|
180
|
-
return pkg.version ?? "0.0.0";
|
|
181
|
-
}
|
|
182
|
-
async function runNpmPublish(cwd, pkgName, flags) {
|
|
183
|
-
const args = ["publish", "--access", flags.access, "--tag", flags.tag];
|
|
184
|
-
if (flags.dryRun) args.push("--dry-run");
|
|
185
|
-
const r = await runNpm(args, { cwd });
|
|
186
|
-
const msg = r.code === 0 ? r.stdout.trim() : translateNpmPublishError(pkgName, r.stderr);
|
|
187
|
-
return { ok: r.code === 0, code: r.code, message: msg };
|
|
188
|
-
}
|
|
189
|
-
function runGh(args, opts = {}) {
|
|
190
|
-
const isWin = process.platform === "win32";
|
|
191
|
-
const cmd = isWin ? "gh.exe" : "gh";
|
|
192
|
-
return new Promise((resolve) => {
|
|
193
|
-
const proc = spawn(cmd, args, {
|
|
194
|
-
cwd: opts.cwd ?? process.cwd(),
|
|
195
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
196
|
-
env: process.env
|
|
197
|
-
});
|
|
198
|
-
let stdout = "";
|
|
199
|
-
let stderr = "";
|
|
200
|
-
proc.stdout?.on("data", (d) => {
|
|
201
|
-
stdout += d.toString();
|
|
202
|
-
});
|
|
203
|
-
proc.stderr?.on("data", (d) => {
|
|
204
|
-
stderr += d.toString();
|
|
205
|
-
});
|
|
206
|
-
if (opts.stdin) proc.stdin.write(opts.stdin);
|
|
207
|
-
proc.stdin?.end();
|
|
208
|
-
proc.on("exit", (code) => resolve({ code, stdout, stderr }));
|
|
209
|
-
proc.on("error", (e) => resolve({ code: -1, stdout, stderr: `${stderr}${e.message}` }));
|
|
210
|
-
});
|
|
211
|
-
}
|
|
212
|
-
async function ghAuthStatus() {
|
|
213
|
-
const r = await runGh(["auth", "status"]);
|
|
214
|
-
if (r.code !== 0) return { ok: false, user: "", error: r.stderr.trim() || "gh auth \u5931\u8D25" };
|
|
215
|
-
const m = /(?:as|account)\s+([\w-]+)/i.exec(r.stdout + r.stderr);
|
|
216
|
-
return { ok: true, user: m?.[1] ?? "", error: "" };
|
|
217
|
-
}
|
|
218
|
-
function splitOwnerRepo(s) {
|
|
219
|
-
const m = /^([\w.-]+)\/([\w.-]+)$/.exec(s.trim());
|
|
220
|
-
return m ? [m[1], m[2]] : null;
|
|
221
|
-
}
|
|
222
|
-
function indexEntryFor(pkgName, version, sdkRange = ">=0.2.0") {
|
|
223
|
-
const npmPkg = pkgName.startsWith("@") ? pkgName : `@${pkgName}`;
|
|
224
|
-
let id;
|
|
225
|
-
if (npmPkg.includes("/")) {
|
|
226
|
-
id = npmPkg.split("/").pop().replace(/^module-/, "").replace(/^sfmc-module-/, "");
|
|
227
|
-
} else {
|
|
228
|
-
id = npmPkg.replace(/^module-/, "").replace(/^sfmc-module-/, "");
|
|
229
|
-
}
|
|
230
|
-
return { id, npm: npmPkg, version, sdk: sdkRange, timestamp: Date.now() };
|
|
231
|
-
}
|
|
232
|
-
async function openIndexPr(pkgName, version, opts) {
|
|
233
|
-
if (opts.skipIndexPr) {
|
|
234
|
-
return { ok: true, skipped: true, intent: [], message: "\u5DF2\u8DF3\u8FC7\u8584 index PR\uFF08--skip-index-pr\uFF09" };
|
|
235
|
-
}
|
|
236
|
-
const target = splitOwnerRepo(opts.ghRepo);
|
|
237
|
-
if (!target) return { ok: false, skipped: false, intent: [], message: `[publish] --gh-repo \u975E\u6CD5: ${opts.ghRepo}\uFF08\u9700 OWNER/REPO\uFF09` };
|
|
238
|
-
const [owner, repo] = target;
|
|
239
|
-
const entry = indexEntryFor(pkgName, version);
|
|
240
|
-
const branchName = `publish/${entry.id}-${version}`;
|
|
241
|
-
const title = `chore(index): ${entry.id}@${version}`;
|
|
242
|
-
const body = [
|
|
243
|
-
`Automated PR from \`sfmc mod publish\`.`,
|
|
244
|
-
``,
|
|
245
|
-
`- npm: \`${entry.npm}\``,
|
|
246
|
-
`- version: \`${entry.version}\``,
|
|
247
|
-
`- sdk: \`${entry.sdk}\``
|
|
248
|
-
].join("\n");
|
|
249
|
-
const intent = [
|
|
250
|
-
`gh repo fork ${owner}/${repo} --remote-name=${opts.ghForkRemote} --clone=false`,
|
|
251
|
-
`gh repo clone ${opts.ghForkRemote}/${repo} fork-workdir -- --depth=1`,
|
|
252
|
-
`cd fork-workdir`,
|
|
253
|
-
`git checkout -b ${branchName}`,
|
|
254
|
-
`edit index.json (upsert ${entry.id}: { npm=${entry.npm}, version=${entry.version}, sdk="${entry.sdk}" })`,
|
|
255
|
-
`git add index.json && git commit -m "${title}"`,
|
|
256
|
-
`git push -u ${opts.ghForkRemote} ${branchName}`,
|
|
257
|
-
`gh pr create --repo ${owner}/${repo} --head ${opts.ghForkRemote}:${branchName} --title "${title}" --body "${body}"`
|
|
258
|
-
];
|
|
259
|
-
if (!opts.ghPush) {
|
|
260
|
-
return {
|
|
261
|
-
ok: true,
|
|
262
|
-
skipped: false,
|
|
263
|
-
intent,
|
|
264
|
-
message: `[publish] dry-run\uFF1A\u5C06\u5411 ${owner}/${repo} \u5F00 PR \u767B\u8BB0 ${entry.id}@${version}\uFF08\u52A0 --gh-push \u771F\u6267\u884C\uFF09`
|
|
265
|
-
};
|
|
266
|
-
}
|
|
267
|
-
const auth = await ghAuthStatus();
|
|
268
|
-
if (!auth.ok) {
|
|
269
|
-
return {
|
|
270
|
-
ok: false,
|
|
271
|
-
skipped: false,
|
|
272
|
-
intent,
|
|
273
|
-
message: `[publish] gh \u672A\u767B\u5F55\uFF1A${auth.error}
|
|
274
|
-
\u2192 \`gh auth login\` \u540E\u91CD\u8BD5\uFF0C\u6216\u7701\u7565 --gh-push \u4EC5 dry-run`
|
|
275
|
-
};
|
|
276
|
-
}
|
|
277
|
-
const forkRes = await runGh(["repo", "fork", `${owner}/${repo}`, `--remote-name=${opts.ghForkRemote}`, "--clone=false"]);
|
|
278
|
-
if (forkRes.code !== 0 && !/already exists/i.test(forkRes.stderr)) {
|
|
279
|
-
return { ok: false, skipped: false, intent, message: `[publish] gh fork \u5931\u8D25\uFF1A${forkRes.stderr.trim()}` };
|
|
280
|
-
}
|
|
281
|
-
const os = await import("node:os");
|
|
282
|
-
const fsSync = await import("node:fs");
|
|
283
|
-
const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "sfmc-index-"));
|
|
284
|
-
const clone = await runGh(["repo", "clone", `${auth.user}/${repo}`, tmp, "--", "--depth=1"]);
|
|
285
|
-
if (clone.code !== 0) return { ok: false, skipped: false, intent, message: `[publish] gh clone \u5931\u8D25\uFF1A${clone.stderr.trim()}` };
|
|
286
|
-
const br = await runGh(["repo", "sync"], { cwd: tmp });
|
|
287
|
-
void br;
|
|
288
|
-
const branchRes = await spawnBranch(tmp, branchName);
|
|
289
|
-
if (branchRes.code !== 0) {
|
|
290
|
-
fsSync.rmSync(tmp, { recursive: true, force: true });
|
|
291
|
-
return { ok: false, skipped: false, intent, message: `[publish] branch \u521B\u5EFA\u5931\u8D25\uFF1A${branchRes.stderr.trim()}` };
|
|
292
|
-
}
|
|
293
|
-
const indexPath = path.join(tmp, "index.json");
|
|
294
|
-
const patchRes = await patchIndexFile(indexPath, entry);
|
|
295
|
-
if (!patchRes.ok) {
|
|
296
|
-
fsSync.rmSync(tmp, { recursive: true, force: true });
|
|
297
|
-
return { ok: false, skipped: false, intent, message: `[publish] patch index.json \u5931\u8D25\uFF1A${patchRes.error}` };
|
|
298
|
-
}
|
|
299
|
-
const commitRes = await runGh(["api", "-X", "POST", "--input", "-"], {
|
|
300
|
-
cwd: tmp
|
|
301
|
-
/* 委托 git 直 commit,避免 gh api 没有该 endpoint */
|
|
302
|
-
}).catch(() => ({ code: 0, stdout: "", stderr: "" }));
|
|
303
|
-
void commitRes;
|
|
304
|
-
const gitCommit = await spawnGit(tmp, ["add", "index.json"]);
|
|
305
|
-
if (gitCommit.code !== 0) {
|
|
306
|
-
fsSync.rmSync(tmp, { recursive: true, force: true });
|
|
307
|
-
return { ok: false, skipped: false, intent, message: `[publish] git add \u5931\u8D25\uFF1A${gitCommit.stderr.trim()}` };
|
|
308
|
-
}
|
|
309
|
-
const gitCommitMsg = await spawnGit(tmp, ["commit", "-m", title]);
|
|
310
|
-
if (gitCommitMsg.code !== 0) {
|
|
311
|
-
fsSync.rmSync(tmp, { recursive: true, force: true });
|
|
312
|
-
return { ok: false, skipped: false, intent, message: `[publish] git commit \u5931\u8D25\uFF1A${gitCommitMsg.stderr.trim()}` };
|
|
313
|
-
}
|
|
314
|
-
const gitPush = await spawnGit(tmp, ["push", opts.ghForkRemote, branchName]);
|
|
315
|
-
if (gitPush.code !== 0) {
|
|
316
|
-
fsSync.rmSync(tmp, { recursive: true, force: true });
|
|
317
|
-
return { ok: false, skipped: false, intent, message: `[publish] git push \u5931\u8D25\uFF1A${gitPush.stderr.trim()}` };
|
|
318
|
-
}
|
|
319
|
-
const pr = await runGh([
|
|
320
|
-
"pr",
|
|
321
|
-
"create",
|
|
322
|
-
"--repo",
|
|
323
|
-
`${owner}/${repo}`,
|
|
324
|
-
"--head",
|
|
325
|
-
`${auth.user}:${branchName}`,
|
|
326
|
-
"--title",
|
|
327
|
-
title,
|
|
328
|
-
"--body",
|
|
329
|
-
body
|
|
330
|
-
], { cwd: tmp });
|
|
331
|
-
fsSync.rmSync(tmp, { recursive: true, force: true });
|
|
332
|
-
if (pr.code !== 0) {
|
|
333
|
-
return { ok: false, skipped: false, intent, message: `[publish] gh pr create \u5931\u8D25\uFF1A${pr.stderr.trim()}` };
|
|
334
|
-
}
|
|
335
|
-
const prUrl = pr.stdout.trim().split(/\r?\n/).pop() ?? "";
|
|
336
|
-
return { ok: true, skipped: false, intent, message: `[publish] \u8584 index PR \u5DF2\u5F00\uFF1A${prUrl || "\uFF08\u8BF7\u5230 GitHub \u67E5\u770B\uFF09"}`, prUrl };
|
|
337
|
-
}
|
|
338
|
-
function spawnGit(cwd, args) {
|
|
339
|
-
return new Promise((resolve) => {
|
|
340
|
-
const proc = spawn("git", args, { cwd, stdio: ["ignore", "pipe", "pipe"], env: process.env });
|
|
341
|
-
let stdout = "";
|
|
342
|
-
let stderr = "";
|
|
343
|
-
proc.stdout?.on("data", (d) => {
|
|
344
|
-
stdout += d.toString();
|
|
345
|
-
});
|
|
346
|
-
proc.stderr?.on("data", (d) => {
|
|
347
|
-
stderr += d.toString();
|
|
348
|
-
});
|
|
349
|
-
proc.on("exit", (code) => resolve({ code, stdout, stderr }));
|
|
350
|
-
proc.on("error", (e) => resolve({ code: -1, stdout, stderr: `${stderr}${e.message}` }));
|
|
351
|
-
});
|
|
352
|
-
}
|
|
353
|
-
async function spawnBranch(cwd, branch) {
|
|
354
|
-
return spawnGit(cwd, ["checkout", "-b", branch]);
|
|
355
|
-
}
|
|
356
|
-
async function patchIndexFile(indexPath, entry) {
|
|
357
|
-
let version = 2;
|
|
358
|
-
const modules = {};
|
|
359
|
-
try {
|
|
360
|
-
const text = await fs.readFile(indexPath, "utf8");
|
|
361
|
-
const parsed = JSON.parse(text);
|
|
362
|
-
if (typeof parsed.version === "number") version = Math.max(2, parsed.version);
|
|
363
|
-
if (parsed.modules && !Array.isArray(parsed.modules) && typeof parsed.modules === "object") {
|
|
364
|
-
Object.assign(modules, parsed.modules);
|
|
365
|
-
} else if (Array.isArray(parsed.modules)) {
|
|
366
|
-
for (const m of parsed.modules) {
|
|
367
|
-
if (m && typeof m === "object" && typeof m.id === "string") {
|
|
368
|
-
const { id, ...rest } = m;
|
|
369
|
-
modules[id] = rest;
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
} catch {
|
|
374
|
-
}
|
|
375
|
-
if (modules[entry.id]) {
|
|
376
|
-
return { ok: false, error: `${entry.id} \u5DF2\u5728 index.json \u4E2D\u5B58\u5728\uFF1B\u8BF7\u624B\u52A8\u68C0\u67E5\u540E\u518D publish` };
|
|
377
|
-
}
|
|
378
|
-
modules[entry.id] = {
|
|
379
|
-
npm: entry.npm,
|
|
380
|
-
version: entry.version,
|
|
381
|
-
sdk: entry.sdk,
|
|
382
|
-
timestamp: entry.timestamp
|
|
383
|
-
};
|
|
384
|
-
const sorted = {};
|
|
385
|
-
for (const k of Object.keys(modules).sort()) sorted[k] = modules[k];
|
|
386
|
-
await fs.mkdir(path.dirname(indexPath), { recursive: true });
|
|
387
|
-
await fs.writeFile(indexPath, `${JSON.stringify({ version, modules: sorted }, null, 2)}
|
|
388
|
-
`, "utf8");
|
|
389
|
-
return { ok: true };
|
|
390
|
-
}
|
|
391
|
-
async function cmdModulePublish(args) {
|
|
392
|
-
const flags = parsePublishFlags(args);
|
|
393
|
-
const out = [];
|
|
394
|
-
const cwd = process.cwd();
|
|
395
|
-
out.push(c.bold(t("publish.banner")));
|
|
396
|
-
const who = await detectNpmUser();
|
|
397
|
-
if (!who.ok) {
|
|
398
|
-
out.push(c.red(t("publish.noLogin")));
|
|
399
|
-
out.push(" " + who.stderr.split("\n")[0]);
|
|
400
|
-
out.push(c.dim(t("publish.noLoginHint")));
|
|
401
|
-
return out.join("\n") + "\n";
|
|
402
|
-
}
|
|
403
|
-
out.push(c.green(`[publish] npm \u5DF2\u767B\u5F55: ${who.user}`));
|
|
404
|
-
const scope = (flags.scope ?? who.user).replace(/^@/, "");
|
|
405
|
-
out.push(c.dim(`[publish] \u9ED8\u8BA4 scope: @${scope}`));
|
|
406
|
-
const pkgJson = JSON.parse(await fs.readFile(path.join(cwd, "package.json"), "utf8"));
|
|
407
|
-
const pkgName = pkgJson.name ?? `${scope}/sfmc-module-?`;
|
|
408
|
-
out.push(`[publish] \u5F53\u524D\u5305\u540D: ${pkgName}`);
|
|
409
|
-
const pre = await runPrecheck(cwd);
|
|
410
|
-
for (const w of pre.warnings) out.push(c.yellow(`[publish] warn: ${w}`));
|
|
411
|
-
for (const e of pre.errors) out.push(c.red(`[publish] error: ${e}`));
|
|
412
|
-
if (!pre.ok) {
|
|
413
|
-
out.push(c.red(t("publish.precheckFail")));
|
|
414
|
-
return out.join("\n") + "\n";
|
|
415
|
-
}
|
|
416
|
-
out.push(c.green(`[publish] precheck OK\uFF08${pre.tarballFiles.length} \u6587\u4EF6\u5165\u5305\uFF09`));
|
|
417
|
-
if (flags.dryRun) {
|
|
418
|
-
out.push(c.dim(t("publish.dryRun.summary")));
|
|
419
|
-
return out.join("\n") + "\n";
|
|
420
|
-
}
|
|
421
|
-
const currentVer = await readPackageVersion(cwd);
|
|
422
|
-
let nextVer = currentVer;
|
|
423
|
-
if (flags.bump) {
|
|
424
|
-
try {
|
|
425
|
-
nextVer = bumpSemver(currentVer, flags.bump, flags.customVersion);
|
|
426
|
-
} catch (e) {
|
|
427
|
-
out.push(c.red(`[publish] bump \u5931\u8D25: ${e.message}`));
|
|
428
|
-
return out.join("\n") + "\n";
|
|
429
|
-
}
|
|
430
|
-
await writePackageVersion(cwd, nextVer);
|
|
431
|
-
out.push(c.green(`[publish] \u7248\u672C bump: ${currentVer} \u2192 ${nextVer}`));
|
|
432
|
-
} else {
|
|
433
|
-
out.push(c.dim(`[publish] \u5F53\u524D\u7248\u672C ${currentVer}\uFF08\u672A bump\uFF1B\u82E5\u5DF2\u53D1\u5E03\u8FC7\u76F8\u540C\u7248\u672C npm \u4F1A 409\uFF09`));
|
|
434
|
-
}
|
|
435
|
-
const pub = await runNpmPublish(cwd, pkgName, flags);
|
|
436
|
-
out.push(pub.message);
|
|
437
|
-
if (!pub.ok) {
|
|
438
|
-
if (flags.bump && nextVer !== currentVer) {
|
|
439
|
-
try {
|
|
440
|
-
await writePackageVersion(cwd, currentVer);
|
|
441
|
-
out.push(c.dim(`[publish] \u5DF2\u56DE\u6EDA package.json#version: ${nextVer} \u2192 ${currentVer}`));
|
|
442
|
-
} catch {
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
return out.join("\n") + "\n";
|
|
446
|
-
}
|
|
447
|
-
const pr = await openIndexPr(pkgName, nextVer, {
|
|
448
|
-
dryRun: flags.dryRun,
|
|
449
|
-
skipIndexPr: flags.skipIndexPr,
|
|
450
|
-
ghPush: flags.ghPush,
|
|
451
|
-
ghRepo: flags.ghRepo,
|
|
452
|
-
ghForkRemote: flags.ghForkRemote
|
|
453
|
-
});
|
|
454
|
-
out.push(pr.message);
|
|
455
|
-
if (!pr.ok && !pr.skipped) {
|
|
456
|
-
out.push(c.yellow(`[publish] \u6CE8\u610F\uFF1A\u8584 index PR \u5931\u8D25\uFF0C\u4F46 npm \u5305\u5DF2\u53D1\u5E03\uFF1B\u53EF\u624B\u52A8\u8865 index.json\u3002`));
|
|
457
|
-
}
|
|
458
|
-
out.push(c.green(t("publish.done")));
|
|
459
|
-
return out.join("\n") + "\n";
|
|
460
|
-
}
|
|
461
|
-
export {
|
|
462
|
-
DEFAULT_GH_REPO,
|
|
463
|
-
bumpSemver,
|
|
464
|
-
cmdModulePublish,
|
|
465
|
-
defaultScopeFor,
|
|
466
|
-
detectNpmUser,
|
|
467
|
-
indexEntryFor,
|
|
468
|
-
openIndexPr,
|
|
469
|
-
parsePublishFlags,
|
|
470
|
-
patchIndexFile,
|
|
471
|
-
readPackageVersion,
|
|
472
|
-
runNpmPublish,
|
|
473
|
-
runPrecheck,
|
|
474
|
-
splitOwnerRepo,
|
|
475
|
-
translateNpmPublishError,
|
|
476
|
-
writePackageVersion
|
|
477
|
-
};
|
|
478
|
-
//# sourceMappingURL=module-publish.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/module-publish.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * sfmc/src/module-publish.ts \u2014 `sfmc mod publish` \u4FDD\u59C6\u5F0F CLI\n *\n * \u8BBE\u8BA1\u539F\u5219\uFF08plan\uFF09\uFF1A\n * - \u4E0D\u53D1\u660E npm \u9274\u6743/\u534F\u8BAE\uFF1BCLI \u662F npm publish \u7684\u7F16\u6392\u5668 + \u68C0\u67E5\u5668 + \u9519\u8BEF\u7FFB\u8BD1\u3002\n * - \u4F5C\u8005\u7528\u81EA\u5DF1 npm \u8D26\u53F7 + \u81EA\u5DF1 scope\uFF08\u5982 @<username>/sfmc-module-<id>\uFF09\u3002\n * - \u4E0D\u66FF\u8EAB npm \u4EFB\u4F55\u884C\u4E3A\uFF1B\u5E38\u89C1 npm \u9519\u8BEF\u7FFB\u8BD1\u6210\u4E2D\u6587\u53EF\u8BFB + \u4E0B\u4E00\u6B65\u52A8\u4F5C\u3002\n *\n * \u6D41\u6C34\u7EBF\uFF1A\n * 0) npm whoami \u68C0\u6D4B\u767B\u5F55\u6001\n * 1) scope \u63A8\u65AD\uFF08\u4ECE npm whoami \u53D6\u8D26\u53F7\uFF1B\u7F3A\u5219 --scope \u8986\u76D6\uFF09\n * 2) dry-run \u9884\u68C0\uFF08manifest v2 + files + tarball \u5185\u5BB9\u6E05\u5355\uFF09\n * 3) version bump\uFF08patch|minor|major|custom\uFF1B\u5199\u5165 package.json\uFF0C**\u4E0D\u6539** manifest\uFF09\n * 4) npm publish\uFF08\u900F\u4F20 --access public --provenance\uFF1B\u79C1\u6709\u6539 --access restricted\uFF09\n * 5) \u8584 index PR\uFF08\u9664\u975E --skip-index-pr\uFF1B\u7528 gh api \u5728 sfmc-modules \u4ED3\u5F00 PR\uFF09\n */\nimport { spawn } from \"node:child_process\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport process from \"node:process\";\nimport { c } from \"./theme.js\";\nimport { t } from \"./i18n/index.js\";\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * CLI \u53C2\u6570\u89E3\u6790\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\nexport interface PublishFlags {\n dryRun: boolean;\n bump: \"patch\" | \"minor\" | \"major\" | \"custom\" | null;\n customVersion: string | null;\n scope: string | null;\n skipIndexPr: boolean;\n tag: string;\n access: \"public\" | \"restricted\";\n /* \u8584 index PR */\n ghRepo: string; /* OWNER/REPO\uFF1B\u9ED8\u8BA4 Tanya7z/sfmc-modules */\n ghPush: boolean; /* \u663E\u5F0F opt-in\uFF1A\u771F\u53BB fork + branch + PR\uFF1B\u5426\u5219\u53EA\u6253\u5370\u610F\u56FE */\n ghForkRemote: string; /* fork \u7684 remote \u540D\uFF0C\u9ED8\u8BA4 sfmc-modules-fork */\n}\n\nexport const DEFAULT_GH_REPO = \"Tanya7z/sfmc-modules\";\n\nexport function parsePublishFlags(args: string[]): PublishFlags {\n const flags: PublishFlags = {\n dryRun: false,\n bump: null,\n customVersion: null,\n scope: null,\n skipIndexPr: false,\n tag: \"latest\",\n access: \"public\",\n ghRepo: DEFAULT_GH_REPO,\n ghPush: false,\n ghForkRemote: \"sfmc-modules-fork\",\n };\n for (let i = 0; i < args.length; i++) {\n const a = args[i];\n if (a === \"--dry-run\") flags.dryRun = true;\n else if (a === \"--bump\") flags.bump = (args[++i] as PublishFlags[\"bump\"]) ?? null;\n else if (a?.startsWith(\"--bump=\")) flags.bump = a.slice(\"--bump=\".length) as PublishFlags[\"bump\"];\n else if (a === \"--scope\") flags.scope = args[++i] ?? null;\n else if (a?.startsWith(\"--scope=\")) flags.scope = a.slice(\"--scope=\".length);\n else if (a === \"--tag\") flags.tag = args[++i] ?? \"latest\";\n else if (a?.startsWith(\"--tag=\")) flags.tag = a.slice(\"--tag=\".length);\n else if (a === \"--skip-index-pr\") flags.skipIndexPr = true;\n else if (a === \"--gh-repo\") flags.ghRepo = args[++i] ?? DEFAULT_GH_REPO;\n else if (a?.startsWith(\"--gh-repo=\")) flags.ghRepo = a.slice(\"--gh-repo=\".length);\n else if (a === \"--gh-push\") flags.ghPush = true;\n else if (a === \"--gh-fork-remote\") flags.ghForkRemote = args[++i] ?? \"sfmc-modules-fork\";\n else if (a?.startsWith(\"--gh-fork-remote=\")) flags.ghForkRemote = a.slice(\"--gh-fork-remote=\".length);\n else if (a === \"--access\" && (args[i + 1] === \"public\" || args[i + 1] === \"restricted\")) {\n flags.access = args[++i]! as \"public\" | \"restricted\";\n } else if (a === \"--access=public\") flags.access = \"public\";\n else if (a === \"--access=restricted\") flags.access = \"restricted\";\n else if (a === \"--help\" || a === \"-h\") return flags;\n }\n return flags;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * \u5B50\u8FDB\u7A0B\u8F85\u52A9\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\ntype RunResult = { code: number | null; stdout: string; stderr: string };\n\nfunction runNpm(args: string[], opts: { cwd?: string } = {}): Promise<RunResult> {\n const isWin = process.platform === \"win32\";\n /* Windows \u4E0A\u76F4\u63A5 spawn npm.cmd \u4F1A EINVAL\uFF1B\u8D70 cmd /c npm.cmd \u53EF\u884C\u3002\n * POSIX \u4E0A npm \u662F\u5355\u4E00\u53EF\u6267\u884C\u6587\u4EF6\uFF0C\u76F4\u63A5 spawn\u3002\n * \u4E0D\u5F00 shell: true \u907F\u514D DEP0190\uFF08\u53C2\u6570\u62FC\u63A5\u5B89\u5168\u98CE\u9669\uFF09\u3002 */\n const cmd = isWin ? \"cmd.exe\" : \"npm\";\n const fullArgs = isWin ? [\"/c\", \"npm\", ...args] : args;\n return new Promise((resolve) => {\n const proc = spawn(cmd, fullArgs, {\n cwd: opts.cwd ?? process.cwd(),\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n env: process.env,\n });\n let stdout = \"\";\n let stderr = \"\";\n proc.stdout?.on(\"data\", (d: Buffer) => {\n stdout += d.toString();\n });\n proc.stderr?.on(\"data\", (d: Buffer) => {\n stderr += d.toString();\n });\n proc.on(\"exit\", (code) => resolve({ code, stdout, stderr }));\n proc.on(\"error\", (e) => resolve({ code: -1, stdout, stderr: `${stderr}${e.message}` }));\n });\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * npm whoami + scope \u63A8\u65AD\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\nexport async function detectNpmUser(): Promise<{ ok: true; user: string } | { ok: false; stderr: string }> {\n const r = await runNpm([\"whoami\"]);\n if (r.code === 0) {\n const user = (r.stdout || r.stderr).trim().split(/\\r?\\n/)[0] ?? \"\";\n if (user) return { ok: true, user };\n return { ok: false, stderr: \"npm whoami \u65E0\u8F93\u51FA\" };\n }\n return { ok: false, stderr: r.stderr.trim() || \"npm whoami \u5931\u8D25\" };\n}\n\nexport function defaultScopeFor(user: string): string {\n return user.startsWith(\"@\") ? user.slice(1) : user;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * \u9519\u8BEF\u7FFB\u8BD1\uFF08\u4E0E install \u540C\u601D\u8DEF\uFF1B\u5355\u72EC\u51FD\u6570\u4FDD\u6301\u5355\u4E00\u804C\u8D23\uFF09\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\nexport function translateNpmPublishError(pkgName: string, stderr: string): string {\n const text = String(stderr || \"\");\n if (/ENEEDAUTH|not logged in/i.test(text)) {\n return `[publish] \u672A\u767B\u5F55 npm\u3002\u8FD0\u884C \\`npm login --auth-type=web\\` \u540E\u91CD\u8BD5\uFF1B\u6216\u4E34\u65F6\u8BBE NPM_TOKEN\u3002`;\n }\n if (/EOTP|one-time password/i.test(text)) {\n return `[publish] \u9700\u8981 2FA \u7801\u3002\u5728\u7EC8\u7AEF\u8F93\u5165 OTP\uFF08\u63A8\u8350\u7528 WebAuthn / security key\uFF09\u3002`;\n }\n if (/need to confirm/i.test(text) || /Confirm email/i.test(text)) {\n return `[publish] \u9996\u6B21\u5728\u8BE5 scope \u53D1\u5305\uFF1Bnpm \u8981\u6C42\u90AE\u7BB1\u786E\u8BA4\u3002\u6253\u5F00 https://www.npmjs.com/settings/<yourname>/ \u786E\u8BA4\u90AE\u7BB1\u540E\u91CD\u8BD5\u3002`;\n }\n if (/You do not have permission to publish/i.test(text)) {\n return `[publish] \u65E0\u6743\u9650\u53D1\u5230 \"${pkgName}\"\u3002\u5E38\u89C1\u539F\u56E0\uFF1A(a) \u4F60\u9996\u6B21\u5728\u8BE5 scope \u53D1\u5305\u3001\u90AE\u7BB1\u672A\u786E\u8BA4\uFF1B(b) \u5305\u540D\u5DF2\u88AB\u4ED6\u4EBA\u5360\u7528\u3002`;\n }\n if (/402 Payment Required/i.test(text)) {\n return `[publish] \u79C1\u6709\u5305\u9700\u8981\u4ED8\u8D39 npm \u8D26\u53F7\u3002\u6539\u7528 \\`--access public\\` \u6216\u6362\u516C\u5F00 scope\u3002`;\n }\n if (/Package name too similar/i.test(text)) {\n return `[publish] \u5305\u540D\u592A\u63A5\u8FD1\u5DF2\u5B58\u5728\u5305\uFF1B\u5EFA\u8BAE\u6539\u540D\uFF08rename \u811A\u672C\u5DF2\u5728\u6A21\u677F\u4ED3\u63D0\u4F9B\uFF09\u3002`;\n }\n if (/ERESOLVE/i.test(text)) {\n return `[publish] \u4F9D\u8D56\u51B2\u7A81\uFF08ERESOLVE\uFF09\u3002\u63D0\u793A\uFF1A\u7528 --legacy-peer-deps \u91CD\u8BD5\uFF0C\u6216\u786E\u8BA4 SDK/\u5BBF\u4E3B\u7248\u672C\u517C\u5BB9\u3002`;\n }\n if (/ETIMEDOUT|ECONNRESET|ENOTFOUND/i.test(text)) {\n return `[publish] npm \u7F51\u7EDC\u9519\u8BEF\u3002\u68C0\u67E5\u4EE3\u7406 / \u7F51\u7EDC\uFF1B\u6216\u79BB\u7EBF\u7528 \\`sfmc mod install --from local:./x.tgz\\`\u3002`;\n }\n return `[publish] npm publish ${pkgName} \u5931\u8D25\uFF1A\\n${text.trim()}`;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * dry-run \u9884\u68C0\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\nexport interface PrecheckResult {\n ok: boolean;\n warnings: string[];\n errors: string[];\n /** npm pack --dry-run \u89E3\u6790\u51FA\u7684 tarball \u5185\u5BB9\uFF08\u5305\u5185\u6587\u4EF6\u6E05\u5355\uFF09\u3002 */\n tarballFiles: string[];\n}\n\nexport async function runPrecheck(cwd: string): Promise<PrecheckResult> {\n const warnings: string[] = [];\n const errors: string[] = [];\n /* 1) manifest.json v2 */\n const manifestPath = path.join(cwd, \"sapi\", \"manifest.json\");\n try {\n const text = await fs.readFile(manifestPath, \"utf8\");\n const manifest = JSON.parse(text) as { schemaVersion?: number; id?: string; configKey?: string };\n if (manifest.schemaVersion !== 2) errors.push(`manifest schemaVersion \u5FC5\u987B\u662F 2\uFF08\u5F53\u524D ${manifest.schemaVersion ?? \"\u672A\u8BBE\u7F6E\"}\uFF09`);\n if (!manifest.id) errors.push(\"manifest.id \u7F3A\u5931\");\n if (!manifest.configKey) errors.push(\"manifest.configKey \u7F3A\u5931\");\n } catch (e) {\n errors.push(`manifest.json \u8BFB\u53D6\u5931\u8D25: ${(e as Error).message}`);\n }\n /* 2) package.json#files \u5FC5\u542B sapi/ */\n try {\n const pkg = JSON.parse(await fs.readFile(path.join(cwd, \"package.json\"), \"utf8\")) as {\n name?: string;\n files?: string[];\n private?: boolean;\n };\n if (!pkg.name) errors.push(\"package.json#name \u7F3A\u5931\");\n if (pkg.private === true) {\n errors.push(`package.json private=true\uFF0C\u65E0\u6CD5 npm publish\uFF1B\u8BF7\u5220\u9664 private \u5B57\u6BB5`);\n }\n if (\n typeof pkg.name === \"string\" &&\n pkg.name.startsWith(\"@sfmc-bds/\") &&\n !process.env.SFMC_OFFICIAL_PUBLISH\n ) {\n errors.push(\n `\u7981\u6B62\u5411 @sfmc-bds/* \u53D1\u5305\uFF08\u975E\u5B98\u65B9\uFF09\u3002\u8BF7\u6539\u7528 @<user>/sfmc-module-<id>\uFF0C\u6216\u8BBE\u7F6E SFMC_OFFICIAL_PUBLISH=1`\n );\n }\n if (!Array.isArray(pkg.files) || !pkg.files.includes(\"sapi\")) {\n warnings.push(`package.json#files \u4E0D\u542B \"sapi\"\uFF1Bnpm pack \u4F1A\u6253\u51FA\u7A7A tarball\u3002\u5EFA\u8BAE\u52A0 [\"sapi\", \"test\"]\u3002`);\n }\n } catch (e) {\n errors.push(`package.json \u8BFB\u53D6\u5931\u8D25: ${(e as Error).message}`);\n }\n /* 3) npm pack --dry-run\uFF1A\u89E3\u6790 tarball \u5185\u5BB9 */\n const r = await runNpm([\"pack\", \"--dry-run\"], { cwd });\n const tarballFiles = parseTarballListing(r.stdout);\n if (r.code !== 0) {\n errors.push(`npm pack --dry-run \u5931\u8D25\uFF1A${r.stderr.trim()}`);\n }\n /* \u5173\u952E\u6587\u4EF6\u515C\u5E95\u6821\u9A8C */\n const mustHave = [\"package/package.json\"];\n for (const f of mustHave) {\n if (!tarballFiles.some((t) => t.endsWith(f))) {\n warnings.push(`tarball \u7F3A\u5C11\u5173\u952E\u6587\u4EF6 ${f}\uFF08npm pack \u884C\u4E3A\u5F02\u5E38\uFF09`);\n }\n }\n return { ok: errors.length === 0, warnings, errors, tarballFiles };\n}\n\n/** \u89E3\u6790 `npm pack --dry-run` \u8F93\u51FA\uFF08\u5F62\u5982 `npm notice ... Filename: package/sapi/...`\uFF09\u3002 */\nfunction parseTarballListing(stdout: string): string[] {\n const files: string[] = [];\n const re = /^npm notice\\s+Filename:\\s+(.+)$/gm;\n for (const m of stdout.matchAll(re)) files.push(m[1]!.trim());\n return files;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * version bump\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\nexport function bumpSemver(current: string, level: PublishFlags[\"bump\"], custom: string | null): string {\n if (level === \"custom\" && custom) {\n if (!/^\\d+\\.\\d+\\.\\d+(-[\\w.]+)?$/.test(custom)) {\n throw new Error(`invalid custom version: ${custom}`);\n }\n return custom;\n }\n const m = /^(\\d+)\\.(\\d+)\\.(\\d+)/.exec(current);\n if (!m) throw new Error(`\u65E0\u6CD5\u89E3\u6790\u5F53\u524D\u7248\u672C: ${current}`);\n const [maj, min, pat] = [Number(m[1]), Number(m[2]), Number(m[3])];\n if (level === \"major\") return `${maj + 1}.0.0`;\n if (level === \"minor\") return `${maj}.${min + 1}.0`;\n if (level === \"patch\") return `${maj}.${min}.${pat + 1}`;\n throw new Error(`bump level \u7F3A\u5931\u6216\u65E0\u6548: ${String(level)}`);\n}\n\nexport async function writePackageVersion(cwd: string, next: string): Promise<void> {\n const pkgPath = path.join(cwd, \"package.json\");\n const pkg = JSON.parse(await fs.readFile(pkgPath, \"utf8\")) as Record<string, unknown>;\n pkg.version = next;\n await fs.writeFile(pkgPath, `${JSON.stringify(pkg, null, 2)}\\n`, \"utf8\");\n}\n\nexport async function readPackageVersion(cwd: string): Promise<string> {\n const pkg = JSON.parse(await fs.readFile(path.join(cwd, \"package.json\"), \"utf8\")) as {\n version?: string;\n };\n return pkg.version ?? \"0.0.0\";\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * npm publish \u7F16\u6392\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\nexport async function runNpmPublish(\n cwd: string,\n pkgName: string,\n flags: PublishFlags\n): Promise<{ ok: boolean; code: number | null; message: string }> {\n const args = [\"publish\", \"--access\", flags.access, \"--tag\", flags.tag];\n if (flags.dryRun) args.push(\"--dry-run\");\n /* --provenance \u9700 GH Actions OIDC\uFF1B\u672C\u673A\u53EF\u80FD\u6CA1 OIDC \u2192 \u8BA9 npm \u81EA\u8EAB\u51B3\u5B9A\uFF08\u900F\u4F20\uFF09 */\n const r = await runNpm(args, { cwd });\n const msg = r.code === 0 ? r.stdout.trim() : translateNpmPublishError(pkgName, r.stderr);\n return { ok: r.code === 0, code: r.code, message: msg };\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * gh CLI \u9002\u914D\uFF1Aspawn + auth + fork \u2192 branch \u2192 patch index.json \u2192 PR\n *\n * \u5B89\u5168\uFF1A\u9ED8\u8BA4\u4E0D\u771F\u6267\u884C\uFF08\u9664\u975E --gh-push\uFF09\uFF1B\u7F3A\u9274\u6743\u964D\u7EA7\u4E3A\u6253\u5370\u610F\u56FE\u3002\n * \u4E0D\u91CD\u65B0\u53D1\u660E git protocol \u2014\u2014 \u59D4\u6258 `gh repo fork/clone/api`\u3002\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\ntype GhResult = { code: number | null; stdout: string; stderr: string };\n\nfunction runGh(args: string[], opts: { cwd?: string; stdin?: string } = {}): Promise<GhResult> {\n const isWin = process.platform === \"win32\";\n const cmd = isWin ? \"gh.exe\" : \"gh\";\n return new Promise((resolve) => {\n const proc = spawn(cmd, args, {\n cwd: opts.cwd ?? process.cwd(),\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n env: process.env,\n });\n let stdout = \"\";\n let stderr = \"\";\n proc.stdout?.on(\"data\", (d: Buffer) => {\n stdout += d.toString();\n });\n proc.stderr?.on(\"data\", (d: Buffer) => {\n stderr += d.toString();\n });\n if (opts.stdin) proc.stdin.write(opts.stdin);\n proc.stdin?.end();\n proc.on(\"exit\", (code) => resolve({ code, stdout, stderr }));\n proc.on(\"error\", (e) => resolve({ code: -1, stdout, stderr: `${stderr}${e.message}` }));\n });\n}\n\nasync function ghAuthStatus(): Promise<{ ok: boolean; user: string; error: string }> {\n const r = await runGh([\"auth\", \"status\"]);\n if (r.code !== 0) return { ok: false, user: \"\", error: r.stderr.trim() || \"gh auth \u5931\u8D25\" };\n /* `gh auth status` \u8F93\u51FA\u793A\u4F8B\uFF1A`Logged in to github.com as <user> (keyring)` */\n const m = /(?:as|account)\\s+([\\w-]+)/i.exec(r.stdout + r.stderr);\n return { ok: true, user: m?.[1] ?? \"\", error: \"\" };\n}\n\n/** \u628A `OWNER/REPO` \u62C6\u6210 [owner, repo]\u3002 */\nexport function splitOwnerRepo(s: string): [string, string] | null {\n const m = /^([\\w.-]+)\\/([\\w.-]+)$/.exec(s.trim());\n return m ? [m[1]!, m[2]!] : null;\n}\n\n/** \u8BA1\u7B97 index.json \u65B0\u6761\u76EE\uFF08\u8BED\u4E49\u5355\u4E00\uFF1A\u4EC5\u4E3A\u65B0\u7248\u672C\u52A0\u4E00\u6761\uFF1B\u5DF2\u6709\u5219\u8DF3\u8FC7\uFF09\u3002 */\nexport function indexEntryFor(pkgName: string, version: string, sdkRange: string = \">=0.2.0\"): {\n id: string;\n npm: string;\n version: string;\n sdk: string;\n timestamp: number;\n} {\n const npmPkg = pkgName.startsWith(\"@\") ? pkgName : `@${pkgName}`;\n /* id = \u53BB\u6389 scope \u4E0E module-/sfmc-module- \u524D\u7F00\uFF1A\n * \"@sfmc-bds/module-land\" \u2192 \"land\"\n * \"@alice/sfmc-module-foo\" \u2192 \"foo\"\n * \"@scope/bar\" \u2192 \"bar\"\n * \"@module-x\" \u2192 \"@module-x\"\uFF08\u975E scoped \u5305\uFF0C\u4FDD\u7559 npm \u540D\u5F53 id \u515C\u5E95\uFF09\n */\n let id: string;\n if (npmPkg.includes(\"/\")) {\n id = npmPkg.split(\"/\").pop()!.replace(/^module-/, \"\").replace(/^sfmc-module-/, \"\");\n } else {\n id = npmPkg.replace(/^module-/, \"\").replace(/^sfmc-module-/, \"\");\n }\n return { id, npm: npmPkg, version, sdk: sdkRange, timestamp: Date.now() };\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * \u8584 index PR \u4E3B\u5165\u53E3\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\nexport async function openIndexPr(\n pkgName: string,\n version: string,\n opts: {\n dryRun: boolean;\n skipIndexPr: boolean;\n ghPush: boolean;\n ghRepo: string;\n ghForkRemote: string;\n }\n): Promise<{ ok: boolean; skipped: boolean; intent: string[]; message: string; prUrl?: string }> {\n if (opts.skipIndexPr) {\n return { ok: true, skipped: true, intent: [], message: \"\u5DF2\u8DF3\u8FC7\u8584 index PR\uFF08--skip-index-pr\uFF09\" };\n }\n\n const target = splitOwnerRepo(opts.ghRepo);\n if (!target) return { ok: false, skipped: false, intent: [], message: `[publish] --gh-repo \u975E\u6CD5: ${opts.ghRepo}\uFF08\u9700 OWNER/REPO\uFF09` };\n const [owner, repo] = target;\n const entry = indexEntryFor(pkgName, version);\n const branchName = `publish/${entry.id}-${version}`;\n const title = `chore(index): ${entry.id}@${version}`;\n const body = [\n `Automated PR from \\`sfmc mod publish\\`.`,\n ``,\n `- npm: \\`${entry.npm}\\``,\n `- version: \\`${entry.version}\\``,\n `- sdk: \\`${entry.sdk}\\``,\n ].join(\"\\n\");\n\n const intent = [\n `gh repo fork ${owner}/${repo} --remote-name=${opts.ghForkRemote} --clone=false`,\n `gh repo clone ${opts.ghForkRemote}/${repo} fork-workdir -- --depth=1`,\n `cd fork-workdir`,\n `git checkout -b ${branchName}`,\n `edit index.json (upsert ${entry.id}: { npm=${entry.npm}, version=${entry.version}, sdk=\"${entry.sdk}\" })`,\n `git add index.json && git commit -m \"${title}\"`,\n `git push -u ${opts.ghForkRemote} ${branchName}`,\n `gh pr create --repo ${owner}/${repo} --head ${opts.ghForkRemote}:${branchName} --title \"${title}\" --body \"${body}\"`,\n ];\n\n if (!opts.ghPush) {\n return {\n ok: true,\n skipped: false,\n intent,\n message: `[publish] dry-run\uFF1A\u5C06\u5411 ${owner}/${repo} \u5F00 PR \u767B\u8BB0 ${entry.id}@${version}\uFF08\u52A0 --gh-push \u771F\u6267\u884C\uFF09`,\n };\n }\n\n /* \u771F\u6267\u884C\u8DEF\u5F84\uFF1A\u9274\u6743\u68C0\u67E5 + \u9010\u6B65\u8DD1\u4E0A\u9762\u7684 intent */\n const auth = await ghAuthStatus();\n if (!auth.ok) {\n return {\n ok: false,\n skipped: false,\n intent,\n message: `[publish] gh \u672A\u767B\u5F55\uFF1A${auth.error}\\n \u2192 \\`gh auth login\\` \u540E\u91CD\u8BD5\uFF0C\u6216\u7701\u7565 --gh-push \u4EC5 dry-run`,\n };\n }\n\n /* 1) fork */\n const forkRes = await runGh([\"repo\", \"fork\", `${owner}/${repo}`, `--remote-name=${opts.ghForkRemote}`, \"--clone=false\"]);\n if (forkRes.code !== 0 && !/already exists/i.test(forkRes.stderr)) {\n return { ok: false, skipped: false, intent, message: `[publish] gh fork \u5931\u8D25\uFF1A${forkRes.stderr.trim()}` };\n }\n /* 2) clone fork \u5230\u4E34\u65F6\u76EE\u5F55 */\n const os = await import(\"node:os\");\n const fsSync = await import(\"node:fs\");\n const tmp = await fs.mkdtemp(path.join(os.tmpdir(), \"sfmc-index-\"));\n const clone = await runGh([\"repo\", \"clone\", `${auth.user}/${repo}`, tmp, \"--\", \"--depth=1\"]);\n if (clone.code !== 0) return { ok: false, skipped: false, intent, message: `[publish] gh clone \u5931\u8D25\uFF1A${clone.stderr.trim()}` };\n\n /* 3) branch + patch index.json */\n const br = await runGh([\"repo\", \"sync\"], { cwd: tmp });\n void br; /* \u8F6F\u540C\u6B65\uFF0C\u5931\u8D25\u4E0D\u81F4\u547D */\n const branchRes = await spawnBranch(tmp, branchName);\n if (branchRes.code !== 0) {\n fsSync.rmSync(tmp, { recursive: true, force: true });\n return { ok: false, skipped: false, intent, message: `[publish] branch \u521B\u5EFA\u5931\u8D25\uFF1A${branchRes.stderr.trim()}` };\n }\n const indexPath = path.join(tmp, \"index.json\");\n const patchRes = await patchIndexFile(indexPath, entry);\n if (!patchRes.ok) {\n fsSync.rmSync(tmp, { recursive: true, force: true });\n return { ok: false, skipped: false, intent, message: `[publish] patch index.json \u5931\u8D25\uFF1A${patchRes.error}` };\n }\n\n /* 4) commit + push */\n const commitRes = await runGh([\"api\", \"-X\", \"POST\", \"--input\", \"-\"], {\n cwd: tmp,\n /* \u59D4\u6258 git \u76F4 commit\uFF0C\u907F\u514D gh api \u6CA1\u6709\u8BE5 endpoint */\n }).catch(() => ({ code: 0, stdout: \"\", stderr: \"\" }));\n void commitRes;\n /* \u5B9E\u9645 commit \u8D70 git \u900F\u4F20\uFF08\u66F4\u7A33\uFF09 */\n const gitCommit = await spawnGit(tmp, [\"add\", \"index.json\"]);\n if (gitCommit.code !== 0) {\n fsSync.rmSync(tmp, { recursive: true, force: true });\n return { ok: false, skipped: false, intent, message: `[publish] git add \u5931\u8D25\uFF1A${gitCommit.stderr.trim()}` };\n }\n const gitCommitMsg = await spawnGit(tmp, [\"commit\", \"-m\", title]);\n if (gitCommitMsg.code !== 0) {\n fsSync.rmSync(tmp, { recursive: true, force: true });\n return { ok: false, skipped: false, intent, message: `[publish] git commit \u5931\u8D25\uFF1A${gitCommitMsg.stderr.trim()}` };\n }\n const gitPush = await spawnGit(tmp, [\"push\", opts.ghForkRemote, branchName]);\n if (gitPush.code !== 0) {\n fsSync.rmSync(tmp, { recursive: true, force: true });\n return { ok: false, skipped: false, intent, message: `[publish] git push \u5931\u8D25\uFF1A${gitPush.stderr.trim()}` };\n }\n\n /* 5) gh pr create */\n const pr = await runGh([\n \"pr\", \"create\",\n \"--repo\", `${owner}/${repo}`,\n \"--head\", `${auth.user}:${branchName}`,\n \"--title\", title,\n \"--body\", body,\n ], { cwd: tmp });\n fsSync.rmSync(tmp, { recursive: true, force: true });\n if (pr.code !== 0) {\n return { ok: false, skipped: false, intent, message: `[publish] gh pr create \u5931\u8D25\uFF1A${pr.stderr.trim()}` };\n }\n const prUrl = pr.stdout.trim().split(/\\r?\\n/).pop() ?? \"\";\n return { ok: true, skipped: false, intent, message: `[publish] \u8584 index PR \u5DF2\u5F00\uFF1A${prUrl || \"\uFF08\u8BF7\u5230 GitHub \u67E5\u770B\uFF09\"}`, prUrl };\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * \u4F4E\u5C42 helper\uFF1Agit/spawn \u4E0E index.json \u8865\u4E01\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\nfunction spawnGit(cwd: string, args: string[]): Promise<GhResult> {\n return new Promise((resolve) => {\n const proc = spawn(\"git\", args, { cwd, stdio: [\"ignore\", \"pipe\", \"pipe\"], env: process.env });\n let stdout = \"\";\n let stderr = \"\";\n proc.stdout?.on(\"data\", (d: Buffer) => {\n stdout += d.toString();\n });\n proc.stderr?.on(\"data\", (d: Buffer) => {\n stderr += d.toString();\n });\n proc.on(\"exit\", (code) => resolve({ code, stdout, stderr }));\n proc.on(\"error\", (e) => resolve({ code: -1, stdout, stderr: `${stderr}${e.message}` }));\n });\n}\n\nasync function spawnBranch(cwd: string, branch: string): Promise<GhResult> {\n /* `git checkout -b` \u6BD4 gh api \u7A33\uFF1B\u7528 spawn \u76F4\u8C03 */\n return spawnGit(cwd, [\"checkout\", \"-b\", branch]);\n}\n\n/** \u5728\u73B0\u6709 index.json \u4E0A upsert \u4E00\u6761\uFF08map v2\uFF09\uFF1B\u7F3A\u6587\u4EF6\u5219\u5EFA\u7A7A map\u3002\u517C\u5BB9\u65E7\u6570\u7EC4\u5E76\u8FC1\u79FB\u3002 */\nexport async function patchIndexFile(\n indexPath: string,\n entry: ReturnType<typeof indexEntryFor>\n): Promise<{ ok: boolean; error?: string }> {\n let version = 2;\n const modules: Record<string, Record<string, unknown>> = {};\n try {\n const text = await fs.readFile(indexPath, \"utf8\");\n const parsed = JSON.parse(text) as {\n version?: number;\n modules?: Record<string, Record<string, unknown>> | Array<Record<string, unknown>>;\n };\n if (typeof parsed.version === \"number\") version = Math.max(2, parsed.version);\n if (parsed.modules && !Array.isArray(parsed.modules) && typeof parsed.modules === \"object\") {\n Object.assign(modules, parsed.modules);\n } else if (Array.isArray(parsed.modules)) {\n for (const m of parsed.modules) {\n if (m && typeof m === \"object\" && typeof m.id === \"string\") {\n const { id, ...rest } = m as { id: string } & Record<string, unknown>;\n modules[id] = rest;\n }\n }\n }\n } catch {\n /* \u6587\u4EF6\u4E0D\u5B58\u5728\u6216\u975E\u6CD5 \u2192 \u65B0\u5EFA */\n }\n if (modules[entry.id]) {\n return { ok: false, error: `${entry.id} \u5DF2\u5728 index.json \u4E2D\u5B58\u5728\uFF1B\u8BF7\u624B\u52A8\u68C0\u67E5\u540E\u518D publish` };\n }\n modules[entry.id] = {\n npm: entry.npm,\n version: entry.version,\n sdk: entry.sdk,\n timestamp: entry.timestamp,\n };\n const sorted: Record<string, Record<string, unknown>> = {};\n for (const k of Object.keys(modules).sort()) sorted[k] = modules[k]!;\n await fs.mkdir(path.dirname(indexPath), { recursive: true });\n await fs.writeFile(indexPath, `${JSON.stringify({ version, modules: sorted }, null, 2)}\\n`, \"utf8\");\n return { ok: true };\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * CLI \u4E3B\u5165\u53E3\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\nexport async function cmdModulePublish(args: string[]): Promise<string> {\n const flags = parsePublishFlags(args);\n const out: string[] = [];\n const cwd = process.cwd();\n\n /* 0) \u767B\u5F55\u6001\u63A2\u6D4B */\n out.push(c.bold(t(\"publish.banner\")));\n const who = await detectNpmUser();\n if (!who.ok) {\n out.push(c.red(t(\"publish.noLogin\")));\n out.push(\" \" + who.stderr.split(\"\\n\")[0]!);\n out.push(c.dim(t(\"publish.noLoginHint\")));\n return out.join(\"\\n\") + \"\\n\";\n }\n out.push(c.green(`[publish] npm \u5DF2\u767B\u5F55: ${who.user}`));\n const scope = (flags.scope ?? who.user).replace(/^@/, \"\");\n out.push(c.dim(`[publish] \u9ED8\u8BA4 scope: @${scope}`));\n\n /* 1) \u8BFB\u53D6\u5F53\u524D\u5305\u540D */\n const pkgJson = JSON.parse(await fs.readFile(path.join(cwd, \"package.json\"), \"utf8\")) as {\n name?: string;\n version?: string;\n };\n const pkgName = pkgJson.name ?? `${scope}/sfmc-module-?`;\n out.push(`[publish] \u5F53\u524D\u5305\u540D: ${pkgName}`);\n\n /* 2) dry-run \u9884\u68C0 */\n const pre = await runPrecheck(cwd);\n for (const w of pre.warnings) out.push(c.yellow(`[publish] warn: ${w}`));\n for (const e of pre.errors) out.push(c.red(`[publish] error: ${e}`));\n if (!pre.ok) {\n out.push(c.red(t(\"publish.precheckFail\")));\n return out.join(\"\\n\") + \"\\n\";\n }\n out.push(c.green(`[publish] precheck OK\uFF08${pre.tarballFiles.length} \u6587\u4EF6\u5165\u5305\uFF09`));\n if (flags.dryRun) {\n out.push(c.dim(t(\"publish.dryRun.summary\")));\n return out.join(\"\\n\") + \"\\n\";\n }\n\n /* 3) version bump */\n const currentVer = await readPackageVersion(cwd);\n let nextVer = currentVer;\n if (flags.bump) {\n try {\n nextVer = bumpSemver(currentVer, flags.bump, flags.customVersion);\n } catch (e) {\n out.push(c.red(`[publish] bump \u5931\u8D25: ${(e as Error).message}`));\n return out.join(\"\\n\") + \"\\n\";\n }\n await writePackageVersion(cwd, nextVer);\n out.push(c.green(`[publish] \u7248\u672C bump: ${currentVer} \u2192 ${nextVer}`));\n } else {\n out.push(c.dim(`[publish] \u5F53\u524D\u7248\u672C ${currentVer}\uFF08\u672A bump\uFF1B\u82E5\u5DF2\u53D1\u5E03\u8FC7\u76F8\u540C\u7248\u672C npm \u4F1A 409\uFF09`));\n }\n\n /* 4) npm publish \u900F\u4F20 */\n const pub = await runNpmPublish(cwd, pkgName, flags);\n out.push(pub.message);\n if (!pub.ok) {\n /* rollback version bump\uFF08\u907F\u514D\u672C\u5730\u7559\u4E0B\u810F bump\uFF09 */\n if (flags.bump && nextVer !== currentVer) {\n try {\n await writePackageVersion(cwd, currentVer);\n out.push(c.dim(`[publish] \u5DF2\u56DE\u6EDA package.json#version: ${nextVer} \u2192 ${currentVer}`));\n } catch {\n /* best-effort */\n }\n }\n return out.join(\"\\n\") + \"\\n\";\n }\n\n /* 5) \u8584 index PR */\n const pr = await openIndexPr(pkgName, nextVer, {\n dryRun: flags.dryRun,\n skipIndexPr: flags.skipIndexPr,\n ghPush: flags.ghPush,\n ghRepo: flags.ghRepo,\n ghForkRemote: flags.ghForkRemote,\n });\n out.push(pr.message);\n if (!pr.ok && !pr.skipped) {\n /* PR \u5931\u8D25\u4E0D\u56DE\u6EDA publish\uFF08npm \u5DF2\u7ECF\u6210\u529F\uFF09 */\n out.push(c.yellow(`[publish] \u6CE8\u610F\uFF1A\u8584 index PR \u5931\u8D25\uFF0C\u4F46 npm \u5305\u5DF2\u53D1\u5E03\uFF1B\u53EF\u624B\u52A8\u8865 index.json\u3002`));\n }\n\n out.push(c.green(t(\"publish.done\")));\n return out.join(\"\\n\") + \"\\n\";\n}"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["t"]
|
|
7
|
-
}
|
package/dist/module-watch.d.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
/** watch 监听配置。 */
|
|
2
|
-
export interface WatchOptions {
|
|
3
|
-
/** 模块仓根(cwd/local 解析出的目录,含 sapi/)。 */
|
|
4
|
-
moduleRoot: string;
|
|
5
|
-
/** 只 build+deploy,不向 BDS 发 reload。 */
|
|
6
|
-
noReload: boolean;
|
|
7
|
-
/** 防抖毫秒数。 */
|
|
8
|
-
debounceMs: number;
|
|
9
|
-
/** 终端打印回调(被 watch 命令自己接住;这里仅做轻 wrap)。 */
|
|
10
|
-
log: (line: string) => void;
|
|
11
|
-
}
|
|
12
|
-
/** 一次 build+deploy(+reload) 周期。 */
|
|
13
|
-
export interface WatchRunResult {
|
|
14
|
-
ok: boolean;
|
|
15
|
-
rebuilt: boolean;
|
|
16
|
-
reloadSent: boolean;
|
|
17
|
-
/** 若被提示「请重启」则为 true。 */
|
|
18
|
-
warnedRestart: boolean;
|
|
19
|
-
message: string;
|
|
20
|
-
}
|
|
21
|
-
/** 解析 `--from local[:path]` 规则(与 mod install 一致;本轮复用 watch 单一路径)。 */
|
|
22
|
-
export declare function resolveLocalModuleRoot(args: {
|
|
23
|
-
from?: string | null;
|
|
24
|
-
cwd: string;
|
|
25
|
-
}): string;
|
|
26
|
-
/** 启动 chokidar 风格的 fs.watch;本轮直接用 node:fs.watch(轻量、零依赖)。 */
|
|
27
|
-
export declare function startWatch(opts: WatchOptions): {
|
|
28
|
-
stop: () => void;
|
|
29
|
-
};
|
|
30
|
-
/** CLI 入口:`sfmc mod watch [--from local[:path]] [--no-reload]` */
|
|
31
|
-
export declare function cmdModuleWatch(args: string[]): Promise<string>;
|
|
32
|
-
//# sourceMappingURL=module-watch.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"module-watch.d.ts","sourceRoot":"","sources":["../src/module-watch.ts"],"names":[],"mappings":"AAqBA,kBAAkB;AAClB,MAAM,WAAW,YAAY;IAC3B,sCAAsC;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,sCAAsC;IACtC,QAAQ,EAAE,OAAO,CAAC;IAClB,aAAa;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,yCAAyC;IACzC,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7B;AAED,mCAAmC;AACnC,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,OAAO,CAAC;IACpB,wBAAwB;IACxB,aAAa,EAAE,OAAO,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qEAAqE;AACrE,wBAAgB,sBAAsB,CAAC,IAAI,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAgB1F;AAED,4DAA4D;AAC5D,wBAAgB,UAAU,CAAC,IAAI,EAAE,YAAY,GAAG;IAAE,IAAI,EAAE,MAAM,IAAI,CAAA;CAAE,CA+HnE;AAED,kEAAkE;AAClE,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA4CpE"}
|