@sfmc-bds/cli 0.2.0-beta.5 → 0.2.0-beta.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. package/dist/argv-parse.d.ts +13 -0
  2. package/dist/argv-parse.d.ts.map +1 -0
  3. package/dist/argv-parse.js +32 -0
  4. package/dist/argv-parse.js.map +7 -0
  5. package/dist/cli-gate.d.ts +11 -0
  6. package/dist/cli-gate.d.ts.map +1 -0
  7. package/dist/cli-gate.js +48 -0
  8. package/dist/cli-gate.js.map +7 -0
  9. package/dist/cmd-remote.d.ts +13 -0
  10. package/dist/cmd-remote.d.ts.map +1 -0
  11. package/dist/cmd-remote.js +38 -0
  12. package/dist/cmd-remote.js.map +7 -0
  13. package/dist/command-palette.d.ts +61 -0
  14. package/dist/command-palette.d.ts.map +1 -0
  15. package/dist/command-palette.js +352 -0
  16. package/dist/command-palette.js.map +7 -0
  17. package/dist/command-surface.d.ts +92 -0
  18. package/dist/command-surface.d.ts.map +1 -0
  19. package/dist/command-surface.js +350 -0
  20. package/dist/command-surface.js.map +7 -0
  21. package/dist/commands-reload.js +2 -2
  22. package/dist/commands-reload.js.map +2 -2
  23. package/dist/commands.d.ts +1 -1
  24. package/dist/commands.d.ts.map +1 -1
  25. package/dist/commands.js +79 -17
  26. package/dist/commands.js.map +2 -2
  27. package/dist/debug-command.d.ts +5 -0
  28. package/dist/debug-command.d.ts.map +1 -0
  29. package/dist/debug-command.js +118 -0
  30. package/dist/debug-command.js.map +7 -0
  31. package/dist/help-text.d.ts +3 -0
  32. package/dist/help-text.d.ts.map +1 -0
  33. package/dist/help-text.js +168 -0
  34. package/dist/help-text.js.map +7 -0
  35. package/dist/i18n/locales/en.d.ts +101 -20
  36. package/dist/i18n/locales/en.d.ts.map +1 -1
  37. package/dist/i18n/locales/en.js +105 -20
  38. package/dist/i18n/locales/en.js.map +2 -2
  39. package/dist/i18n/locales/zh-CN.d.ts.map +1 -1
  40. package/dist/i18n/locales/zh-CN.js +153 -62
  41. package/dist/i18n/locales/zh-CN.js.map +2 -2
  42. package/dist/index.d.ts +1 -1
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js +6 -0
  45. package/dist/index.js.map +2 -2
  46. package/dist/logs.d.ts +16 -1
  47. package/dist/logs.d.ts.map +1 -1
  48. package/dist/logs.js +80 -11
  49. package/dist/logs.js.map +2 -2
  50. package/dist/main.js +58 -44
  51. package/dist/main.js.map +2 -2
  52. package/dist/module-commands.d.ts +29 -33
  53. package/dist/module-commands.d.ts.map +1 -1
  54. package/dist/module-commands.js +101 -37
  55. package/dist/module-commands.js.map +2 -2
  56. package/dist/module-pack-build.d.ts +10 -0
  57. package/dist/module-pack-build.d.ts.map +1 -0
  58. package/dist/module-pack-build.js +430 -0
  59. package/dist/module-pack-build.js.map +7 -0
  60. package/dist/module-publish.d.ts +69 -0
  61. package/dist/module-publish.d.ts.map +1 -0
  62. package/dist/module-publish.js +478 -0
  63. package/dist/module-publish.js.map +7 -0
  64. package/dist/module-watch.d.ts +32 -0
  65. package/dist/module-watch.d.ts.map +1 -0
  66. package/dist/module-watch.js +171 -0
  67. package/dist/module-watch.js.map +7 -0
  68. package/dist/module-wizard.d.ts +4 -6
  69. package/dist/module-wizard.d.ts.map +1 -1
  70. package/dist/module-wizard.js +108 -124
  71. package/dist/module-wizard.js.map +2 -2
  72. package/dist/pack-lifecycle.d.ts +1 -1
  73. package/dist/pack-lifecycle.d.ts.map +1 -1
  74. package/dist/pack-lifecycle.js +3 -3
  75. package/dist/pack-lifecycle.js.map +2 -2
  76. package/dist/pack-update/index.d.ts +18 -0
  77. package/dist/pack-update/index.d.ts.map +1 -0
  78. package/dist/pack-update/index.js +113 -0
  79. package/dist/pack-update/index.js.map +7 -0
  80. package/dist/registry.d.ts +6 -3
  81. package/dist/registry.d.ts.map +1 -1
  82. package/dist/registry.js +15 -3
  83. package/dist/registry.js.map +2 -2
  84. package/dist/remote-agent.d.ts.map +1 -1
  85. package/dist/remote-agent.js +7 -5
  86. package/dist/remote-agent.js.map +2 -2
  87. package/dist/repl-windows/format-display.d.ts +10 -0
  88. package/dist/repl-windows/format-display.d.ts.map +1 -0
  89. package/dist/repl-windows/format-display.js +57 -0
  90. package/dist/repl-windows/format-display.js.map +7 -0
  91. package/dist/repl-windows/host.d.ts +60 -0
  92. package/dist/repl-windows/host.d.ts.map +1 -0
  93. package/dist/repl-windows/host.js +179 -0
  94. package/dist/repl-windows/host.js.map +7 -0
  95. package/dist/repl-windows/index.d.ts +9 -0
  96. package/dist/repl-windows/index.d.ts.map +1 -0
  97. package/dist/repl-windows/index.js +13 -0
  98. package/dist/repl-windows/index.js.map +7 -0
  99. package/dist/repl-windows/logs-filter-window.d.ts +15 -0
  100. package/dist/repl-windows/logs-filter-window.d.ts.map +1 -0
  101. package/dist/repl-windows/logs-filter-window.js +77 -0
  102. package/dist/repl-windows/logs-filter-window.js.map +7 -0
  103. package/dist/repl-windows/service-window.d.ts +4 -0
  104. package/dist/repl-windows/service-window.d.ts.map +1 -0
  105. package/dist/repl-windows/service-window.js +28 -0
  106. package/dist/repl-windows/service-window.js.map +7 -0
  107. package/dist/repl-windows/types.d.ts +56 -0
  108. package/dist/repl-windows/types.d.ts.map +1 -0
  109. package/dist/repl-windows/types.js +1 -0
  110. package/dist/repl-windows/types.js.map +7 -0
  111. package/dist/repl.d.ts +7 -8
  112. package/dist/repl.d.ts.map +1 -1
  113. package/dist/repl.js +722 -412
  114. package/dist/repl.js.map +3 -3
  115. package/dist/runtime.d.ts +2 -0
  116. package/dist/runtime.d.ts.map +1 -1
  117. package/dist/runtime.js +4 -0
  118. package/dist/runtime.js.map +2 -2
  119. package/dist/send-target.d.ts +11 -0
  120. package/dist/send-target.d.ts.map +1 -0
  121. package/dist/send-target.js +38 -0
  122. package/dist/send-target.js.map +7 -0
  123. package/dist/services.d.ts +21 -1
  124. package/dist/services.d.ts.map +1 -1
  125. package/dist/services.js +146 -7
  126. package/dist/services.js.map +2 -2
  127. package/dist/theme.js +1 -1
  128. package/dist/theme.js.map +2 -2
  129. package/dist/wizard.d.ts.map +1 -1
  130. package/dist/wizard.js +11 -9
  131. package/dist/wizard.js.map +2 -2
  132. package/dist/world-packs.d.ts.map +1 -1
  133. package/dist/world-packs.js +6 -3
  134. package/dist/world-packs.js.map +2 -2
  135. package/package.json +4 -4
  136. package/dist/pack-update/bindings.d.ts +0 -12
  137. package/dist/pack-update/bindings.d.ts.map +0 -1
  138. package/dist/pack-update/bindings.js +0 -64
  139. package/dist/pack-update/bindings.js.map +0 -7
  140. package/dist/pack-update/config.d.ts +0 -22
  141. package/dist/pack-update/config.d.ts.map +0 -1
  142. package/dist/pack-update/config.js +0 -141
  143. package/dist/pack-update/config.js.map +0 -7
  144. package/dist/pack-update/providers/curseforge.d.ts +0 -23
  145. package/dist/pack-update/providers/curseforge.d.ts.map +0 -1
  146. package/dist/pack-update/providers/curseforge.js +0 -229
  147. package/dist/pack-update/providers/curseforge.js.map +0 -7
  148. package/dist/pack-update/providers/index.d.ts +0 -16
  149. package/dist/pack-update/providers/index.d.ts.map +0 -1
  150. package/dist/pack-update/providers/index.js +0 -37
  151. package/dist/pack-update/providers/index.js.map +0 -7
  152. package/dist/pack-update/service.d.ts +0 -21
  153. package/dist/pack-update/service.d.ts.map +0 -1
  154. package/dist/pack-update/service.js +0 -572
  155. package/dist/pack-update/service.js.map +0 -7
  156. package/dist/pack-update/types.d.ts +0 -126
  157. package/dist/pack-update/types.d.ts.map +0 -1
  158. package/dist/pack-update/types.js +0 -8
  159. package/dist/pack-update/types.js.map +0 -7
  160. package/dist/pack-update/version-policy.d.ts +0 -81
  161. package/dist/pack-update/version-policy.d.ts.map +0 -1
  162. package/dist/pack-update/version-policy.js +0 -210
  163. package/dist/pack-update/version-policy.js.map +0 -7
@@ -0,0 +1,171 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import process from "node:process";
4
+ import { c } from "./theme.js";
5
+ import { t } from "./i18n/index.js";
6
+ function resolveLocalModuleRoot(args) {
7
+ const raw = (args.from ?? "").trim();
8
+ if (!raw) return path.resolve(args.cwd);
9
+ if (raw === "local") return path.resolve(args.cwd);
10
+ if (raw.startsWith("local:")) {
11
+ const p = raw.slice("local:".length).trim();
12
+ if (!p) return path.resolve(args.cwd);
13
+ return path.isAbsolute(p) ? path.resolve(p) : path.resolve(args.cwd, p);
14
+ }
15
+ if (raw.startsWith("dir:")) {
16
+ const p = raw.slice("dir:".length).trim();
17
+ return path.isAbsolute(p) ? path.resolve(p) : path.resolve(args.cwd, p);
18
+ }
19
+ return path.resolve(args.cwd);
20
+ }
21
+ function startWatch(opts) {
22
+ const sapiDir = path.join(opts.moduleRoot, "sapi");
23
+ if (!fs.existsSync(sapiDir)) {
24
+ opts.log(c.red(t("watch.noSapiDir", { path: sapiDir })));
25
+ return { stop: () => {
26
+ } };
27
+ }
28
+ const srcDir = path.join(sapiDir, "src");
29
+ if (!fs.existsSync(srcDir)) {
30
+ opts.log(c.yellow(t("watch.noSapiSrc", { path: srcDir })));
31
+ }
32
+ let debounceTimer = null;
33
+ let pending = /* @__PURE__ */ new Set();
34
+ let running = false;
35
+ let stopped = false;
36
+ opts.log(c.bold(t("watch.banner", { path: opts.moduleRoot })));
37
+ opts.log(c.dim(t("watch.hint")));
38
+ const trigger = (kind, files) => {
39
+ if (stopped) return;
40
+ if (kind === "manifest" || kind === "tsconfig") {
41
+ opts.log(c.yellow(t("watch.manifestOrTsconfig", { kind, files: files.join(", ") })));
42
+ return;
43
+ }
44
+ for (const f of files) pending.add(f);
45
+ if (debounceTimer) clearTimeout(debounceTimer);
46
+ debounceTimer = setTimeout(() => {
47
+ void runOnce();
48
+ }, opts.debounceMs);
49
+ };
50
+ const runOnce = async () => {
51
+ if (running || stopped) return;
52
+ running = true;
53
+ const changed = [...pending];
54
+ pending = /* @__PURE__ */ new Set();
55
+ const t0 = Date.now();
56
+ opts.log(c.dim(t("watch.rebuild.start", { count: changed.length, files: changed.join(", ") })));
57
+ try {
58
+ const { cmdModuleReload } = await import("./module-pack-build.js");
59
+ const out = await cmdModuleReload(opts.noReload ? ["--build-only"] : []);
60
+ const ok = !out.startsWith(c.red(""));
61
+ const elapsed = Date.now() - t0;
62
+ if (ok) {
63
+ opts.log(c.green(t("watch.rebuild.ok", { ms: elapsed })));
64
+ if (!opts.noReload) {
65
+ opts.log(c.green(t("watch.reload.sent")));
66
+ } else {
67
+ opts.log(c.yellow(t("watch.reload.manualHint")));
68
+ }
69
+ } else {
70
+ opts.log(c.red(t("watch.rebuild.fail", { ms: elapsed, output: out.trim() })));
71
+ }
72
+ } catch (e) {
73
+ opts.log(c.red(t("watch.rebuild.error", { message: e.message })));
74
+ } finally {
75
+ running = false;
76
+ }
77
+ };
78
+ void runOnce;
79
+ const watchSrc = (dir) => {
80
+ if (!fs.existsSync(dir)) return null;
81
+ try {
82
+ return fs.watch(
83
+ dir,
84
+ { recursive: true, persistent: true },
85
+ (_event, filename) => {
86
+ if (!filename) return;
87
+ const rel = filename.toString();
88
+ if (rel.includes("node_modules") || rel.includes("dist") || rel.endsWith(".tgz")) return;
89
+ trigger("src", [rel]);
90
+ }
91
+ );
92
+ } catch (e) {
93
+ opts.log(c.yellow(t("watch.recursiveFallback", { message: e.message })));
94
+ return fs.watch(dir, { persistent: true }, (_event, filename) => {
95
+ if (!filename) return;
96
+ trigger("src", [filename.toString()]);
97
+ });
98
+ }
99
+ };
100
+ const watchMeta = (file, kind) => {
101
+ if (!fs.existsSync(file)) return null;
102
+ return fs.watch(file, { persistent: true }, (event) => {
103
+ if (event === "change") trigger(kind, [path.basename(file)]);
104
+ });
105
+ };
106
+ const watchers = [];
107
+ const ws = watchSrc(srcDir);
108
+ if (ws) watchers.push(ws);
109
+ const wm = watchMeta(path.join(sapiDir, "manifest.json"), "manifest");
110
+ if (wm) watchers.push(wm);
111
+ const wt = watchMeta(path.join(sapiDir, "tsconfig.json"), "tsconfig");
112
+ if (wt) watchers.push(wt);
113
+ const stop = () => {
114
+ stopped = true;
115
+ if (debounceTimer) {
116
+ clearTimeout(debounceTimer);
117
+ debounceTimer = null;
118
+ }
119
+ for (const w of watchers) {
120
+ try {
121
+ w.close();
122
+ } catch {
123
+ }
124
+ }
125
+ opts.log(c.dim(t("watch.stopped")));
126
+ };
127
+ return { stop };
128
+ }
129
+ async function cmdModuleWatch(args) {
130
+ let fromRaw = null;
131
+ let noReload = false;
132
+ for (let i = 0; i < args.length; i++) {
133
+ const a = args[i];
134
+ if (a === "--from") {
135
+ fromRaw = args[++i] ?? null;
136
+ } else if (a?.startsWith("--from=")) {
137
+ fromRaw = a.slice("--from=".length);
138
+ } else if (a === "--no-reload") {
139
+ noReload = true;
140
+ } else if (a === "--help" || a === "-h") {
141
+ return c.dim(t("watch.usage"));
142
+ }
143
+ }
144
+ const moduleRoot = resolveLocalModuleRoot({ from: fromRaw, cwd: process.cwd() });
145
+ const log = (line) => {
146
+ process.stdout.write(line + "\n");
147
+ };
148
+ let stopRef = null;
149
+ const onSig = () => {
150
+ if (stopRef) stopRef();
151
+ process.exit(0);
152
+ };
153
+ process.once("SIGINT", onSig);
154
+ process.once("SIGTERM", onSig);
155
+ const { stop } = startWatch({
156
+ moduleRoot,
157
+ noReload,
158
+ debounceMs: 200,
159
+ log
160
+ });
161
+ stopRef = stop;
162
+ await new Promise(() => {
163
+ });
164
+ return "";
165
+ }
166
+ export {
167
+ cmdModuleWatch,
168
+ resolveLocalModuleRoot,
169
+ startWatch
170
+ };
171
+ //# sourceMappingURL=module-watch.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/module-watch.ts"],
4
+ "sourcesContent": ["/**\n * sfmc/src/module-watch.ts \u2014 `sfmc mod watch` \u5F15\u64CE\n *\n * \u76D1\u542C cwd/local \u6A21\u5757\u7684 sapi/src \u53D8\u66F4 \u2192 \u590D\u7528 cmdModuleReload \u7684 build/deploy/reload\n * \u8DEF\u5F84\uFF0C\u907F\u514D\u5728\u6838\u5FC3 switch/if \u94FE\u4E0A\u518D\u6253\u6D1E\uFF08OCP/DRY\uFF09\u3002\n *\n * \u89E6\u53D1\u8BED\u4E49\uFF1A\n * - sapi/src/** \u53D8\u66F4 \u2192 rebuild + deploy + reload\n * - sapi/manifest.json \u53D8\u66F4 \u2192 \u4EC5\u63D0\u793A\u300CSAPI \u542F\u52A8\u671F\u7F13\u5B58\uFF0C\u8BF7\u91CD\u542F BDS \u8FDB\u7A0B\u300D\uFF0C\u4E0D\u81EA\u52A8\u70ED\u66F4\n * - sapi/tsconfig.json \u53D8\u66F4 \u2192 \u540C manifest\uFF0C\u63D0\u793A\u91CD\u542F\n * - \u5176\u4ED6\uFF08configs/\u3001SDK \u5185\u90E8\u3001node_modules\u3001dist\u3001*.tgz\uFF09\u2192 \u5FFD\u7565\n *\n * \u8FDB\u7A0B\u63A2\u6D4B\u590D\u7528 sfmc-cli \u7EDF\u4E00\u63A5\u53E3\uFF1AqueryServicesRuntime + probeBdsStatus\uFF1B\n * \u5916\u90E8 BDS\uFF08state === \"external\"\uFF09\u964D\u7EA7 build+deploy \u5E76\u63D0\u793A\u300C\u8BF7\u5728 BDS/\u6E38\u620F\u5185\u8F93\u5165 reload\u300D\u3002\n */\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport process from \"node:process\";\nimport { c } from \"./theme.js\";\nimport { t } from \"./i18n/index.js\";\n\n/** watch \u76D1\u542C\u914D\u7F6E\u3002 */\nexport interface WatchOptions {\n /** \u6A21\u5757\u4ED3\u6839\uFF08cwd/local \u89E3\u6790\u51FA\u7684\u76EE\u5F55\uFF0C\u542B sapi/\uFF09\u3002 */\n moduleRoot: string;\n /** \u53EA build+deploy\uFF0C\u4E0D\u5411 BDS \u53D1 reload\u3002 */\n noReload: boolean;\n /** \u9632\u6296\u6BEB\u79D2\u6570\u3002 */\n debounceMs: number;\n /** \u7EC8\u7AEF\u6253\u5370\u56DE\u8C03\uFF08\u88AB watch \u547D\u4EE4\u81EA\u5DF1\u63A5\u4F4F\uFF1B\u8FD9\u91CC\u4EC5\u505A\u8F7B wrap\uFF09\u3002 */\n log: (line: string) => void;\n}\n\n/** \u4E00\u6B21 build+deploy(+reload) \u5468\u671F\u3002 */\nexport interface WatchRunResult {\n ok: boolean;\n rebuilt: boolean;\n reloadSent: boolean;\n /** \u82E5\u88AB\u63D0\u793A\u300C\u8BF7\u91CD\u542F\u300D\u5219\u4E3A true\u3002 */\n warnedRestart: boolean;\n message: string;\n}\n\n/** \u89E3\u6790 `--from local[:path]` \u89C4\u5219\uFF08\u4E0E mod install \u4E00\u81F4\uFF1B\u672C\u8F6E\u590D\u7528 watch \u5355\u4E00\u8DEF\u5F84\uFF09\u3002 */\nexport function resolveLocalModuleRoot(args: { from?: string | null; cwd: string }): string {\n const raw = (args.from ?? \"\").trim();\n if (!raw) return path.resolve(args.cwd);\n /* `--from local[:<path>]` */\n if (raw === \"local\") return path.resolve(args.cwd);\n if (raw.startsWith(\"local:\")) {\n const p = raw.slice(\"local:\".length).trim();\n if (!p) return path.resolve(args.cwd);\n return path.isAbsolute(p) ? path.resolve(p) : path.resolve(args.cwd, p);\n }\n /* `--from dir:<path>` \u517C\u5BB9\u65E7\u5199\u6CD5\uFF08\u6682\u4E0D\u5F3A\u5236\uFF1B\u672C\u671F watch \u4E0D\u5F3A\u5236\u94FE\u63A5 dir\uFF09\u3002 */\n if (raw.startsWith(\"dir:\")) {\n const p = raw.slice(\"dir:\".length).trim();\n return path.isAbsolute(p) ? path.resolve(p) : path.resolve(args.cwd, p);\n }\n return path.resolve(args.cwd);\n}\n\n/** \u542F\u52A8 chokidar \u98CE\u683C\u7684 fs.watch\uFF1B\u672C\u8F6E\u76F4\u63A5\u7528 node:fs.watch\uFF08\u8F7B\u91CF\u3001\u96F6\u4F9D\u8D56\uFF09\u3002 */\nexport function startWatch(opts: WatchOptions): { stop: () => void } {\n const sapiDir = path.join(opts.moduleRoot, \"sapi\");\n if (!fs.existsSync(sapiDir)) {\n opts.log(c.red(t(\"watch.noSapiDir\", { path: sapiDir })));\n return { stop: () => {} };\n }\n const srcDir = path.join(sapiDir, \"src\");\n if (!fs.existsSync(srcDir)) {\n opts.log(c.yellow(t(\"watch.noSapiSrc\", { path: srcDir })));\n }\n\n let debounceTimer: NodeJS.Timeout | null = null;\n let pending: Set<string> = new Set();\n let running = false;\n let stopped = false;\n\n /* \u542F\u52A8 banner */\n opts.log(c.bold(t(\"watch.banner\", { path: opts.moduleRoot })));\n opts.log(c.dim(t(\"watch.hint\")));\n\n const trigger = (kind: \"src\" | \"manifest\" | \"tsconfig\", files: string[]) => {\n if (stopped) return;\n if (kind === \"manifest\" || kind === \"tsconfig\") {\n opts.log(c.yellow(t(\"watch.manifestOrTsconfig\", { kind, files: files.join(\", \") })));\n return;\n }\n /* src \u53D8\u66F4\uFF1A\u5408\u5E76\u5230 pending\uFF0C\u7B49\u5F85 debounce \u89E6\u53D1\u4E00\u6B21 rebuild\u3002 */\n for (const f of files) pending.add(f);\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n void runOnce();\n }, opts.debounceMs);\n };\n\n const runOnce = async (): Promise<void> => {\n if (running || stopped) return;\n running = true;\n const changed = [...pending];\n pending = new Set();\n const t0 = Date.now();\n opts.log(c.dim(t(\"watch.rebuild.start\", { count: changed.length, files: changed.join(\", \") })));\n try {\n const { cmdModuleReload } = await import(\"./module-pack-build.js\");\n const out = await cmdModuleReload(opts.noReload ? [\"--build-only\"] : []);\n const ok = !out.startsWith(c.red(\"\"));\n const elapsed = Date.now() - t0;\n if (ok) {\n opts.log(c.green(t(\"watch.rebuild.ok\", { ms: elapsed })));\n if (!opts.noReload) {\n opts.log(c.green(t(\"watch.reload.sent\")));\n } else {\n opts.log(c.yellow(t(\"watch.reload.manualHint\")));\n }\n } else {\n opts.log(c.red(t(\"watch.rebuild.fail\", { ms: elapsed, output: out.trim() })));\n }\n } catch (e) {\n opts.log(c.red(t(\"watch.rebuild.error\", { message: (e as Error).message })));\n } finally {\n running = false;\n }\n };\n\n /**\n * \u4E00\u6B21\u6027 runOnce + send reload\uFF0C\u517C\u5BB9 `sfmc mod test`/wizard \u672A\u6765\u590D\u7528\uFF1A\n * \u672C\u671F\u4E0D\u5BFC\u51FA\uFF0C\u4F46\u4FDD\u7559\u6269\u5C55\u4F4D\u3002\n */\n void runOnce;\n\n /* \u76D1\u542C sapi/src \u6811\u3002 */\n const watchSrc = (dir: string): fs.FSWatcher | null => {\n if (!fs.existsSync(dir)) return null;\n try {\n return fs.watch(\n dir,\n { recursive: true, persistent: true },\n (_event, filename) => {\n if (!filename) return;\n const rel = filename.toString();\n /* \u8FC7\u6EE4\uFF1Adist / *.tgz / \u4E34\u65F6\u6587\u4EF6 */\n if (rel.includes(\"node_modules\") || rel.includes(\"dist\") || rel.endsWith(\".tgz\")) return;\n trigger(\"src\", [rel]);\n }\n );\n } catch (e) {\n /* Windows \u67D0\u4E9B\u957F\u8DEF\u5F84/\u6743\u9650\u573A\u666F\u4E0B recursive \u4E0D\u652F\u6301\uFF1B\u964D\u7EA7\u5230\u975E recursive\u3002 */\n opts.log(c.yellow(t(\"watch.recursiveFallback\", { message: (e as Error).message })));\n return fs.watch(dir, { persistent: true }, (_event, filename) => {\n if (!filename) return;\n trigger(\"src\", [filename.toString()]);\n });\n }\n };\n\n /* \u76D1\u542C manifest / tsconfig\uFF1A\u5355\u72EC watcher\uFF0C\u4E0D\u89E6\u53D1 build\u3002 */\n const watchMeta = (file: string, kind: \"manifest\" | \"tsconfig\"): fs.FSWatcher | null => {\n if (!fs.existsSync(file)) return null;\n return fs.watch(file, { persistent: true }, (event) => {\n if (event === \"change\") trigger(kind, [path.basename(file)]);\n });\n };\n\n const watchers: fs.FSWatcher[] = [];\n const ws = watchSrc(srcDir);\n if (ws) watchers.push(ws);\n const wm = watchMeta(path.join(sapiDir, \"manifest.json\"), \"manifest\");\n if (wm) watchers.push(wm);\n const wt = watchMeta(path.join(sapiDir, \"tsconfig.json\"), \"tsconfig\");\n if (wt) watchers.push(wt);\n\n const stop = (): void => {\n stopped = true;\n if (debounceTimer) {\n clearTimeout(debounceTimer);\n debounceTimer = null;\n }\n for (const w of watchers) {\n try {\n w.close();\n } catch {\n /* ignore */\n }\n }\n opts.log(c.dim(t(\"watch.stopped\")));\n };\n\n return { stop };\n}\n\n/** CLI \u5165\u53E3\uFF1A`sfmc mod watch [--from local[:path]] [--no-reload]` */\nexport async function cmdModuleWatch(args: string[]): Promise<string> {\n let fromRaw: string | null = null;\n let noReload = false;\n for (let i = 0; i < args.length; i++) {\n const a = args[i];\n if (a === \"--from\") {\n fromRaw = args[++i] ?? null;\n } else if (a?.startsWith(\"--from=\")) {\n fromRaw = a.slice(\"--from=\".length);\n } else if (a === \"--no-reload\") {\n noReload = true;\n } else if (a === \"--help\" || a === \"-h\") {\n return c.dim(t(\"watch.usage\"));\n }\n }\n const moduleRoot = resolveLocalModuleRoot({ from: fromRaw, cwd: process.cwd() });\n\n /* \u96C6\u4E2D\u5230 stdout\uFF1A\u547D\u4EE4\u884C\u573A\u666F\u4E0B\u4E0D\u9700\u8981 sfmc \u65E5\u5FD7\u7BA1\u9053\u7684 stamp\u3002 */\n const log = (line: string): void => {\n process.stdout.write(line + \"\\n\");\n };\n\n /* Ctrl+C \u2192 stop watchers\uFF0C\u518D\u9000\u51FA\u3002 */\n let stopRef: (() => void) | null = null;\n const onSig = (): void => {\n if (stopRef) stopRef();\n process.exit(0);\n };\n process.once(\"SIGINT\", onSig);\n process.once(\"SIGTERM\", onSig);\n\n const { stop } = startWatch({\n moduleRoot,\n noReload,\n debounceMs: 200,\n log,\n });\n stopRef = stop;\n\n /* \u4FDD\u6301\u8FDB\u7A0B\u4E0D\u9000\u51FA\uFF1A\u7528\u4E00\u4E2A\u6C38\u9A7B Promise\u3002 */\n await new Promise<void>(() => {\n /* never resolves; SIGINT/SIGTERM \u89E6\u53D1 exit\u3002 */\n });\n return \"\";\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -1,14 +1,12 @@
1
1
  /**
2
2
  * module-wizard.ts — 模块脚手架 / 本地联调交互向导
3
3
  *
4
- * 复用 @clack/prompts init 向导相同依赖;薄包装 tools/new-module.mjs、fetch-module.mjs
4
+ * 单包根(template 同构):不写入旁路 sfmc-modules monorepo
5
5
  */
6
- declare function isInteractive(): boolean;
7
- /** 交互式创建模块包并可选 link / enable / build+deploy。 */
6
+ /** 交互式创建单包模块(cwd 或指定空目录),可选 link / enable / build+deploy。 */
8
7
  export declare function runModuleCreateWizard(): Promise<string>;
9
- /** sfmc-modules/packages 选择并 --link 安装。 */
8
+ /** 选择本地作者仓目录并 --link 安装。 */
10
9
  export declare function runModuleLinkWizard(): Promise<string>;
11
- /** 链接 + 启用 + 构建部署(本地开发一键流)。 */
10
+ /** 本地开发提示(不再依赖旁路 sfmc-modules)。 */
12
11
  export declare function runModuleDevWizard(): Promise<string>;
13
- export { isInteractive as isModuleWizardInteractive };
14
12
  //# sourceMappingURL=module-wizard.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"module-wizard.d.ts","sourceRoot":"","sources":["../src/module-wizard.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAmBH,iBAAS,aAAa,IAAI,OAAO,CAEhC;AAgGD,gDAAgD;AAChD,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,MAAM,CAAC,CAiG7D;AAED,6CAA6C;AAC7C,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC,CAsD3D;AAED,+BAA+B;AAC/B,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC,CA4E1D;AAED,OAAO,EAAE,aAAa,IAAI,yBAAyB,EAAE,CAAC"}
1
+ {"version":3,"file":"module-wizard.d.ts","sourceRoot":"","sources":["../src/module-wizard.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAwHH,6DAA6D;AAC7D,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,MAAM,CAAC,CAmI7D;AAED,4BAA4B;AAC5B,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC,CAuD3D;AAED,mCAAmC;AACnC,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC,CAe1D"}
@@ -7,12 +7,6 @@ import { t } from "./i18n/index.js";
7
7
  import { cmdModuleEnable } from "./module-commands.js";
8
8
  import { pickDirectory, resolveUserPath } from "./interactive-prompts.js";
9
9
  import { ROOT, resolveFetchModule, resolveNewModule } from "./runtime.js";
10
- import {
11
- listSfmcModulePackages,
12
- packageDirForId,
13
- persistSfmcModulesRoot,
14
- resolveSfmcModulesRoot
15
- } from "./sfmc-modules-root.js";
16
10
  import { c } from "./theme.js";
17
11
  function isInteractive() {
18
12
  return Boolean(process.stdin.isTTY);
@@ -37,22 +31,6 @@ function spawnTool(script, args) {
37
31
  proc.on("error", (e) => resolve({ code: 1, output: `${output}${e.message}` }));
38
32
  });
39
33
  }
40
- async function ensureSfmcModulesRoot() {
41
- let modulesRoot = resolveSfmcModulesRoot();
42
- if (modulesRoot) {
43
- note(c.text(t("modwiz.sfmcModulesPath", { path: modulesRoot })), t("common.path"));
44
- return modulesRoot;
45
- }
46
- const defaultGuess = path.resolve(ROOT, "..", "sfmc-modules");
47
- const picked = await pickDirectory(t("modwiz.pickModulesRoot"), defaultGuess);
48
- modulesRoot = resolveUserPath(picked, ROOT);
49
- if (!existsSync(path.join(modulesRoot, "packages"))) {
50
- outro(c.red(t("modwiz.noPackages", { path: modulesRoot })));
51
- return null;
52
- }
53
- persistSfmcModulesRoot(modulesRoot);
54
- return modulesRoot;
55
- }
56
34
  async function runFetchModuleLink(folderId, pkgPath) {
57
35
  const fetchScript = resolveFetchModule();
58
36
  if (!fetchScript) {
@@ -101,13 +79,35 @@ function validateFolderId(value) {
101
79
  }
102
80
  return void 0;
103
81
  }
82
+ async function listTemplatesFromTool() {
83
+ const script = resolveNewModule();
84
+ if (!script) return [];
85
+ const { code, output } = await spawnTool(script, ["--list-templates"]);
86
+ if (code !== 0) return [];
87
+ const out = [];
88
+ for (const line of output.split(/\r?\n/)) {
89
+ const trimmed = line.trim();
90
+ if (!trimmed) continue;
91
+ const [id, ...flags] = trimmed.split(" ");
92
+ if (!id) continue;
93
+ out.push({ id, isDefault: flags.includes("default") });
94
+ }
95
+ return out;
96
+ }
97
+ function tplLabel(id) {
98
+ const label = t(`modwiz.tpl.${id}`);
99
+ return label === `modwiz.tpl.${id}` ? id : label;
100
+ }
101
+ function tplHint(id) {
102
+ const hint = t(`modwiz.tpl.${id}Hint`);
103
+ return hint === `modwiz.tpl.${id}Hint` ? void 0 : hint;
104
+ }
104
105
  async function runModuleCreateWizard() {
105
106
  if (!isInteractive()) {
106
107
  return c.yellow(t("modwiz.needTty.create"));
107
108
  }
108
109
  intro(c.bold(t("modwiz.createIntro")));
109
- const modulesRoot = await ensureSfmcModulesRoot();
110
- if (!modulesRoot) return cancelMessage();
110
+ note(c.dim(t("modwiz.standaloneHint")), t("common.hint"));
111
111
  const idRaw = await text({
112
112
  message: t("modwiz.folderId"),
113
113
  placeholder: "my-feature",
@@ -118,7 +118,14 @@ async function runModuleCreateWizard() {
118
118
  return cancelMessage();
119
119
  }
120
120
  const folderId = idRaw.trim();
121
- const target = packageDirForId(modulesRoot, folderId);
121
+ const defaultTarget = path.resolve(process.cwd(), folderId);
122
+ const picked = await pickDirectory(t("modwiz.pickPackageRoot"), path.dirname(defaultTarget));
123
+ if (isCancel(picked) || !picked) {
124
+ outro(cancelMessage());
125
+ return cancelMessage();
126
+ }
127
+ const parentDir = resolveUserPath(String(picked), ROOT);
128
+ const target = path.join(parentDir, folderId);
122
129
  if (existsSync(target)) {
123
130
  outro(c.red(t("modwiz.dirExists", { path: target })));
124
131
  return c.red(t("modwiz.dirExists", { path: target }));
@@ -132,35 +139,65 @@ async function runModuleCreateWizard() {
132
139
  outro(cancelMessage());
133
140
  return cancelMessage();
134
141
  }
142
+ const templates = await listTemplatesFromTool();
143
+ if (templates.length === 0) {
144
+ outro(c.red(t("modwiz.noNewModule")));
145
+ return c.red(t("modwiz.noNewModule"));
146
+ }
147
+ const defaultTpl = templates.find((tpl) => tpl.isDefault) ?? templates[0];
135
148
  const template = await select({
136
149
  message: t("modwiz.template"),
137
- options: [
138
- { value: "minimal", label: t("modwiz.tpl.minimal"), hint: t("modwiz.tpl.minimalHint") },
139
- { value: "db", label: t("modwiz.tpl.db"), hint: t("modwiz.tpl.dbHint") }
140
- ]
150
+ initialValue: defaultTpl.id,
151
+ options: templates.map((tpl) => {
152
+ const opt = {
153
+ value: tpl.id,
154
+ label: tplLabel(tpl.id)
155
+ };
156
+ const hint = tplHint(tpl.id);
157
+ if (hint) opt.hint = hint;
158
+ return opt;
159
+ })
141
160
  });
142
161
  if (isCancel(template)) {
143
162
  outro(cancelMessage());
144
163
  return cancelMessage();
145
164
  }
146
- const siblingNewModule = path.join(modulesRoot, "tools", "new-module.mjs");
147
- const platformNewModule = resolveNewModule();
148
- const useSibling = existsSync(siblingNewModule) && template === "minimal";
149
- const newModuleScript = useSibling ? siblingNewModule : platformNewModule;
165
+ const newModuleScript = resolveNewModule();
150
166
  if (!newModuleScript) {
151
167
  outro(c.red(t("modwiz.noNewModule")));
152
168
  return c.red(t("modwiz.noNewModule"));
153
169
  }
170
+ const { mkdirSync } = await import("node:fs");
171
+ mkdirSync(target, { recursive: true });
154
172
  let scaffoldOutput = "";
155
173
  try {
156
174
  await tasks([
157
175
  {
158
176
  title: t("modwiz.genPackage", { id: folderId }),
159
177
  task: async () => {
160
- const spawnArgs = useSibling ? [folderId, nameRaw.trim()] : [folderId, "--name", nameRaw.trim(), "--root", modulesRoot, "--template", String(template)];
161
- const { code, output } = await spawnTool(newModuleScript, spawnArgs);
162
- scaffoldOutput = output;
163
- if (code !== 0) throw new Error(output.trim() || `exit ${code}`);
178
+ const { spawn: spawnChild } = await import("node:child_process");
179
+ const result = await new Promise((resolve) => {
180
+ const proc = spawnChild(
181
+ process.execPath,
182
+ [newModuleScript, folderId, "--name", nameRaw.trim(), "--template", String(template)],
183
+ {
184
+ cwd: target,
185
+ stdio: ["ignore", "pipe", "pipe"],
186
+ env: { ...process.env, SFMC_ROOT: ROOT }
187
+ }
188
+ );
189
+ let output = "";
190
+ proc.stdout?.on("data", (d) => {
191
+ output += d.toString();
192
+ });
193
+ proc.stderr?.on("data", (d) => {
194
+ output += d.toString();
195
+ });
196
+ proc.on("exit", (code) => resolve({ code, output }));
197
+ proc.on("error", (e) => resolve({ code: 1, output: e.message }));
198
+ });
199
+ scaffoldOutput = result.output;
200
+ if (result.code !== 0) throw new Error(result.output.trim() || `exit ${result.code}`);
164
201
  return t("modwiz.skeletonWritten");
165
202
  }
166
203
  }
@@ -191,36 +228,36 @@ async function runModuleLinkWizard() {
191
228
  return c.yellow(t("modwiz.needTty.link"));
192
229
  }
193
230
  intro(c.bold(t("modwiz.linkIntro")));
194
- const modulesRoot = await ensureSfmcModulesRoot();
195
- if (!modulesRoot) return cancelMessage();
196
- const packages = listSfmcModulePackages(modulesRoot);
197
- if (packages.length === 0) {
198
- outro(c.yellow(t("modwiz.noLinkable", { path: modulesRoot })));
199
- return c.yellow(t("modwiz.noLinkableShort"));
200
- }
201
- const picked = await select({
202
- message: t("modwiz.pickLink"),
203
- options: packages.map((p) => ({
204
- value: p.id,
205
- label: p.id,
206
- hint: `${p.name} \xB7 ${p.logicalId}`
207
- }))
208
- });
209
- if (isCancel(picked)) {
231
+ const picked = await pickDirectory(t("modwiz.pickAuthorPkg"), process.cwd());
232
+ if (isCancel(picked) || !picked) {
210
233
  outro(cancelMessage());
211
234
  return cancelMessage();
212
235
  }
213
- const pkg = packages.find((p) => p.id === picked);
236
+ const pkgPath = resolveUserPath(String(picked), ROOT);
237
+ if (!existsSync(path.join(pkgPath, "sapi", "manifest.json"))) {
238
+ outro(c.red(t("modwiz.notModulePkg", { path: pkgPath })));
239
+ return c.red(t("modwiz.notModulePkg", { path: pkgPath }));
240
+ }
241
+ const fetchScript = resolveFetchModule();
242
+ if (!fetchScript) {
243
+ outro(c.red(t("modwiz.noFetch")));
244
+ return c.red(t("modwiz.noFetch"));
245
+ }
214
246
  let linkOutput = "";
215
247
  try {
216
248
  await tasks([
217
249
  {
218
- title: t("modwiz.linking", { id: pkg.id }),
250
+ title: t("modwiz.linking", { id: path.basename(pkgPath) }),
219
251
  task: async () => {
220
- const { ok, output } = await runFetchModuleLink(pkg.id, pkg.path);
252
+ const { code, output } = await spawnTool(fetchScript, [
253
+ "install",
254
+ "--from",
255
+ `dir:${pkgPath}`,
256
+ "--link"
257
+ ]);
221
258
  linkOutput = output;
222
- if (!ok) throw new Error(output.trim() || t("modwiz.linkFailed"));
223
- return t("modwiz.linkSynced");
259
+ if (code !== 0) throw new Error(output.trim() || `exit ${code}`);
260
+ return t("common.done");
224
261
  }
225
262
  }
226
263
  ]);
@@ -229,83 +266,30 @@ async function runModuleLinkWizard() {
229
266
  return c.red(e.message);
230
267
  }
231
268
  note(linkOutput.trim(), t("modwiz.link"));
232
- const enableMsg = await maybeEnableModule(pkg.id);
269
+ const folderId = path.basename(pkgPath);
270
+ const enableMsg = await maybeEnableModule(folderId);
233
271
  if (enableMsg) note(enableMsg, t("modwiz.enable"));
234
- outro(c.green(t("modwiz.linked", { id: pkg.id })));
235
- return c.green(t("modwiz.linked", { id: pkg.id }));
272
+ await maybeBuildDeploy();
273
+ outro(c.green(t("modwiz.linkDone", { id: folderId })));
274
+ return c.green(t("modwiz.linkDone", { id: folderId }));
236
275
  }
237
276
  async function runModuleDevWizard() {
238
277
  if (!isInteractive()) {
239
278
  return c.yellow(t("modwiz.needTty.dev"));
240
279
  }
241
280
  intro(c.bold(t("modwiz.devIntro")));
242
- const modulesRoot = await ensureSfmcModulesRoot();
243
- if (!modulesRoot) return cancelMessage();
244
- const packages = listSfmcModulePackages(modulesRoot);
245
- if (packages.length === 0) {
246
- outro(c.yellow(t("modwiz.noDevPackages", { path: modulesRoot })));
247
- return c.yellow(t("modwiz.noDevShort"));
248
- }
249
- const picked = await select({
250
- message: t("modwiz.pickDev"),
251
- options: packages.map((p) => ({
252
- value: p.id,
253
- label: p.id,
254
- hint: `${p.name} \xB7 ${p.logicalId}`
255
- }))
281
+ note(c.text(t("modwiz.devStandalone")), t("common.hint"));
282
+ const doReload = await confirm({
283
+ message: t("modwiz.buildDeploy"),
284
+ initialValue: false
256
285
  });
257
- if (isCancel(picked)) {
258
- outro(cancelMessage());
259
- return cancelMessage();
260
- }
261
- const pkg = packages.find((p) => p.id === picked);
262
- try {
263
- await tasks([
264
- {
265
- title: t("modwiz.linking", { id: pkg.id }),
266
- task: async () => {
267
- const { ok, output } = await runFetchModuleLink(pkg.id, pkg.path);
268
- if (!ok) throw new Error(output.trim() || t("modwiz.linkFailed"));
269
- return output.trim().split("\n").pop() ?? "linked";
270
- }
271
- },
272
- {
273
- title: t("modwiz.enabling", { id: pkg.id }),
274
- task: async () => {
275
- const r = await cmdModuleEnable([pkg.id]);
276
- if (!r.ok) throw new Error(r.message.trim());
277
- return r.message.trim();
278
- }
279
- },
280
- {
281
- title: t("modwiz.task.build"),
282
- task: async () => {
283
- const { cmdBehaviorPackBuild } = await import("./commands-behavior-pack.js");
284
- const r = await cmdBehaviorPackBuild([]);
285
- if (!r.ok) throw new Error(r.message.trim());
286
- return t("common.done");
287
- }
288
- },
289
- {
290
- title: t("modwiz.task.deploy"),
291
- task: async () => {
292
- const { cmdBehaviorPackDeploy } = await import("./commands-behavior-pack.js");
293
- const r = await cmdBehaviorPackDeploy([]);
294
- if (!r.ok) throw new Error(r.message.trim());
295
- return t("common.done");
296
- }
297
- }
298
- ]);
299
- } catch (e) {
300
- outro(c.red(e.message));
301
- return c.red(e.message);
286
+ if (!isCancel(doReload) && doReload) {
287
+ await maybeBuildDeploy();
302
288
  }
303
- note(c.yellow(t("modwiz.devHint")), t("common.hint"));
304
- outro(c.green(t("modwiz.devDone", { id: pkg.id })));
305
- return c.green(t("modwiz.devReady", { id: pkg.id }));
289
+ outro(c.green(t("modwiz.reloadHint")));
290
+ return c.dim(t("modwiz.reloadHint"));
306
291
  }
307
292
  export {
308
- isInteractive as isModuleWizardInteractive,
309
293
  runModuleCreateWizard,
310
294
  runModuleDevWizard,
311
295
  runModuleLinkWizard