create-windy 0.3.0 → 0.3.1

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 (40) hide show
  1. package/README.md +26 -3
  2. package/dist/cli.js +8077 -3852
  3. package/package.json +3 -3
  4. package/template/.windy-template.json +2 -2
  5. package/template/README.md +25 -3
  6. package/template/_gitignore +4 -0
  7. package/template/apps/agent-server/tests/__init__.py +1 -0
  8. package/template/apps/agent-server/tests/openai_provider_test_support.py +131 -0
  9. package/template/apps/agent-server/tests/test_openai_provider.py +7 -123
  10. package/template/apps/server/src/auth/routes.test-support.ts +94 -0
  11. package/template/apps/server/src/auth/routes.test.ts +20 -88
  12. package/template/apps/server/src/index.ts +17 -34
  13. package/template/apps/server/src/mcp/adapter.test.ts +3 -2
  14. package/template/apps/server/src/mcp/adapter.ts +9 -9
  15. package/template/apps/server/src/mcp/routes.ts +4 -3
  16. package/template/apps/server/src/platform-http-runtime.ts +87 -0
  17. package/template/apps/server/src/system/drizzle-system-configs.ts +319 -0
  18. package/template/apps/server/src/system/drizzle-system.ts +35 -315
  19. package/template/apps/server/src/system/resource-routes.ts +270 -0
  20. package/template/apps/server/src/system/routes.ts +3 -269
  21. package/template/apps/web/src/pages/system/components/SystemResourceLoadError.vue +21 -0
  22. package/template/apps/web/src/pages/system/components/SystemResourceLoadError.webtest.ts +17 -0
  23. package/template/apps/web/src/pages/system/components/SystemResourcePage.vue +5 -10
  24. package/template/docs/architecture/mcp-business-capabilities.md +107 -0
  25. package/template/docs/development/custom-login-page.md +3 -3
  26. package/template/docs/platform/agent-runtime.md +5 -5
  27. package/template/docs/platform/agent-tools.md +4 -0
  28. package/template/packages/modules/package.json +1 -1
  29. package/template/packages/modules/src/composition-fixtures.test-support.ts +164 -0
  30. package/template/packages/modules/src/composition.test.ts +5 -158
  31. package/template/packages/modules/src/system-api-operational.ts +234 -0
  32. package/template/packages/modules/src/system-api-permissions.ts +8 -229
  33. package/template/packages/modules/src/system-module-tasks.ts +86 -0
  34. package/template/packages/modules/src/system-modules-access.test.ts +60 -0
  35. package/template/packages/modules/src/system-modules.test.ts +0 -53
  36. package/template/packages/modules/src/system-modules.ts +2 -84
  37. package/template/packages/shared/index.ts +1 -0
  38. package/template/packages/shared/package.json +1 -1
  39. package/template/packages/shared/src/mcp.test.ts +12 -0
  40. package/template/packages/shared/src/mcp.ts +7 -0
@@ -0,0 +1,164 @@
1
+ import type { ModuleManifest } from "./manifest.js";
2
+ import { featureKey } from "@southwind-ai/shared";
3
+
4
+ export function fixture(
5
+ name: string,
6
+ dependencies: string[] = [],
7
+ ): ModuleManifest {
8
+ const featureKey = `${name}.feature`;
9
+ const readPermission = `${name}.read`;
10
+ const managePermission = `${name}.manage`;
11
+ return {
12
+ name,
13
+ version: "0.1.0",
14
+ label: name,
15
+ description: `${name} module`,
16
+ dependencies,
17
+ menus: [
18
+ {
19
+ key: `${name}.page`,
20
+ title: name,
21
+ type: "menu",
22
+ order: 1,
23
+ visible: true,
24
+ path: `/${name}`,
25
+ permissionKey: readPermission,
26
+ featureKey,
27
+ },
28
+ ],
29
+ adminRoutes: [
30
+ {
31
+ key: `${name}.page`,
32
+ path: `/${name}`,
33
+ title: name,
34
+ surface: "sidebar",
35
+ permissionKey: readPermission,
36
+ featureKey,
37
+ },
38
+ ],
39
+ permissions: [
40
+ permission(name, readPermission, "read"),
41
+ permission(name, managePermission, "manage"),
42
+ ],
43
+ apiPermissions: [
44
+ {
45
+ method: "GET",
46
+ path: `/api/${name}`,
47
+ permissionKey: readPermission,
48
+ featureKey,
49
+ },
50
+ ],
51
+ features: [
52
+ {
53
+ key: featureKey,
54
+ label: name,
55
+ module: name,
56
+ visible: "visible",
57
+ enabled: true,
58
+ stage: "stable",
59
+ },
60
+ ],
61
+ migrations: [],
62
+ schemaExports: [
63
+ {
64
+ key: `${name}.schema`,
65
+ exportName: `${name}Table`,
66
+ migrationIds: [`${name}.001`],
67
+ },
68
+ ],
69
+ jsonSchemas: [
70
+ {
71
+ key: `${name}.tool.input.v1`,
72
+ schema: { type: "object" },
73
+ },
74
+ {
75
+ key: `${name}.tool.output.v1`,
76
+ schema: { type: "object" },
77
+ },
78
+ ],
79
+ tasks: [
80
+ {
81
+ key: `${name}.task`,
82
+ label: name,
83
+ description: name,
84
+ permissionKey: managePermission,
85
+ featureKey,
86
+ intervalSeconds: 60,
87
+ maxAttempts: 3,
88
+ retryDelaySeconds: 10,
89
+ },
90
+ ],
91
+ tools: [
92
+ {
93
+ key: `${name}.tool`,
94
+ label: name,
95
+ description: name,
96
+ inputSchemaKey: `${name}.tool.input.v1`,
97
+ outputSchemaKey: `${name}.tool.output.v1`,
98
+ operation: "query",
99
+ permissionKey: readPermission,
100
+ featureKey,
101
+ auditAction: "agent.tool.execute",
102
+ scopeMode: "request",
103
+ dataClassification: "internal",
104
+ idempotency: "none",
105
+ approval: "none",
106
+ limits: {
107
+ maxDurationSeconds: 10,
108
+ maxInputBytes: 4096,
109
+ maxOutputBytes: 4096,
110
+ },
111
+ },
112
+ ],
113
+ providers: [
114
+ {
115
+ key: `${name}.provider`,
116
+ kind: "fixture",
117
+ contractVersion: "1",
118
+ permissionKey: readPermission,
119
+ featureKey,
120
+ },
121
+ ],
122
+ auditActions: ["agent.tool.execute"],
123
+ };
124
+ }
125
+
126
+ export function dataPolicy(): NonNullable<
127
+ ModuleManifest["dataPolicies"]
128
+ >[number] {
129
+ return {
130
+ key: "system.user.fields",
131
+ resourceType: "system.user",
132
+ version: "1",
133
+ featureKey: featureKey("system.feature"),
134
+ readPermissionKey: "system.read",
135
+ revealPermissionKey: "system.reveal",
136
+ exportPermissionKey: "system.export",
137
+ display: {
138
+ read: "masked",
139
+ reveal: "plaintext",
140
+ unauthorized: "hidden",
141
+ },
142
+ fields: [
143
+ {
144
+ fieldKey: "phone",
145
+ classification: "sensitive",
146
+ mask: { kind: "partial", prefix: 3, suffix: 4 },
147
+ },
148
+ ],
149
+ };
150
+ }
151
+
152
+ export function permission(
153
+ module: string,
154
+ key: string,
155
+ action: "read" | "manage",
156
+ ): ModuleManifest["permissions"][number] {
157
+ return {
158
+ key,
159
+ label: action,
160
+ module,
161
+ resource: "fixture",
162
+ action,
163
+ };
164
+ }
@@ -1,6 +1,10 @@
1
1
  import { describe, expect, test } from "bun:test";
2
2
  import { featureKey, licenseVersionKey } from "@southwind-ai/shared";
3
- import type { ModuleManifest } from "./manifest.js";
3
+ import {
4
+ dataPolicy,
5
+ fixture,
6
+ permission,
7
+ } from "./composition-fixtures.test-support.js";
4
8
  import { validateModuleComposition } from "./composition.js";
5
9
 
6
10
  describe("Module Composition 契约", () => {
@@ -223,160 +227,3 @@ describe("Module Composition 契约", () => {
223
227
  );
224
228
  });
225
229
  });
226
-
227
- function fixture(name: string, dependencies: string[] = []): ModuleManifest {
228
- const featureKey = `${name}.feature`;
229
- const readPermission = `${name}.read`;
230
- const managePermission = `${name}.manage`;
231
- return {
232
- name,
233
- version: "0.1.0",
234
- label: name,
235
- description: `${name} module`,
236
- dependencies,
237
- menus: [
238
- {
239
- key: `${name}.page`,
240
- title: name,
241
- type: "menu",
242
- order: 1,
243
- visible: true,
244
- path: `/${name}`,
245
- permissionKey: readPermission,
246
- featureKey,
247
- },
248
- ],
249
- adminRoutes: [
250
- {
251
- key: `${name}.page`,
252
- path: `/${name}`,
253
- title: name,
254
- surface: "sidebar",
255
- permissionKey: readPermission,
256
- featureKey,
257
- },
258
- ],
259
- permissions: [
260
- permission(name, readPermission, "read"),
261
- permission(name, managePermission, "manage"),
262
- ],
263
- apiPermissions: [
264
- {
265
- method: "GET",
266
- path: `/api/${name}`,
267
- permissionKey: readPermission,
268
- featureKey,
269
- },
270
- ],
271
- features: [
272
- {
273
- key: featureKey,
274
- label: name,
275
- module: name,
276
- visible: "visible",
277
- enabled: true,
278
- stage: "stable",
279
- },
280
- ],
281
- migrations: [],
282
- schemaExports: [
283
- {
284
- key: `${name}.schema`,
285
- exportName: `${name}Table`,
286
- migrationIds: [`${name}.001`],
287
- },
288
- ],
289
- jsonSchemas: [
290
- {
291
- key: `${name}.tool.input.v1`,
292
- schema: { type: "object" },
293
- },
294
- {
295
- key: `${name}.tool.output.v1`,
296
- schema: { type: "object" },
297
- },
298
- ],
299
- tasks: [
300
- {
301
- key: `${name}.task`,
302
- label: name,
303
- description: name,
304
- permissionKey: managePermission,
305
- featureKey,
306
- intervalSeconds: 60,
307
- maxAttempts: 3,
308
- retryDelaySeconds: 10,
309
- },
310
- ],
311
- tools: [
312
- {
313
- key: `${name}.tool`,
314
- label: name,
315
- description: name,
316
- inputSchemaKey: `${name}.tool.input.v1`,
317
- outputSchemaKey: `${name}.tool.output.v1`,
318
- operation: "query",
319
- permissionKey: readPermission,
320
- featureKey,
321
- auditAction: "agent.tool.execute",
322
- scopeMode: "request",
323
- dataClassification: "internal",
324
- idempotency: "none",
325
- approval: "none",
326
- limits: {
327
- maxDurationSeconds: 10,
328
- maxInputBytes: 4096,
329
- maxOutputBytes: 4096,
330
- },
331
- },
332
- ],
333
- providers: [
334
- {
335
- key: `${name}.provider`,
336
- kind: "fixture",
337
- contractVersion: "1",
338
- permissionKey: readPermission,
339
- featureKey,
340
- },
341
- ],
342
- auditActions: ["agent.tool.execute"],
343
- };
344
- }
345
-
346
- function dataPolicy(): NonNullable<ModuleManifest["dataPolicies"]>[number] {
347
- return {
348
- key: "system.user.fields",
349
- resourceType: "system.user",
350
- version: "1",
351
- featureKey: featureKey("system.feature"),
352
- readPermissionKey: "system.read",
353
- revealPermissionKey: "system.reveal",
354
- exportPermissionKey: "system.export",
355
- display: {
356
- read: "masked",
357
- reveal: "plaintext",
358
- unauthorized: "hidden",
359
- },
360
- fields: [
361
- {
362
- fieldKey: "phone",
363
- classification: "sensitive",
364
- mask: { kind: "partial", prefix: 3, suffix: 4 },
365
- },
366
- ],
367
- };
368
- }
369
-
370
- function permission(
371
- module: string,
372
- key: string,
373
- action: "read" | "manage",
374
- ): ModuleManifest["permissions"][number] {
375
- return {
376
- key,
377
- label: action,
378
- module,
379
- resource: "fixture",
380
- action,
381
- };
382
- }
@@ -0,0 +1,234 @@
1
+ import type { ApiPermissionBinding } from "@southwind-ai/shared";
2
+ // oxlint-disable-next-line no-unused-vars -- 可选模块全部裁剪后该导入仍需保留类型稳定的生成源码。
3
+ import { binding } from "./system-api-binding.js";
4
+
5
+ export function systemOperationalApiPermissionBindings(): ApiPermissionBinding[] {
6
+ return [
7
+ // @windy-module system.storage begin
8
+ binding(
9
+ "POST",
10
+ "/api/system/storage/uploads",
11
+ "system.storage.create",
12
+ "system.storage",
13
+ ),
14
+ binding(
15
+ "GET",
16
+ "/api/system/storage/uploads/:id",
17
+ "system.storage.create",
18
+ "system.storage",
19
+ ),
20
+ binding(
21
+ "PUT",
22
+ "/api/system/storage/uploads/:id/parts/:partNumber",
23
+ "system.storage.create",
24
+ "system.storage",
25
+ ),
26
+ binding(
27
+ "POST",
28
+ "/api/system/storage/uploads/:id/complete",
29
+ "system.storage.create",
30
+ "system.storage",
31
+ ),
32
+ binding(
33
+ "DELETE",
34
+ "/api/system/storage/uploads/:id",
35
+ "system.storage.create",
36
+ "system.storage",
37
+ ),
38
+ binding(
39
+ "GET",
40
+ "/api/system/storage/files/:id",
41
+ "system.storage.read",
42
+ "system.storage",
43
+ ),
44
+ binding(
45
+ "GET",
46
+ "/api/platform/files/:id",
47
+ "system.settings.read",
48
+ "system.settings",
49
+ true,
50
+ ),
51
+ // @windy-module system.storage end
52
+ // @windy-module system.operations begin
53
+ binding("GET", "/api/system/operations", "system.ops.read", "system.ops"),
54
+ // @windy-module system.operations end
55
+ // @windy-module system.notification begin
56
+ binding(
57
+ "GET",
58
+ "/api/notifications",
59
+ "system.notification.read",
60
+ "system.notification",
61
+ ),
62
+ binding(
63
+ "GET",
64
+ "/api/notifications/preferences",
65
+ "system.notification.read",
66
+ "system.notification",
67
+ ),
68
+ binding(
69
+ "PUT",
70
+ "/api/notifications/preferences",
71
+ "system.notification.read",
72
+ "system.notification",
73
+ ),
74
+ binding(
75
+ "POST",
76
+ "/api/notifications/:id/read",
77
+ "system.notification.read",
78
+ "system.notification",
79
+ ),
80
+ binding(
81
+ "PUT",
82
+ "/api/notifications/:id/favorite",
83
+ "system.notification.read",
84
+ "system.notification",
85
+ ),
86
+ binding(
87
+ "DELETE",
88
+ "/api/notifications/:id/favorite",
89
+ "system.notification.read",
90
+ "system.notification",
91
+ ),
92
+ binding(
93
+ "GET",
94
+ "/api/system/notifications/audience-options",
95
+ "system.notification.manage",
96
+ "system.notification",
97
+ ),
98
+ binding(
99
+ "GET",
100
+ "/api/system/notifications/:id/deliveries",
101
+ "system.notification.manage",
102
+ "system.notification",
103
+ ),
104
+ binding(
105
+ "GET",
106
+ "/api/system/notifications",
107
+ "system.notification.manage",
108
+ "system.notification",
109
+ ),
110
+ binding(
111
+ "POST",
112
+ "/api/system/notifications",
113
+ "system.notification.manage",
114
+ "system.notification",
115
+ ),
116
+ binding(
117
+ "PUT",
118
+ "/api/system/notifications/:id",
119
+ "system.notification.update",
120
+ "system.notification",
121
+ ),
122
+ binding(
123
+ "GET",
124
+ "/api/system/notifications/:id/revisions",
125
+ "system.notification.manage",
126
+ "system.notification",
127
+ ),
128
+ binding(
129
+ "DELETE",
130
+ "/api/system/notifications/:id",
131
+ "system.notification.manage",
132
+ "system.notification",
133
+ ),
134
+ // @windy-module system.notification end
135
+ // @windy-module system.workflow begin
136
+ binding(
137
+ "GET",
138
+ "/api/workflow/work-items",
139
+ "system.workflow.read",
140
+ "system.workflow",
141
+ ),
142
+ binding(
143
+ "GET",
144
+ "/api/workflow/work-items/:id",
145
+ "system.workflow.read",
146
+ "system.workflow",
147
+ ),
148
+ binding(
149
+ "GET",
150
+ "/api/workflow/work-items/:id/history",
151
+ "system.workflow.read",
152
+ "system.workflow",
153
+ ),
154
+ binding(
155
+ "POST",
156
+ "/api/workflow/work-items",
157
+ "system.workflow.create",
158
+ "system.workflow",
159
+ ),
160
+ ...["claim", "transfer", "approve", "reject", "cancel"].map((command) =>
161
+ binding(
162
+ "POST",
163
+ `/api/workflow/work-items/:id/${command}`,
164
+ "system.workflow.approve",
165
+ "system.workflow",
166
+ ),
167
+ ),
168
+ // @windy-module system.workflow end
169
+ // @windy-module system.scheduler begin
170
+ binding(
171
+ "GET",
172
+ "/api/system/scheduled-tasks",
173
+ "system.scheduler.read",
174
+ "system.scheduler",
175
+ ),
176
+ binding(
177
+ "GET",
178
+ "/api/system/scheduled-task-runs",
179
+ "system.scheduler.read",
180
+ "system.scheduler",
181
+ ),
182
+ binding(
183
+ "GET",
184
+ "/api/system/operations/scheduler",
185
+ "system.scheduler.read",
186
+ "system.scheduler",
187
+ ),
188
+ binding(
189
+ "POST",
190
+ "/api/system/scheduled-tasks/:id/trigger",
191
+ "system.scheduler.manage",
192
+ "system.scheduler",
193
+ ),
194
+ binding(
195
+ "POST",
196
+ "/api/system/scheduled-tasks/:id/runs/:runId/recover",
197
+ "system.scheduler.manage",
198
+ "system.scheduler",
199
+ ),
200
+ // @windy-module system.scheduler end
201
+ // @windy-module system.bulk-data begin
202
+ binding(
203
+ "GET",
204
+ "/api/system/bulk-data/jobs",
205
+ "system.dict.read",
206
+ "system.bulk-data",
207
+ ),
208
+ binding(
209
+ "GET",
210
+ "/api/system/bulk-data/jobs/:id",
211
+ "system.dict.read",
212
+ "system.bulk-data",
213
+ ),
214
+ binding(
215
+ "GET",
216
+ "/api/system/bulk-data/jobs/:id/artifacts/:kind",
217
+ "system.dict.read",
218
+ "system.bulk-data",
219
+ ),
220
+ binding(
221
+ "POST",
222
+ "/api/system/bulk-data/dictionaries/import",
223
+ "system.dict.manage",
224
+ "system.bulk-data",
225
+ ),
226
+ binding(
227
+ "POST",
228
+ "/api/system/bulk-data/dictionaries/export",
229
+ "system.dict.read",
230
+ "system.bulk-data",
231
+ ),
232
+ // @windy-module system.bulk-data end
233
+ ];
234
+ }