mn-ws 0.1.0 → 0.2.0

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 (178) hide show
  1. package/assets/groups.json +10 -0
  2. package/assets/mn-ws/SKILL.md +55 -0
  3. package/assets/mn-ws/hooks.json +14 -0
  4. package/assets/mn-ws/install/inject-root.mjs +26 -0
  5. package/bin/ws.mjs +13 -0
  6. package/dist/core/auth.d.ts +194 -0
  7. package/dist/core/auth.d.ts.map +1 -0
  8. package/dist/core/auth.js +331 -0
  9. package/dist/core/auth.js.map +1 -0
  10. package/dist/core/brand.d.ts +11 -0
  11. package/dist/core/brand.d.ts.map +1 -0
  12. package/dist/core/brand.js +7 -0
  13. package/dist/core/brand.js.map +1 -0
  14. package/dist/core/bridge.d.ts +106 -0
  15. package/dist/core/bridge.d.ts.map +1 -0
  16. package/dist/core/bridge.js +308 -0
  17. package/dist/core/bridge.js.map +1 -0
  18. package/dist/core/config.d.ts +174 -0
  19. package/dist/core/config.d.ts.map +1 -0
  20. package/dist/core/config.js +417 -0
  21. package/dist/core/config.js.map +1 -0
  22. package/dist/core/controller.d.ts +64 -0
  23. package/dist/core/controller.d.ts.map +1 -0
  24. package/dist/core/controller.js +100 -0
  25. package/dist/core/controller.js.map +1 -0
  26. package/dist/core/errors/index.d.ts +30 -0
  27. package/dist/core/errors/index.d.ts.map +1 -0
  28. package/dist/core/errors/index.js +88 -0
  29. package/dist/core/errors/index.js.map +1 -0
  30. package/dist/core/open.d.ts +3 -0
  31. package/dist/core/open.d.ts.map +1 -0
  32. package/dist/core/open.js +27 -0
  33. package/dist/core/open.js.map +1 -0
  34. package/dist/core/paths.d.ts +15 -0
  35. package/dist/core/paths.d.ts.map +1 -0
  36. package/dist/core/paths.js +50 -0
  37. package/dist/core/paths.js.map +1 -0
  38. package/dist/core/serve-port.d.ts +73 -0
  39. package/dist/core/serve-port.d.ts.map +1 -0
  40. package/dist/core/serve-port.js +134 -0
  41. package/dist/core/serve-port.js.map +1 -0
  42. package/dist/core/session.d.ts +78 -0
  43. package/dist/core/session.d.ts.map +1 -0
  44. package/dist/core/session.js +124 -0
  45. package/dist/core/session.js.map +1 -0
  46. package/dist/core/skills/bus.d.ts +29 -0
  47. package/dist/core/skills/bus.d.ts.map +1 -0
  48. package/dist/core/skills/bus.js +114 -0
  49. package/dist/core/skills/bus.js.map +1 -0
  50. package/dist/core/skills/get.d.ts +17 -0
  51. package/dist/core/skills/get.d.ts.map +1 -0
  52. package/dist/core/skills/get.js +87 -0
  53. package/dist/core/skills/get.js.map +1 -0
  54. package/dist/core/skills/handlers.d.ts +22 -0
  55. package/dist/core/skills/handlers.d.ts.map +1 -0
  56. package/dist/core/skills/handlers.js +86 -0
  57. package/dist/core/skills/handlers.js.map +1 -0
  58. package/dist/core/skills/index.d.ts +47 -0
  59. package/dist/core/skills/index.d.ts.map +1 -0
  60. package/dist/core/skills/index.js +268 -0
  61. package/dist/core/skills/index.js.map +1 -0
  62. package/dist/core/skills/install.d.ts +18 -0
  63. package/dist/core/skills/install.d.ts.map +1 -0
  64. package/dist/core/skills/install.js +123 -0
  65. package/dist/core/skills/install.js.map +1 -0
  66. package/dist/core/skills/text-util.d.ts +2 -0
  67. package/dist/core/skills/text-util.d.ts.map +1 -0
  68. package/dist/core/skills/text-util.js +14 -0
  69. package/dist/core/skills/text-util.js.map +1 -0
  70. package/dist/core/store.d.ts +29 -0
  71. package/dist/core/store.d.ts.map +1 -0
  72. package/dist/core/store.js +100 -0
  73. package/dist/core/store.js.map +1 -0
  74. package/dist/core/views.d.ts +11 -0
  75. package/dist/core/views.d.ts.map +1 -0
  76. package/dist/core/views.js +20 -0
  77. package/dist/core/views.js.map +1 -0
  78. package/dist/index.d.ts +6 -0
  79. package/dist/index.d.ts.map +1 -0
  80. package/dist/index.js +8 -0
  81. package/dist/index.js.map +1 -0
  82. package/dist/modules/auth/index.d.ts +73 -0
  83. package/dist/modules/auth/index.d.ts.map +1 -0
  84. package/dist/modules/auth/index.js +64 -0
  85. package/dist/modules/auth/index.js.map +1 -0
  86. package/dist/modules/auth/service.d.ts +98 -0
  87. package/dist/modules/auth/service.d.ts.map +1 -0
  88. package/dist/modules/auth/service.js +200 -0
  89. package/dist/modules/auth/service.js.map +1 -0
  90. package/dist/modules/bridge/index.d.ts +73 -0
  91. package/dist/modules/bridge/index.d.ts.map +1 -0
  92. package/dist/modules/bridge/index.js +89 -0
  93. package/dist/modules/bridge/index.js.map +1 -0
  94. package/dist/modules/bridge/service.d.ts +75 -0
  95. package/dist/modules/bridge/service.d.ts.map +1 -0
  96. package/dist/modules/bridge/service.js +134 -0
  97. package/dist/modules/bridge/service.js.map +1 -0
  98. package/dist/modules/home/index.d.ts +95 -0
  99. package/dist/modules/home/index.d.ts.map +1 -0
  100. package/dist/modules/home/index.js +123 -0
  101. package/dist/modules/home/index.js.map +1 -0
  102. package/dist/modules/home/service.d.ts +48 -0
  103. package/dist/modules/home/service.d.ts.map +1 -0
  104. package/dist/modules/home/service.js +195 -0
  105. package/dist/modules/home/service.js.map +1 -0
  106. package/dist/modules/skill/index.d.ts +78 -0
  107. package/dist/modules/skill/index.d.ts.map +1 -0
  108. package/dist/modules/skill/index.js +132 -0
  109. package/dist/modules/skill/index.js.map +1 -0
  110. package/dist/runtime/api.d.ts +24 -0
  111. package/dist/runtime/api.d.ts.map +1 -0
  112. package/dist/runtime/api.js +140 -0
  113. package/dist/runtime/api.js.map +1 -0
  114. package/dist/runtime/cli.d.ts +23 -0
  115. package/dist/runtime/cli.d.ts.map +1 -0
  116. package/dist/runtime/cli.js +410 -0
  117. package/dist/runtime/cli.js.map +1 -0
  118. package/dist/runtime/help.d.ts +29 -0
  119. package/dist/runtime/help.d.ts.map +1 -0
  120. package/dist/runtime/help.js +89 -0
  121. package/dist/runtime/help.js.map +1 -0
  122. package/dist/runtime/registry.d.ts +318 -0
  123. package/dist/runtime/registry.d.ts.map +1 -0
  124. package/dist/runtime/registry.js +75 -0
  125. package/dist/runtime/registry.js.map +1 -0
  126. package/dist/runtime/server.d.ts +10 -0
  127. package/dist/runtime/server.d.ts.map +1 -0
  128. package/dist/runtime/server.js +127 -0
  129. package/dist/runtime/server.js.map +1 -0
  130. package/dist/runtime/spec.d.ts +32 -0
  131. package/dist/runtime/spec.d.ts.map +1 -0
  132. package/dist/runtime/spec.js +180 -0
  133. package/dist/runtime/spec.js.map +1 -0
  134. package/dist/runtime/types/action.d.ts +101 -0
  135. package/dist/runtime/types/action.d.ts.map +1 -0
  136. package/dist/runtime/types/action.js +19 -0
  137. package/dist/runtime/types/action.js.map +1 -0
  138. package/dist/runtime/types/client.d.ts +39 -0
  139. package/dist/runtime/types/client.d.ts.map +1 -0
  140. package/dist/runtime/types/client.js +2 -0
  141. package/dist/runtime/types/client.js.map +1 -0
  142. package/dist/runtime/types/http.d.ts +22 -0
  143. package/dist/runtime/types/http.d.ts.map +1 -0
  144. package/dist/runtime/types/http.js +6 -0
  145. package/dist/runtime/types/http.js.map +1 -0
  146. package/dist/runtime/types/module.d.ts +72 -0
  147. package/dist/runtime/types/module.d.ts.map +1 -0
  148. package/dist/runtime/types/module.js +15 -0
  149. package/dist/runtime/types/module.js.map +1 -0
  150. package/dist/web/public/assets/CliHints-BOxU-Duc.js +1 -0
  151. package/dist/web/public/assets/index-BTRKdMIW.js +50 -0
  152. package/dist/web/public/assets/index-BjGe8ggI.css +1 -0
  153. package/dist/web/public/assets/view-CE4tnCuy.js +1 -0
  154. package/dist/web/public/assets/view-CEQ2uPxE.js +1 -0
  155. package/dist/web/public/favicon-16.png +0 -0
  156. package/dist/web/public/favicon-32.png +0 -0
  157. package/dist/web/public/favicon-48.png +0 -0
  158. package/dist/web/public/favicon.ico +0 -0
  159. package/dist/web/public/index.html +19 -0
  160. package/dist/web/public/logo-rounded.png +0 -0
  161. package/dist/web/public/logo-rounded.svg +6 -0
  162. package/dist/web/public/logo.png +0 -0
  163. package/dist/web/public/logo.svg +6 -0
  164. package/package.json +52 -31
  165. package/README.md +0 -251
  166. package/bin/index.js +0 -714
  167. package/client/bridge-client.js +0 -160
  168. package/client/web.js +0 -234
  169. package/client/ws-client.js +0 -191
  170. package/lib/apps.js +0 -237
  171. package/lib/auth.js +0 -319
  172. package/lib/config.js +0 -534
  173. package/lib/index.js +0 -15
  174. package/lib/logger.js +0 -63
  175. package/lib/protocol.js +0 -208
  176. package/lib/store.js +0 -66
  177. package/server/auth.js +0 -274
  178. package/server/server.js +0 -752
@@ -0,0 +1,318 @@
1
+ export declare const MODULES: readonly [{
2
+ readonly id: "home";
3
+ readonly title: "首页";
4
+ readonly order: 1;
5
+ readonly actions: readonly [import("./types/action.js").TypedAction<{
6
+ readonly id: "home.bootstrap";
7
+ readonly cli: readonly ["bootstrap", "show"];
8
+ readonly http: readonly ["GET", "/api/bootstrap"];
9
+ readonly summary: "一次取齐面板启动所需的全部上下文";
10
+ }, {
11
+ app: {
12
+ name: string;
13
+ title: string;
14
+ description: string;
15
+ version: string;
16
+ };
17
+ storePath: string;
18
+ storeEnv: string;
19
+ commands: import("./help.js").CommandEntry[];
20
+ }>, import("./types/action.js").TypedAction<{
21
+ readonly id: "home.routes";
22
+ readonly cli: readonly ["routes"];
23
+ readonly http: readonly ["GET", "/api/routes"];
24
+ readonly summary: "列出 CLI 命令与 HTTP 路由的对照表";
25
+ }, {
26
+ status: "ok";
27
+ count: number;
28
+ routes: {
29
+ id: string;
30
+ module: string;
31
+ cli: string;
32
+ http: string | null;
33
+ summary: string | undefined;
34
+ }[];
35
+ }>, import("./types/action.js").TypedAction<{
36
+ readonly id: "home.health";
37
+ readonly cli: readonly ["health"];
38
+ readonly http: readonly ["GET", "/api/health"];
39
+ readonly summary: "自检:存储目录是否可写";
40
+ }, {
41
+ status: "ok" | "blocked";
42
+ storePath: string;
43
+ reason: string;
44
+ }>, import("./types/action.js").TypedAction<{
45
+ readonly id: "home.greet";
46
+ readonly cli: readonly ["greet"];
47
+ readonly http: readonly ["POST", "/api/greet"];
48
+ readonly summary: "打个招呼(演示动作:问候次数累计进本机存储)";
49
+ readonly args: readonly [{
50
+ readonly name: "name";
51
+ readonly required: true;
52
+ }];
53
+ readonly flags: {
54
+ readonly loud: {
55
+ readonly type: "boolean";
56
+ };
57
+ };
58
+ }, import("../modules/home/service.js").GreetingResult>, import("./types/action.js").TypedAction<{
59
+ readonly id: "setting.get";
60
+ readonly cli: readonly ["setting", "get"];
61
+ readonly http: readonly ["GET", "/api/settings"];
62
+ readonly summary: "读取全部设置(含头部导航分组 / 隐藏 / 平铺顺序)";
63
+ }, import("../modules/home/service.js").SettingsView>, import("./types/action.js").TypedAction<{
64
+ readonly id: "setting.set";
65
+ readonly cli: readonly ["setting", "set"];
66
+ readonly http: readonly ["PATCH", "/api/settings"];
67
+ readonly summary: "修改设置(PATCH 语义:只改传入的项)";
68
+ readonly flags: {
69
+ readonly key: {
70
+ readonly type: "string";
71
+ readonly hint: "设置项名";
72
+ };
73
+ readonly value: {
74
+ readonly type: "string";
75
+ readonly hint: "取值";
76
+ };
77
+ readonly set: {
78
+ readonly type: "kv";
79
+ readonly hint: "k=v,可重复(值可以是 JSON 数组,如 navGroups=[{...}])";
80
+ };
81
+ readonly 'dry-run': {
82
+ readonly type: "boolean";
83
+ };
84
+ };
85
+ }, {
86
+ status: "skipped";
87
+ dryRun: true;
88
+ wouldSet: Record<string, unknown>;
89
+ } | {
90
+ status: "ok";
91
+ settings: import("../core/store.js").Settings;
92
+ }>];
93
+ }, {
94
+ readonly id: "bridge";
95
+ readonly title: "桥接";
96
+ readonly order: 2;
97
+ readonly actions: readonly [import("./types/action.js").TypedAction<{
98
+ readonly id: "bridge.status";
99
+ readonly cli: readonly ["status"];
100
+ readonly http: readonly ["GET", "/api/bridge/status"];
101
+ readonly summary: "桥接状态:连没连、注册了哪些 app、当前凭据是谁";
102
+ }, import("../modules/bridge/service.js").BridgeStatusView>, import("./types/action.js").TypedAction<{
103
+ readonly id: "bridge.apps";
104
+ readonly cli: readonly ["apps"];
105
+ readonly http: readonly ["GET", "/api/bridge/apps"];
106
+ readonly summary: "列出可桥接的应用:白名单 + 本地端口存活探测";
107
+ }, import("../modules/bridge/service.js").BridgeAppsView>, import("./types/action.js").TypedAction<{
108
+ readonly id: "bridge.whitelist.set";
109
+ readonly cli: readonly ["apps", "set"];
110
+ readonly http: readonly ["POST", "/api/bridge/whitelist"];
111
+ readonly summary: "设置白名单(只有列出的应用会被桥;不给就一个都不桥)";
112
+ readonly flags: {
113
+ readonly apps: {
114
+ readonly type: "string";
115
+ readonly hint: "逗号分隔的应用名,如 nx-kv,nx-rh";
116
+ };
117
+ readonly ports: {
118
+ readonly type: "string";
119
+ readonly hint: "逗号分隔的本地端口(从已知表反查应用名)";
120
+ };
121
+ readonly 'app-map': {
122
+ readonly type: "string";
123
+ readonly hint: "显式基址,如 nx-kv=http://127.0.0.1:7999";
124
+ };
125
+ };
126
+ }, {
127
+ ok: boolean;
128
+ apps: string[];
129
+ applied: boolean;
130
+ }>, import("./types/action.js").TypedAction<{
131
+ readonly id: "bridge.catalog";
132
+ readonly cli: readonly ["catalog"];
133
+ readonly http: readonly ["GET", "/api/bridge/catalog"];
134
+ readonly summary: "拉远端 server 半的元信息目录(哪些能路由)";
135
+ }, import("../modules/bridge/service.js").CatalogView>, import("./types/action.js").TypedAction<{
136
+ readonly id: "bridge.start";
137
+ readonly cli: readonly ["bridge", "start"];
138
+ readonly http: readonly ["POST", "/api/bridge/start"];
139
+ readonly summary: "起桥(连 server 半并注册白名单里的应用)";
140
+ }, {
141
+ started: boolean;
142
+ apps: string[];
143
+ reason?: string;
144
+ }>, import("./types/action.js").TypedAction<{
145
+ readonly id: "bridge.stop";
146
+ readonly cli: readonly ["bridge", "stop"];
147
+ readonly http: readonly ["POST", "/api/bridge/stop"];
148
+ readonly summary: "停桥(断开 server 半,本机 nx 服务不受影响)";
149
+ }, {
150
+ stopped: boolean;
151
+ reason?: string;
152
+ }>, import("./types/action.js").TypedAction<{
153
+ readonly id: "bridge.known";
154
+ readonly cli: readonly ["apps", "known"];
155
+ readonly http: readonly ["GET", "/api/bridge/known"];
156
+ readonly summary: "列出已知的 nx 服务与它们的默认端口";
157
+ }, {
158
+ app: string;
159
+ port: number;
160
+ title: string;
161
+ }[]>];
162
+ }, {
163
+ readonly id: "auth";
164
+ readonly title: "登录";
165
+ readonly order: 3;
166
+ readonly actions: readonly [import("./types/action.js").TypedAction<{
167
+ readonly id: "auth.login";
168
+ readonly cli: readonly ["auth", "login"];
169
+ readonly http: readonly ["POST", "/api/auth/login/start"];
170
+ readonly summary: "统一登录(弹浏览器):换回设备令牌,之后免手填";
171
+ readonly flags: {
172
+ readonly 'new-account': {
173
+ readonly type: "boolean";
174
+ readonly hint: "强制认证中心重新登录(换人用)";
175
+ };
176
+ readonly 'no-open': {
177
+ readonly type: "boolean";
178
+ readonly hint: "只打印授权地址、不弹浏览器";
179
+ };
180
+ };
181
+ }, import("../modules/auth/service.js").LoginView>, import("./types/action.js").TypedAction<{
182
+ readonly id: "auth.list";
183
+ readonly cli: readonly ["auth", "list"];
184
+ readonly http: readonly ["GET", "/api/auth/accounts"];
185
+ readonly summary: "列出本机已存账号";
186
+ }, import("../modules/auth/service.js").AccountsView>, import("./types/action.js").TypedAction<{
187
+ readonly id: "auth.switch";
188
+ readonly cli: readonly ["auth", "switch"];
189
+ readonly http: readonly ["POST", "/api/auth/switch"];
190
+ readonly summary: "切换当前生效账号(序号/邮箱/用户名/昵称)";
191
+ readonly args: readonly [{
192
+ readonly name: "account";
193
+ readonly required: false;
194
+ }];
195
+ }, {
196
+ ok: boolean;
197
+ changed: boolean;
198
+ key?: string;
199
+ label?: string;
200
+ error?: string;
201
+ }>, import("./types/action.js").TypedAction<{
202
+ readonly id: "auth.status";
203
+ readonly cli: readonly ["auth", "status"];
204
+ readonly http: readonly ["GET", "/api/auth/status"];
205
+ readonly summary: "查看当前身份、令牌剩余有效期";
206
+ }, {
207
+ loggedIn: boolean;
208
+ userId?: string;
209
+ email?: string;
210
+ nickname?: string;
211
+ clientId: string;
212
+ serverHttp: string;
213
+ expiresAt?: number;
214
+ expired: boolean;
215
+ via: string;
216
+ }>, import("./types/action.js").TypedAction<{
217
+ readonly id: "auth.logout";
218
+ readonly cli: readonly ["auth", "logout"];
219
+ readonly http: readonly ["POST", "/api/auth/logout"];
220
+ readonly summary: "清除登录凭据(--all 清空全部账号)";
221
+ readonly flags: {
222
+ readonly all: {
223
+ readonly type: "boolean";
224
+ readonly hint: "清空全部账号";
225
+ };
226
+ };
227
+ }, {
228
+ ok: boolean;
229
+ remaining: number;
230
+ error?: string;
231
+ }>];
232
+ }, {
233
+ readonly id: "skill";
234
+ readonly title: "Skill";
235
+ readonly order: 20;
236
+ readonly actions: readonly [import("./types/action.js").TypedAction<{
237
+ readonly id: "skill.list";
238
+ readonly cli: readonly ["skill", "list"];
239
+ readonly http: readonly ["GET", "/api/skills"];
240
+ readonly summary: "列出可装的 skill 与 group";
241
+ }, {
242
+ skills: string[];
243
+ groups: string[];
244
+ defaultGroup: string | null;
245
+ source: "manifest" | "assets-dirs";
246
+ }>, import("./types/action.js").TypedAction<{
247
+ readonly id: "skill.groups";
248
+ readonly cli: readonly ["skill", "groups"];
249
+ readonly http: readonly ["GET", "/api/skill-groups"];
250
+ readonly summary: "列出每个 group 含哪些 skill";
251
+ }, {
252
+ source: "manifest" | "assets-dirs";
253
+ groups: Record<string, import("../core/skills/index.js").GroupSpec>;
254
+ warning: string | undefined;
255
+ }>, import("./types/action.js").TypedAction<{
256
+ readonly id: "skill.get";
257
+ readonly cli: readonly ["skill", "get"];
258
+ readonly http: readonly ["GET", "/api/skill-content"];
259
+ readonly summary: "导出 skill 文档(并幂等安装)";
260
+ readonly args: readonly [{
261
+ readonly name: "name";
262
+ readonly required: false;
263
+ }, {
264
+ readonly name: "ref";
265
+ readonly required: false;
266
+ }];
267
+ readonly flags: {
268
+ readonly to: {
269
+ readonly type: "string";
270
+ };
271
+ readonly force: {
272
+ readonly type: "boolean";
273
+ };
274
+ };
275
+ }, {
276
+ skillName: string;
277
+ ref: string;
278
+ contentBytes: number;
279
+ prefix: string;
280
+ content: string;
281
+ installStatus: string;
282
+ }>, import("./types/action.js").TypedAction<{
283
+ readonly id: "skill.install";
284
+ readonly cli: readonly ["skill", "install"];
285
+ readonly http: readonly ["POST", "/api/skill-install"];
286
+ readonly summary: "安装 skill、整组 skill 或全部 skill";
287
+ readonly args: readonly [{
288
+ readonly name: "name";
289
+ readonly required: false;
290
+ }];
291
+ readonly flags: {
292
+ readonly all: {
293
+ readonly type: "boolean";
294
+ };
295
+ readonly group: {
296
+ readonly type: "string";
297
+ };
298
+ readonly to: {
299
+ readonly type: "string";
300
+ };
301
+ readonly force: {
302
+ readonly type: "boolean";
303
+ };
304
+ };
305
+ }, import("../core/skills/index.js").InstallResult | import("../core/skills/index.js").GroupInstallResult>];
306
+ }];
307
+ export interface BoundAction {
308
+ id: string;
309
+ module: string;
310
+ cli: unknown;
311
+ http?: unknown;
312
+ web?: boolean;
313
+ run: (...a: unknown[]) => unknown;
314
+ [k: string]: unknown;
315
+ }
316
+ export declare const ACTIONS: BoundAction[];
317
+ export declare const CLI_ONLY_PREFIXES: string[];
318
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/runtime/registry.ts"],"names":[],"mappings":"AAoBA,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAA6C,CAAC;AAElE,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,OAAO,CAAC;IACb,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,GAAG,EAAE,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC;IAClC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AAED,eAAO,MAAM,OAAO,EAAE,WAAW,EAEhC,CAAC;AAgBF,eAAO,MAAM,iBAAiB,UAA+B,CAAC"}
@@ -0,0 +1,75 @@
1
+ // 模块注册表:所有功能域的 action 在此汇合。
2
+ //
3
+ // CLI 命令表、HTTP 路由表、help 文本三者全部由此派生 —— 这是
4
+ // 「Web 上每个操作都有等价 CLI 命令」得以成为**结构性保证**而非口头约定的原因:
5
+ // 一条 action 同时声明 cli 与 http,二者写在同一处,不可能分叉。
6
+ //
7
+ // 新增功能域只需两步:
8
+ // 1. 写 src/modules/<name>/(index.ts 声明 actions,service.ts 写业务,view.tsx 写面板)
9
+ // 2. 在下面 import 并加进 defineModules;再到 web/frontend/registry.ts 登记视图
10
+ // 编译期类型检查 + tests/unit 一致性断言,漏登记直接失败。
11
+ import { defineModules } from './types/module.js';
12
+ import { cliPathsOf } from './spec.js';
13
+ import home from '../modules/home/index.js';
14
+ import bridge from '../modules/bridge/index.js';
15
+ import auth from '../modules/auth/index.js';
16
+ import skill from '../modules/skill/index.js';
17
+ // 编译期:defineModules 对模块/action id、CLI/HTTP 键查重 + 路由歧义检测;
18
+ // 运行时:按 order 排序。
19
+ export const MODULES = defineModules([home, bridge, auth, skill]);
20
+ export const ACTIONS = MODULES.flatMap((m) => (m.actions || []).map((a) => ({ ...a, module: m.id })));
21
+ // 装载期自检(运行时防线,与编译期检查互为备份):
22
+ // 把「两个模块声明了同名命令」这类问题暴露在启动瞬间,
23
+ // 而不是等某个用户敲到那条命令时才发现。
24
+ //
25
+ // 方向性约定(刻意的不对称):
26
+ // - 每条 action 都必须有 cli —— 保证「Web 上能做的,CLI 都能做」
27
+ // - 有 http 才谈得上 Web 入口;http: null 只留给两类:
28
+ // a) 豁免前缀(serve / server / skill —— 天然是 CLI 侧能力)
29
+ // b) 显式 web: false(这个操作就是不给面板入口)
30
+ // 其余 http: null 一律视为漏声明,启动即失败(与 eslint 的 local/action-parity 同规)
31
+ // - 不允许声明 http 却没有 cli,也不允许 http 与 web: false 同时出现
32
+ //
33
+ // 豁免前缀必须与 eslint.config.js 里 local/action-parity 的 cliOnlyPrefixes 一致,
34
+ // tests/unit/registry.test.mjs 会对账。
35
+ export const CLI_ONLY_PREFIXES = ['serve', 'server', 'skill'];
36
+ const seenIds = new Set();
37
+ const seenCli = new Set();
38
+ const seenHttp = new Set();
39
+ for (const a of ACTIONS) {
40
+ if (seenIds.has(a.id))
41
+ throw new Error('action id 重复: ' + a.id);
42
+ seenIds.add(a.id);
43
+ const paths = cliPathsOf(a);
44
+ if (!paths.length)
45
+ throw new Error(`action 没有声明 CLI 命令(Web 操作必须有 CLI 等价): ${a.id}`);
46
+ for (const path of paths) {
47
+ const key = path.join(' ');
48
+ if (seenCli.has(key))
49
+ throw new Error(`CLI 命令重复: ${key}(action ${a.id})`);
50
+ seenCli.add(key);
51
+ }
52
+ const http = a.http;
53
+ if (http) {
54
+ const [method, pattern] = http;
55
+ const httpKey = method + ' ' + pattern;
56
+ if (seenHttp.has(httpKey))
57
+ throw new Error(`HTTP 路由重复: ${httpKey}(action ${a.id})`);
58
+ seenHttp.add(httpKey);
59
+ if (a.web === false) {
60
+ throw new Error(`action 同时声明了 http 与 web: false,语义冲突: ${a.id}`);
61
+ }
62
+ }
63
+ else if (http === null) {
64
+ const segment = paths[0]?.[0];
65
+ if (a.web !== false && !(segment && CLI_ONLY_PREFIXES.includes(segment))) {
66
+ throw new Error(`action 没有声明 HTTP 路由(CLI 与 Web 必须成对;纯 CLI 请显式 web: false 或使用豁免前缀): ${a.id}`);
67
+ }
68
+ }
69
+ else {
70
+ throw new Error(`action 的 http 必须是路由数组或显式 null: ${a.id}`);
71
+ }
72
+ if (!a.run)
73
+ throw new Error(`action 缺少 run: ${a.id}`);
74
+ }
75
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/runtime/registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { IncomingMessage, ServerResponse, Server as HttpServer } from 'node:http';
2
+ import type { MnWsController } from '../core/controller.js';
3
+ export interface StartServerOptions {
4
+ port?: number;
5
+ host?: string;
6
+ /** 运行时控制器(登录态 + 桥)。传了就启用登录门禁与 /callback 路由。 */
7
+ controller?: MnWsController | null;
8
+ }
9
+ export declare function startServer({ port, host, controller }?: StartServerOptions): Promise<HttpServer<typeof IncomingMessage, typeof ServerResponse>>;
10
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/runtime/server.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,WAAW,CAAC;AAOvF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAiD5D,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,+CAA+C;IAC/C,UAAU,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;CACpC;AAED,wBAAgB,WAAW,CAAC,EAAE,IAAmB,EAAE,IAAkB,EAAE,UAAiB,EAAE,GAAE,kBAAuB,GAAG,OAAO,CAC3H,UAAU,CAAC,OAAO,eAAe,EAAE,OAAO,cAAc,CAAC,CAC1D,CAkCA"}
@@ -0,0 +1,127 @@
1
+ // Web 服务器:node:http 零依赖。
2
+ //
3
+ // 职责三件:
4
+ // 1. 发静态面板文件
5
+ // 2. 把 /api/* 交给路由层(见 api.ts)
6
+ // 3. **登录门禁**:未登录时业务 API 一律 401;以及 OIDC 回调路由 /callback
7
+ //
8
+ // 为什么门禁在服务端而不是前端:面板握着桥的凭据(能连 server、能改白名单),
9
+ // 「打开就能用」等于「任何能访问这个端口的东西都能用」。
10
+ // 门禁一旦只做在前端(藏个按钮),任何本机进程照样能直接调 API。
11
+ import http from 'node:http';
12
+ import { extname, resolve, sep } from 'node:path';
13
+ import { fileURLToPath } from 'node:url';
14
+ import fsp from 'node:fs/promises';
15
+ import { handleApi, sendJson, setApiGate, defaultApiGate } from './api.js';
16
+ import { DEFAULT_PORT } from '../core/paths.js';
17
+ import { asAbsolutePath } from '../core/brand.js';
18
+ // vite 的 outDir:
19
+ // 构建后 dist/runtime/server.js → dist/web/public
20
+ // 源码态 src/runtime/server.ts → src/web/public(dev 下由 vite 直接服务,仅兜底)
21
+ const PUBLIC_DIR = asAbsolutePath(resolve(fileURLToPath(new URL('../web/public/', import.meta.url))));
22
+ const MIME = {
23
+ '.html': 'text/html; charset=utf-8',
24
+ '.js': 'text/javascript; charset=utf-8',
25
+ '.mjs': 'text/javascript; charset=utf-8',
26
+ '.css': 'text/css; charset=utf-8',
27
+ '.json': 'application/json; charset=utf-8',
28
+ '.svg': 'image/svg+xml',
29
+ '.png': 'image/png',
30
+ '.jpg': 'image/jpeg',
31
+ '.webp': 'image/webp',
32
+ '.ico': 'image/x-icon',
33
+ '.woff2': 'font/woff2',
34
+ '.map': 'application/json; charset=utf-8',
35
+ };
36
+ async function serveStatic(pathname, res) {
37
+ const rel = pathname === '/' ? 'index.html' : decodeURIComponent(pathname).replace(/^\/+/, '');
38
+ const file = resolve(PUBLIC_DIR, rel);
39
+ // 越界校验:解析成绝对路径后必须仍落在 PUBLIC_DIR 内。
40
+ // 比对解析结果,而不是剥离 '..' 字面量——后者挡不住编码变形。
41
+ if (file !== PUBLIC_DIR && !file.startsWith(PUBLIC_DIR + sep)) {
42
+ res.writeHead(403, { 'content-type': 'text/plain; charset=utf-8' });
43
+ res.end('Forbidden');
44
+ return;
45
+ }
46
+ try {
47
+ const buf = await fsp.readFile(file);
48
+ res.writeHead(200, {
49
+ 'content-type': MIME[extname(file).toLowerCase()] || 'application/octet-stream',
50
+ 'cache-control': 'no-store',
51
+ });
52
+ res.end(buf);
53
+ }
54
+ catch {
55
+ res.writeHead(404, { 'content-type': 'text/plain; charset=utf-8' });
56
+ res.end('Not Found');
57
+ }
58
+ }
59
+ export function startServer({ port = DEFAULT_PORT, host = '127.0.0.1', controller = null } = {}) {
60
+ // 装登录门禁(没有 controller 就不设 —— 开发态可能只想看静态页)
61
+ setApiGate(controller ? defaultApiGate(() => controller.session.snapshot().loggedIn) : null);
62
+ const server = http.createServer(async (req, res) => {
63
+ try {
64
+ const url = new URL(req.url || '/', `http://${req.headers.host || 'localhost'}`);
65
+ // ── OIDC 回调:浏览器把授权码送回面板的 /callback ──
66
+ //
67
+ // 放在 /api 之前:它不是 API,是认证中心指定的固定回调地址。
68
+ // 路径固定 /callback、端口通配 —— 与 go-ah 里 mn-ws-client 的白名单一致。
69
+ if (url.pathname === '/callback' && controller) {
70
+ await handleCallback(url, res, controller);
71
+ return;
72
+ }
73
+ if (url.pathname.startsWith('/api/')) {
74
+ await handleApi(req, res, url);
75
+ return;
76
+ }
77
+ await serveStatic(url.pathname, res);
78
+ }
79
+ catch (err) {
80
+ sendJson(res, 500, {
81
+ ok: false,
82
+ error: String(err?.message || err),
83
+ code: 'INTERNAL',
84
+ });
85
+ }
86
+ });
87
+ return new Promise((resolve_, reject) => {
88
+ server.once('error', reject);
89
+ server.listen(port, host, () => resolve_(server));
90
+ });
91
+ }
92
+ /**
93
+ * 处理 OIDC 回调:收回调 → 换 access_token → 换设备令牌 → 存账号簿。
94
+ *
95
+ * 失败时**如实说失败**:页面显示错误 + 原因,而不是一个「登录成功」的假象。
96
+ */
97
+ async function handleCallback(url, res, controller) {
98
+ const code = url.searchParams.get('code') || '';
99
+ const state = url.searchParams.get('state') || '';
100
+ const err = url.searchParams.get('error');
101
+ if (err) {
102
+ res.writeHead(200, { 'content-type': 'text/html; charset=utf-8' });
103
+ res.end(`<h3>授权未通过</h3><p>${escapeHtml(err)}</p><p>可以关闭这个页面了。</p>`);
104
+ return;
105
+ }
106
+ try {
107
+ const session = await controller.session.completeLogin(code, state);
108
+ res.writeHead(200, { 'content-type': 'text/html; charset=utf-8' });
109
+ res.end(`<h3>✅ 已登录</h3><p>${escapeHtml(session.nickname || session.email || session.userId || '已登录')}</p>`
110
+ + '<p>可以关闭这个页面,回到面板了。</p>');
111
+ }
112
+ catch (e) {
113
+ res.writeHead(400, { 'content-type': 'text/html; charset=utf-8' });
114
+ res.end(`<h3>登录失败</h3><p>${escapeHtml(e.message)}</p>`
115
+ + '<p>可以关闭这个页面,回到面板重试。</p>');
116
+ }
117
+ }
118
+ /** 最小 HTML 转义:回调页会回显错误文本,不能让它变成可执行脚本。 */
119
+ function escapeHtml(s) {
120
+ return String(s)
121
+ .replace(/&/g, '&amp;')
122
+ .replace(/</g, '&lt;')
123
+ .replace(/>/g, '&gt;')
124
+ .replace(/"/g, '&quot;')
125
+ .replace(/'/g, '&#39;');
126
+ }
127
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/runtime/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import type { ActionShape, ArgEntry, FlagSpec, CtxOf } from './types/action.js';
2
+ export declare function cliPathsOf(action: {
3
+ cli: ActionShape['cli'];
4
+ }): string[][];
5
+ export interface ResolvedArg {
6
+ name: string;
7
+ required: boolean;
8
+ rest?: boolean;
9
+ }
10
+ export declare function argSpecsOf(action: {
11
+ args?: readonly ArgEntry[];
12
+ }): ResolvedArg[];
13
+ export interface ResolvedFlag extends FlagSpec {
14
+ name: string;
15
+ }
16
+ export declare function flagSpecsOf(action: {
17
+ flags?: Record<string, FlagSpec>;
18
+ }): ResolvedFlag[];
19
+ export declare function booleanFlagNames(action: {
20
+ flags?: Record<string, FlagSpec>;
21
+ }): Set<string>;
22
+ export declare function applySpec<const A extends ActionShape>(action: A, raw: Record<string, unknown>): CtxOf<A>;
23
+ export interface CompiledRoute {
24
+ method: string;
25
+ keys: string[];
26
+ regex: RegExp;
27
+ }
28
+ export declare function compileRoute(action: ActionShape & {
29
+ http: readonly [string, string];
30
+ }): CompiledRoute;
31
+ export declare function usageOf(action: ActionShape): string;
32
+ //# sourceMappingURL=spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec.d.ts","sourceRoot":"","sources":["../../src/runtime/spec.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAOhF,wBAAgB,UAAU,CAAC,MAAM,EAAE;IAAE,GAAG,EAAE,WAAW,CAAC,KAAK,CAAC,CAAA;CAAE,GAAG,MAAM,EAAE,EAAE,CAK1E;AAGD,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE;IAAE,IAAI,CAAC,EAAE,SAAS,QAAQ,EAAE,CAAA;CAAE,GAAG,WAAW,EAAE,CAMhF;AAED,MAAM,WAAW,YAAa,SAAQ,QAAQ;IAC5C,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;CAAE,GAAG,YAAY,EAAE,CAExF;AAID,wBAAgB,gBAAgB,CAAC,MAAM,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;CAAE,GAAG,GAAG,CAAC,MAAM,CAAC,CAM1F;AAgED,wBAAgB,SAAS,CAAC,KAAK,CAAC,CAAC,SAAS,WAAW,EAAE,MAAM,EAAE,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAsBxG;AAID,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAID,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,GAAG;IAAE,IAAI,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GAAG,aAAa,CAgBrG;AAID,wBAAgB,OAAO,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CA2BnD"}