@sfmc-bds/cli 0.2.0-beta.7 → 0.2.0-beta.9

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 (91) hide show
  1. package/dist/argv-parse.d.ts +0 -2
  2. package/dist/argv-parse.d.ts.map +1 -1
  3. package/dist/argv-parse.js +1 -5
  4. package/dist/argv-parse.js.map +2 -2
  5. package/dist/cli-gate.d.ts.map +1 -1
  6. package/dist/cli-gate.js +0 -2
  7. package/dist/cli-gate.js.map +2 -2
  8. package/dist/command-surface.d.ts +2 -12
  9. package/dist/command-surface.d.ts.map +1 -1
  10. package/dist/command-surface.js +2 -34
  11. package/dist/command-surface.js.map +2 -2
  12. package/dist/commands.d.ts.map +1 -1
  13. package/dist/commands.js +123 -10
  14. package/dist/commands.js.map +2 -2
  15. package/dist/help-text.d.ts.map +1 -1
  16. package/dist/help-text.js +1 -5
  17. package/dist/help-text.js.map +2 -2
  18. package/dist/i18n/locales/en.d.ts +27 -38
  19. package/dist/i18n/locales/en.d.ts.map +1 -1
  20. package/dist/i18n/locales/en.js +27 -41
  21. package/dist/i18n/locales/en.js.map +2 -2
  22. package/dist/i18n/locales/zh-CN.d.ts.map +1 -1
  23. package/dist/i18n/locales/zh-CN.js +27 -41
  24. package/dist/i18n/locales/zh-CN.js.map +2 -2
  25. package/dist/index.d.ts +2 -2
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +3 -4
  28. package/dist/index.js.map +2 -2
  29. package/dist/llbot-launch.d.ts +20 -0
  30. package/dist/llbot-launch.d.ts.map +1 -0
  31. package/dist/llbot-launch.js +40 -0
  32. package/dist/llbot-launch.js.map +7 -0
  33. package/dist/main.js +7 -12
  34. package/dist/main.js.map +2 -2
  35. package/dist/module-commands.d.ts +5 -18
  36. package/dist/module-commands.d.ts.map +1 -1
  37. package/dist/module-commands.js +89 -87
  38. package/dist/module-commands.js.map +2 -2
  39. package/dist/module-pack-build.d.ts.map +1 -1
  40. package/dist/module-pack-build.js +4 -0
  41. package/dist/module-pack-build.js.map +2 -2
  42. package/dist/module-toggle.d.ts +33 -0
  43. package/dist/module-toggle.d.ts.map +1 -0
  44. package/dist/module-toggle.js +28 -0
  45. package/dist/module-toggle.js.map +7 -0
  46. package/dist/node-service-probe.d.ts +18 -0
  47. package/dist/node-service-probe.d.ts.map +1 -0
  48. package/dist/node-service-probe.js +97 -0
  49. package/dist/node-service-probe.js.map +7 -0
  50. package/dist/pack-lifecycle.d.ts.map +1 -1
  51. package/dist/pack-lifecycle.js +11 -1
  52. package/dist/pack-lifecycle.js.map +2 -2
  53. package/dist/repl-windows/service-window.d.ts +1 -1
  54. package/dist/repl-windows/service-window.d.ts.map +1 -1
  55. package/dist/repl-windows/service-window.js +8 -1
  56. package/dist/repl-windows/service-window.js.map +2 -2
  57. package/dist/repl.d.ts +0 -2
  58. package/dist/repl.d.ts.map +1 -1
  59. package/dist/repl.js +0 -19
  60. package/dist/repl.js.map +2 -2
  61. package/dist/runtime.d.ts +4 -13
  62. package/dist/runtime.d.ts.map +1 -1
  63. package/dist/runtime.js +15 -27
  64. package/dist/runtime.js.map +2 -2
  65. package/dist/send-target.d.ts.map +1 -1
  66. package/dist/send-target.js +6 -2
  67. package/dist/send-target.js.map +2 -2
  68. package/dist/services.d.ts +32 -6
  69. package/dist/services.d.ts.map +1 -1
  70. package/dist/services.js +101 -16
  71. package/dist/services.js.map +2 -2
  72. package/dist/wizard.d.ts.map +1 -1
  73. package/dist/wizard.js +65 -7
  74. package/dist/wizard.js.map +2 -2
  75. package/package.json +7 -8
  76. package/dist/cmd-remote.d.ts +0 -13
  77. package/dist/cmd-remote.d.ts.map +0 -1
  78. package/dist/cmd-remote.js +0 -38
  79. package/dist/cmd-remote.js.map +0 -7
  80. package/dist/module-publish.d.ts +0 -69
  81. package/dist/module-publish.d.ts.map +0 -1
  82. package/dist/module-publish.js +0 -478
  83. package/dist/module-publish.js.map +0 -7
  84. package/dist/module-watch.d.ts +0 -32
  85. package/dist/module-watch.d.ts.map +0 -1
  86. package/dist/module-watch.js +0 -171
  87. package/dist/module-watch.js.map +0 -7
  88. package/dist/remote-agent.d.ts +0 -18
  89. package/dist/remote-agent.d.ts.map +0 -1
  90. package/dist/remote-agent.js +0 -198
  91. package/dist/remote-agent.js.map +0 -7
@@ -1,171 +0,0 @@
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
@@ -1,7 +0,0 @@
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,18 +0,0 @@
1
- type RemoteStatus = {
2
- enabled?: boolean;
3
- controller_url?: string;
4
- agent_id?: string;
5
- connected: boolean;
6
- last_error?: string;
7
- retry_in_ms?: number;
8
- };
9
- /** Close the active socket (if any) and stop reconnecting. Idempotent. */
10
- export declare function stopRemoteAgent(): void;
11
- /** Start one outbound-only remote-management connection for this supervisor process. */
12
- export declare function startRemoteAgent(): void;
13
- export declare function enrollRemoteAgent(controllerUrl: string, enrollmentToken: string, name: string): Promise<string>;
14
- /** Disable the remote agent: clear enabled flag and close the connection. */
15
- export declare function disableRemoteAgent(): void;
16
- export declare function remoteStatus(): RemoteStatus;
17
- export {};
18
- //# sourceMappingURL=remote-agent.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"remote-agent.d.ts","sourceRoot":"","sources":["../src/remote-agent.ts"],"names":[],"mappings":"AAqBA,KAAK,YAAY,GAAG;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AA6FF,0EAA0E;AAC1E,wBAAgB,eAAe,IAAI,IAAI,CAetC;AAED,wFAAwF;AACxF,wBAAgB,gBAAgB,IAAI,IAAI,CAkEvC;AAED,wBAAsB,iBAAiB,CAAC,aAAa,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAWrH;AAED,6EAA6E;AAC7E,wBAAgB,kBAAkB,IAAI,IAAI,CAOzC;AAED,wBAAgB,YAAY,IAAI,YAAY,CAW3C"}
@@ -1,198 +0,0 @@
1
- import { WebSocket } from "ws";
2
- import {
3
- configPath,
4
- DEFAULT_REMOTE_CONFIG,
5
- loadEnsuredConfig,
6
- writeJson,
7
- withConfigSchema
8
- } from "@sfmc-bds/sdk/node/config";
9
- import { cmdRestart, cmdSend, cmdStart, cmdStop } from "./commands.js";
10
- import { ROOT } from "./runtime.js";
11
- import { SERVICE_NAMES, serviceStatus } from "./services.js";
12
- let socket = null;
13
- let retryTimer = null;
14
- let retryDelay = 1e3;
15
- let heartbeatTimer = null;
16
- let lastError = "";
17
- let warnedMissingConfig = false;
18
- let stopping = false;
19
- const HEARTBEAT_INTERVAL_MS = 2e4;
20
- function loadConfig() {
21
- return loadEnsuredConfig(
22
- ROOT,
23
- "remote.json",
24
- "remote",
25
- { ...DEFAULT_REMOTE_CONFIG }
26
- );
27
- }
28
- function writeConfig(config) {
29
- writeJson(configPath(ROOT, "remote.json"), withConfigSchema({ ...config }, "remote"));
30
- }
31
- function isService(value) {
32
- return !!value && SERVICE_NAMES.includes(value);
33
- }
34
- function isAction(value) {
35
- return value === "status" || value === "start" || value === "stop" || value === "restart" || value === "send";
36
- }
37
- function websocketUrl(controllerUrl, agentId) {
38
- const url = new URL(controllerUrl);
39
- url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
40
- url.pathname = "/v1/agent";
41
- url.search = new URLSearchParams({ id: agentId }).toString();
42
- return url.toString();
43
- }
44
- function send(payload) {
45
- if (socket?.readyState === WebSocket.OPEN) socket.send(JSON.stringify(payload));
46
- }
47
- function startHeartbeat() {
48
- stopHeartbeat();
49
- heartbeatTimer = setInterval(() => send({ type: "ping" }), HEARTBEAT_INTERVAL_MS);
50
- }
51
- function stopHeartbeat() {
52
- if (heartbeatTimer) {
53
- clearInterval(heartbeatTimer);
54
- heartbeatTimer = null;
55
- }
56
- }
57
- async function execute(task) {
58
- if (!isAction(task.action)) throw new Error("invalid task action");
59
- if (task.action === "status") return { services: await serviceStatus() };
60
- if (!isService(task.service)) throw new Error("service is required and must be one of: " + SERVICE_NAMES.join(", "));
61
- if (task.action === "send") {
62
- if (!task.message) throw new Error("message is required for send action");
63
- return { output: await cmdSend(task.service, task.message), services: await serviceStatus() };
64
- }
65
- const output = task.action === "start" ? await cmdStart(task.service) : task.action === "stop" ? await cmdStop(task.service) : await cmdRestart(task.service);
66
- return { output, services: await serviceStatus() };
67
- }
68
- function scheduleReconnect() {
69
- if (retryTimer || stopping) return;
70
- const delay = retryDelay;
71
- retryTimer = setTimeout(() => {
72
- retryTimer = null;
73
- startRemoteAgent();
74
- }, delay);
75
- }
76
- function resetReconnect(reason) {
77
- retryDelay = 1e3;
78
- if (reason) {
79
- lastError = reason;
80
- console.warn(`[remote-agent] ${reason} \u2014 will retry in ${retryDelay}ms`);
81
- }
82
- }
83
- function stopRemoteAgent() {
84
- stopping = true;
85
- stopHeartbeat();
86
- if (retryTimer) {
87
- clearTimeout(retryTimer);
88
- retryTimer = null;
89
- }
90
- if (socket) {
91
- try {
92
- socket.close(1e3, "client_shutdown");
93
- } catch {
94
- }
95
- socket = null;
96
- }
97
- }
98
- function startRemoteAgent() {
99
- if (stopping) return;
100
- if (socket || retryTimer) return;
101
- const config = loadConfig();
102
- if (!config.enabled || !config.controller_url || !config.agent_id || !config.agent_secret) {
103
- if (!warnedMissingConfig) {
104
- const missing = [];
105
- if (!config.enabled) missing.push("enabled");
106
- if (!config.controller_url) missing.push("controller_url");
107
- if (!config.agent_id) missing.push("agent_id");
108
- if (!config.agent_secret) missing.push("agent_secret");
109
- if (missing.length) {
110
- console.warn(`[remote-agent] disabled \u2014 missing remote.json fields: ${missing.join(", ")} (run \`sfmc remote enroll\`)`);
111
- }
112
- warnedMissingConfig = true;
113
- }
114
- return;
115
- }
116
- warnedMissingConfig = true;
117
- let ws;
118
- try {
119
- ws = new WebSocket(websocketUrl(config.controller_url, config.agent_id));
120
- } catch (e) {
121
- resetReconnect(`failed to construct websocket: ${e.message}`);
122
- scheduleReconnect();
123
- return;
124
- }
125
- socket = ws;
126
- ws.on("open", () => {
127
- retryDelay = 1e3;
128
- lastError = "";
129
- void serviceStatus().then((status) => {
130
- send({ type: "hello", agentId: config.agent_id, secret: config.agent_secret, status });
131
- startHeartbeat();
132
- });
133
- });
134
- ws.on("message", (raw) => {
135
- let msg;
136
- try {
137
- msg = JSON.parse(raw.toString());
138
- } catch {
139
- return;
140
- }
141
- if (msg.type === "ping") {
142
- send({ type: "pong" });
143
- return;
144
- }
145
- if (msg.type !== "task") return;
146
- const task = msg;
147
- void execute(task).then((result) => send({ type: "task_result", taskId: task.taskId, ok: true, result })).catch((error) => send({ type: "task_result", taskId: task.taskId, ok: false, error: error.message }));
148
- });
149
- ws.on("close", (code, reason) => {
150
- if (socket === ws) socket = null;
151
- stopHeartbeat();
152
- if (stopping) return;
153
- resetReconnect(`disconnected (code=${code} ${reason.toString() || "no_reason"})`);
154
- scheduleReconnect();
155
- });
156
- ws.on("error", (e) => {
157
- resetReconnect(`socket error: ${e.message}`);
158
- });
159
- }
160
- async function enrollRemoteAgent(controllerUrl, enrollmentToken, name) {
161
- const response = await fetch(new URL("/v1/enroll", controllerUrl), {
162
- method: "POST",
163
- headers: { "content-type": "application/json", authorization: `Bearer ${enrollmentToken}` },
164
- body: JSON.stringify({ name })
165
- });
166
- const result = await response.json();
167
- if (!response.ok || !result.agentId || !result.agentSecret) throw new Error(result.error ?? "enrollment failed");
168
- writeConfig({ enabled: true, controller_url: controllerUrl, agent_id: result.agentId, agent_secret: result.agentSecret });
169
- return result.agentId;
170
- }
171
- function disableRemoteAgent() {
172
- const config = loadConfig();
173
- if (config.agent_id || config.agent_secret) {
174
- writeConfig({ ...config, enabled: false });
175
- }
176
- stopRemoteAgent();
177
- stopping = false;
178
- }
179
- function remoteStatus() {
180
- const config = loadConfig();
181
- const result = { connected: socket?.readyState === WebSocket.OPEN };
182
- if (config.enabled !== void 0) result.enabled = config.enabled;
183
- if (config.controller_url) result.controller_url = config.controller_url;
184
- if (config.agent_id) result.agent_id = config.agent_id;
185
- if (lastError) {
186
- result.last_error = lastError;
187
- result.retry_in_ms = retryDelay;
188
- }
189
- return result;
190
- }
191
- export {
192
- disableRemoteAgent,
193
- enrollRemoteAgent,
194
- remoteStatus,
195
- startRemoteAgent,
196
- stopRemoteAgent
197
- };
198
- //# sourceMappingURL=remote-agent.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/remote-agent.ts"],
4
- "sourcesContent": ["import { WebSocket } from \"ws\";\nimport {\n configPath,\n DEFAULT_REMOTE_CONFIG,\n loadEnsuredConfig,\n writeJson,\n withConfigSchema,\n type RemoteConfig,\n} from \"@sfmc-bds/sdk/node/config\";\nimport { cmdRestart, cmdSend, cmdStart, cmdStop } from \"./commands.js\";\nimport { ROOT } from \"./runtime.js\";\nimport { SERVICE_NAMES, serviceStatus, type ServiceName } from \"./services.js\";\n\ntype Task = {\n type: \"task\";\n taskId: string;\n action: \"status\" | \"start\" | \"stop\" | \"restart\" | \"send\";\n service?: string;\n message?: string;\n};\n\ntype RemoteStatus = {\n enabled?: boolean;\n controller_url?: string;\n agent_id?: string;\n connected: boolean;\n last_error?: string;\n retry_in_ms?: number;\n};\n\nlet socket: WebSocket | null = null;\nlet retryTimer: NodeJS.Timeout | null = null;\nlet retryDelay = 1000;\nlet heartbeatTimer: NodeJS.Timeout | null = null;\nlet lastError = \"\";\nlet warnedMissingConfig = false;\nlet stopping = false;\n\nconst HEARTBEAT_INTERVAL_MS = 20_000;\n\n/** \u542F\u52A8\u65F6\u786E\u4FDD remote.json \u5B58\u5728,\u8FD4\u56DE\u73B0\u6709\u6216\u7A7A\u914D\u7F6E\uFF08\u5DF2\u5265\u79BB $schema\uFF09\u3002 */\nfunction loadConfig(): RemoteConfig {\n return loadEnsuredConfig(\n ROOT,\n \"remote.json\",\n \"remote\",\n { ...DEFAULT_REMOTE_CONFIG } as Record<string, unknown>\n ) as RemoteConfig;\n}\n\nfunction writeConfig(config: RemoteConfig): void {\n writeJson(configPath(ROOT, \"remote.json\"), withConfigSchema({ ...config } as Record<string, unknown>, \"remote\"));\n}\n\nfunction isService(value: string | undefined): value is ServiceName {\n return !!value && SERVICE_NAMES.includes(value as ServiceName);\n}\n\nfunction isAction(value: unknown): value is Task[\"action\"] {\n return value === \"status\" || value === \"start\" || value === \"stop\" || value === \"restart\" || value === \"send\";\n}\n\nfunction websocketUrl(controllerUrl: string, agentId: string): string {\n const url = new URL(controllerUrl);\n url.protocol = url.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n url.pathname = \"/v1/agent\";\n url.search = new URLSearchParams({ id: agentId }).toString();\n return url.toString();\n}\n\nfunction send(payload: unknown): void {\n if (socket?.readyState === WebSocket.OPEN) socket.send(JSON.stringify(payload));\n}\n\nfunction startHeartbeat(): void {\n stopHeartbeat();\n heartbeatTimer = setInterval(() => send({ type: \"ping\" }), HEARTBEAT_INTERVAL_MS);\n}\n\nfunction stopHeartbeat(): void {\n if (heartbeatTimer) {\n clearInterval(heartbeatTimer);\n heartbeatTimer = null;\n }\n}\n\nasync function execute(task: Task): Promise<unknown> {\n if (!isAction(task.action)) throw new Error(\"invalid task action\");\n if (task.action === \"status\") return { services: await serviceStatus() };\n if (!isService(task.service)) throw new Error(\"service is required and must be one of: \" + SERVICE_NAMES.join(\", \"));\n if (task.action === \"send\") {\n if (!task.message) throw new Error(\"message is required for send action\");\n return { output: await cmdSend(task.service, task.message), services: await serviceStatus() };\n }\n\n const output =\n task.action === \"start\"\n ? await cmdStart(task.service)\n : task.action === \"stop\"\n ? await cmdStop(task.service)\n : await cmdRestart(task.service);\n return { output, services: await serviceStatus() };\n}\n\nfunction scheduleReconnect(): void {\n if (retryTimer || stopping) return;\n const delay = retryDelay;\n retryTimer = setTimeout(() => {\n retryTimer = null;\n startRemoteAgent();\n }, delay);\n}\n\nfunction resetReconnect(reason?: string): void {\n retryDelay = 1000;\n if (reason) {\n lastError = reason;\n console.warn(`[remote-agent] ${reason} \u2014 will retry in ${retryDelay}ms`);\n }\n}\n\n/** Close the active socket (if any) and stop reconnecting. Idempotent. */\nexport function stopRemoteAgent(): void {\n stopping = true;\n stopHeartbeat();\n if (retryTimer) {\n clearTimeout(retryTimer);\n retryTimer = null;\n }\n if (socket) {\n try {\n socket.close(1000, \"client_shutdown\");\n } catch {\n /* ignore */\n }\n socket = null;\n }\n}\n\n/** Start one outbound-only remote-management connection for this supervisor process. */\nexport function startRemoteAgent(): void {\n if (stopping) return;\n if (socket || retryTimer) return;\n const config = loadConfig();\n if (!config.enabled || !config.controller_url || !config.agent_id || !config.agent_secret) {\n if (!warnedMissingConfig) {\n const missing: string[] = [];\n if (!config.enabled) missing.push(\"enabled\");\n if (!config.controller_url) missing.push(\"controller_url\");\n if (!config.agent_id) missing.push(\"agent_id\");\n if (!config.agent_secret) missing.push(\"agent_secret\");\n if (missing.length) {\n console.warn(`[remote-agent] disabled \u2014 missing remote.json fields: ${missing.join(\", \")} (run \\`sfmc remote enroll\\`)`);\n }\n warnedMissingConfig = true;\n }\n return;\n }\n warnedMissingConfig = true;\n\n let ws: WebSocket;\n try {\n ws = new WebSocket(websocketUrl(config.controller_url, config.agent_id));\n } catch (e) {\n resetReconnect(`failed to construct websocket: ${(e as Error).message}`);\n scheduleReconnect();\n return;\n }\n socket = ws;\n\n ws.on(\"open\", () => {\n retryDelay = 1000;\n lastError = \"\";\n void serviceStatus().then((status) => {\n send({ type: \"hello\", agentId: config.agent_id, secret: config.agent_secret, status });\n startHeartbeat();\n });\n });\n ws.on(\"message\", (raw) => {\n let msg: { type?: string };\n try {\n msg = JSON.parse(raw.toString()) as { type?: string };\n } catch {\n return;\n }\n if (msg.type === \"ping\") {\n send({ type: \"pong\" });\n return;\n }\n if (msg.type !== \"task\") return;\n const task = msg as Task;\n void execute(task)\n .then((result) => send({ type: \"task_result\", taskId: task.taskId, ok: true, result }))\n .catch((error: Error) => send({ type: \"task_result\", taskId: task.taskId, ok: false, error: error.message }));\n });\n ws.on(\"close\", (code, reason) => {\n if (socket === ws) socket = null;\n stopHeartbeat();\n if (stopping) return;\n resetReconnect(`disconnected (code=${code} ${reason.toString() || \"no_reason\"})`);\n scheduleReconnect();\n });\n ws.on(\"error\", (e) => {\n resetReconnect(`socket error: ${e.message}`);\n /* close event will follow and trigger reconnect */\n });\n}\n\nexport async function enrollRemoteAgent(controllerUrl: string, enrollmentToken: string, name: string): Promise<string> {\n const response = await fetch(new URL(\"/v1/enroll\", controllerUrl), {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", authorization: `Bearer ${enrollmentToken}` },\n body: JSON.stringify({ name }),\n });\n const result = (await response.json()) as { agentId?: string; agentSecret?: string; error?: string };\n if (!response.ok || !result.agentId || !result.agentSecret) throw new Error(result.error ?? \"enrollment failed\");\n\n writeConfig({ enabled: true, controller_url: controllerUrl, agent_id: result.agentId, agent_secret: result.agentSecret });\n return result.agentId;\n}\n\n/** Disable the remote agent: clear enabled flag and close the connection. */\nexport function disableRemoteAgent(): void {\n const config = loadConfig();\n if (config.agent_id || config.agent_secret) {\n writeConfig({ ...config, enabled: false });\n }\n stopRemoteAgent();\n stopping = false;\n}\n\nexport function remoteStatus(): RemoteStatus {\n const config = loadConfig();\n const result: RemoteStatus = { connected: socket?.readyState === WebSocket.OPEN };\n if (config.enabled !== undefined) result.enabled = config.enabled;\n if (config.controller_url) result.controller_url = config.controller_url;\n if (config.agent_id) result.agent_id = config.agent_id;\n if (lastError) {\n result.last_error = lastError;\n result.retry_in_ms = retryDelay;\n }\n return result;\n}"],
5
- "mappings": "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",
6
- "names": []
7
- }