create-windy 0.2.34 → 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 (261) hide show
  1. package/README.md +26 -3
  2. package/dist/cli.js +8121 -3746
  3. package/package.json +3 -3
  4. package/template/.windy-template.json +2 -2
  5. package/template/AGENTS.md +5 -0
  6. package/template/README.md +28 -4
  7. package/template/_gitignore +4 -0
  8. package/template/apps/agent-server/Dockerfile +1 -0
  9. package/template/apps/agent-server/README.md +18 -5
  10. package/template/apps/agent-server/adk_web_agents/__init__.py +1 -0
  11. package/template/apps/agent-server/adk_web_agents/safe_debug/__init__.py +3 -0
  12. package/template/apps/agent-server/adk_web_agents/safe_debug/agent.py +40 -0
  13. package/template/apps/agent-server/pyproject.toml +1 -1
  14. package/template/apps/agent-server/src/southwind_agent_server/adk_adapter.py +191 -16
  15. package/template/apps/agent-server/src/southwind_agent_server/adk_failure.py +13 -0
  16. package/template/apps/agent-server/src/southwind_agent_server/adk_model.py +225 -0
  17. package/template/apps/agent-server/src/southwind_agent_server/adk_tools.py +76 -0
  18. package/template/apps/agent-server/src/southwind_agent_server/app.py +1 -2
  19. package/template/apps/agent-server/tests/__init__.py +1 -0
  20. package/template/apps/agent-server/tests/openai_provider_test_support.py +131 -0
  21. package/template/apps/agent-server/tests/test_adk_adapter.py +305 -0
  22. package/template/apps/agent-server/tests/test_adk_web_agent.py +12 -0
  23. package/template/apps/agent-server/tests/test_openai_provider.py +7 -123
  24. package/template/apps/server/package.json +4 -1
  25. package/template/apps/server/src/agent/run-facade.ts +2 -7
  26. package/template/apps/server/src/agent/tool-registry.ts +2 -6
  27. package/template/apps/server/src/application-services.ts +50 -0
  28. package/template/apps/server/src/audit/drizzle-log-store.ts +25 -0
  29. package/template/apps/server/src/audit/search-summary.ts +2 -6
  30. package/template/apps/server/src/auth/credential-restriction.ts +1 -0
  31. package/template/apps/server/src/auth/password.ts +30 -21
  32. package/template/apps/server/src/auth/routes.test-support.ts +94 -0
  33. package/template/apps/server/src/auth/routes.test.ts +51 -78
  34. package/template/apps/server/src/auth/routes.ts +6 -1
  35. package/template/apps/server/src/auth/runtime.ts +4 -1
  36. package/template/apps/server/src/auth/service.ts +25 -7
  37. package/template/apps/server/src/configuration/bootstrap.ts +20 -1
  38. package/template/apps/server/src/configuration/definition.test.ts +71 -0
  39. package/template/apps/server/src/configuration/definition.ts +242 -12
  40. package/template/apps/server/src/configuration/drizzle-repository.ts +36 -2
  41. package/template/apps/server/src/configuration/repository.ts +27 -2
  42. package/template/apps/server/src/configuration/routes.ts +4 -1
  43. package/template/apps/server/src/configuration/service.test.ts +100 -0
  44. package/template/apps/server/src/configuration/service.ts +50 -10
  45. package/template/apps/server/src/data-access/scoped-repository.integration.test.ts +3 -2
  46. package/template/apps/server/src/data-governance/export/service.ts +2 -6
  47. package/template/apps/server/src/example-modules.ts +4 -1
  48. package/template/apps/server/src/guards.ts +18 -5
  49. package/template/apps/server/src/http/request-source.test.ts +85 -0
  50. package/template/apps/server/src/http/request-source.ts +90 -0
  51. package/template/apps/server/src/index.ts +40 -40
  52. package/template/apps/server/src/license/routes.ts +2 -0
  53. package/template/apps/server/src/license/runtime-service.ts +10 -11
  54. package/template/apps/server/src/mcp/adapter.test.ts +3 -2
  55. package/template/apps/server/src/mcp/adapter.ts +9 -9
  56. package/template/apps/server/src/mcp/routes.ts +4 -3
  57. package/template/apps/server/src/module-bootstrap.ts +2 -2
  58. package/template/apps/server/src/module-host/request-context.ts +6 -6
  59. package/template/apps/server/src/module-host/storage-scope.ts +2 -9
  60. package/template/apps/server/src/module-host/user-directory-port.ts +2 -6
  61. package/template/apps/server/src/notification/channel-adapter.ts +46 -0
  62. package/template/apps/server/src/notification/delivery-policy.test.ts +59 -0
  63. package/template/apps/server/src/notification/delivery-policy.ts +37 -0
  64. package/template/apps/server/src/notification/delivery-repository.ts +198 -0
  65. package/template/apps/server/src/notification/delivery-worker.test.ts +87 -0
  66. package/template/apps/server/src/notification/delivery-worker.ts +88 -0
  67. package/template/apps/server/src/notification/drizzle-management.ts +180 -0
  68. package/template/apps/server/src/notification/drizzle-query.ts +160 -0
  69. package/template/apps/server/src/notification/drizzle-repository.integration.test.ts +301 -0
  70. package/template/apps/server/src/notification/drizzle-repository.ts +156 -90
  71. package/template/apps/server/src/notification/extension-routes.test.ts +119 -0
  72. package/template/apps/server/src/notification/extension-routes.ts +111 -0
  73. package/template/apps/server/src/notification/memory-delivery-repository.ts +137 -0
  74. package/template/apps/server/src/notification/memory-support.ts +72 -0
  75. package/template/apps/server/src/notification/preference-repository.ts +95 -0
  76. package/template/apps/server/src/notification/recipient-directory.ts +104 -0
  77. package/template/apps/server/src/notification/repository.test.ts +171 -0
  78. package/template/apps/server/src/notification/repository.ts +179 -32
  79. package/template/apps/server/src/notification/revision-routes.test.ts +186 -0
  80. package/template/apps/server/src/notification/route-support.ts +225 -0
  81. package/template/apps/server/src/notification/routes.test.ts +182 -0
  82. package/template/apps/server/src/notification/routes.ts +225 -132
  83. package/template/apps/server/src/notification/service.test.ts +104 -0
  84. package/template/apps/server/src/notification/service.ts +140 -0
  85. package/template/apps/server/src/notification/smtp-adapter.test.ts +65 -0
  86. package/template/apps/server/src/notification/smtp-adapter.ts +68 -0
  87. package/template/apps/server/src/persistence.integration.test.ts +41 -2
  88. package/template/apps/server/src/platform-http-runtime.ts +87 -0
  89. package/template/apps/server/src/route-guards.ts +1 -0
  90. package/template/apps/server/src/runtime-audit-list.test.ts +39 -0
  91. package/template/apps/server/src/runtime-development.ts +1 -0
  92. package/template/apps/server/src/runtime.test.ts +23 -9
  93. package/template/apps/server/src/runtime.ts +39 -2
  94. package/template/apps/server/src/scheduler/audit.ts +2 -11
  95. package/template/apps/server/src/scheduler/definitions.test.ts +6 -0
  96. package/template/apps/server/src/scheduler/definitions.ts +7 -0
  97. package/template/apps/server/src/scheduler/recovery-service.ts +2 -11
  98. package/template/apps/server/src/scheduler/routes.ts +2 -7
  99. package/template/apps/server/src/search/opensearch-client.test.ts +45 -0
  100. package/template/apps/server/src/search/opensearch-client.ts +145 -0
  101. package/template/apps/server/src/search/service.ts +2 -6
  102. package/template/apps/server/src/settings/routes.ts +15 -3
  103. package/template/apps/server/src/settings/runtime.ts +10 -1
  104. package/template/apps/server/src/storage/runtime.ts +13 -0
  105. package/template/apps/server/src/system/audit-query.ts +33 -4
  106. package/template/apps/server/src/system/audit-routes.test.ts +58 -4
  107. package/template/apps/server/src/system/audit-routes.ts +6 -5
  108. package/template/apps/server/src/system/department-organization.ts +320 -0
  109. package/template/apps/server/src/system/department-routes.test.ts +207 -48
  110. package/template/apps/server/src/system/department-routes.ts +114 -33
  111. package/template/apps/server/src/system/drizzle-repository.ts +15 -7
  112. package/template/apps/server/src/system/drizzle-scoped-repository.ts +5 -3
  113. package/template/apps/server/src/system/drizzle-system-configs.ts +319 -0
  114. package/template/apps/server/src/system/drizzle-system.ts +59 -311
  115. package/template/apps/server/src/system/drizzle-transaction-context.ts +14 -0
  116. package/template/apps/server/src/system/identity-route-config.ts +7 -2
  117. package/template/apps/server/src/system/mutation-runner.ts +23 -0
  118. package/template/apps/server/src/system/organization-postgres.integration.test.ts +176 -0
  119. package/template/apps/server/src/system/resource-access-response.ts +12 -6
  120. package/template/apps/server/src/system/resource-routes.ts +270 -0
  121. package/template/apps/server/src/system/role-department-scope-policy.ts +55 -0
  122. package/template/apps/server/src/system/route-helpers.ts +2 -5
  123. package/template/apps/server/src/system/route-types.ts +12 -3
  124. package/template/apps/server/src/system/routes-validation.test.ts +26 -0
  125. package/template/apps/server/src/system/routes.test.ts +10 -2
  126. package/template/apps/server/src/system/routes.ts +35 -267
  127. package/template/apps/server/src/system/seed.ts +7 -0
  128. package/template/apps/server/src/work-order/data-scope.integration.test.ts +9 -2
  129. package/template/apps/server/src/work-order/opensearch-index.test.ts +97 -0
  130. package/template/apps/server/src/work-order/opensearch-index.ts +313 -0
  131. package/template/apps/server/src/work-order/search-provider.ts +60 -1
  132. package/template/apps/server/src/work-order/service.ts +42 -10
  133. package/template/apps/web/src/app/error-pages.ts +9 -0
  134. package/template/apps/web/src/components/auth/PasswordChangeForm.vue +16 -11
  135. package/template/apps/web/src/components/auth/PasswordChangeForm.webtest.ts +14 -0
  136. package/template/apps/web/src/components/common/FormDialog.vue +16 -2
  137. package/template/apps/web/src/components/common/ModalLayout.webtest.ts +20 -1
  138. package/template/apps/web/src/composables/useGlobalSearch.ts +68 -0
  139. package/template/apps/web/src/composables/usePlatformSettings.ts +8 -7
  140. package/template/apps/web/src/layout/GlobalSearchResults.vue +58 -0
  141. package/template/apps/web/src/layout/NavigationSearchDialog.vue +42 -6
  142. package/template/apps/web/src/layout/NavigationSearchDialog.webtest.ts +71 -0
  143. package/template/apps/web/src/layout/NotificationMenu.vue +73 -31
  144. package/template/apps/web/src/layout/NotificationMenu.webtest.ts +44 -1
  145. package/template/apps/web/src/layout/NotificationMenuItem.vue +61 -0
  146. package/template/apps/web/src/layout/NotificationPreferencesDialog.vue +181 -0
  147. package/template/apps/web/src/layout/NotificationPreferencesDialog.webtest.ts +80 -0
  148. package/template/apps/web/src/lib/date-time.ts +22 -10
  149. package/template/apps/web/src/lib/date-time.webtest.ts +9 -1
  150. package/template/apps/web/src/main.ts +14 -1
  151. package/template/apps/web/src/pages/auth/ChangePasswordPage.vue +16 -1
  152. package/template/apps/web/src/pages/configuration/components/ModuleConfigVersionList.vue +1 -0
  153. package/template/apps/web/src/pages/configuration/components/ModuleConfigurationEditor.vue +10 -0
  154. package/template/apps/web/src/pages/configuration/components/ModuleConfigurationWorkbench.vue +37 -6
  155. package/template/apps/web/src/pages/errors/PlatformErrorPage.vue +115 -0
  156. package/template/apps/web/src/pages/errors/PlatformErrorPage.webtest.ts +44 -0
  157. package/template/apps/web/src/pages/errors/error-page-extension.ts +26 -0
  158. package/template/apps/web/src/pages/system/SystemNotificationsPage.vue +136 -68
  159. package/template/apps/web/src/pages/system/SystemNotificationsPage.webtest.ts +224 -12
  160. package/template/apps/web/src/pages/system/audit-log-presenter.ts +86 -0
  161. package/template/apps/web/src/pages/system/audit-time-range.ts +28 -0
  162. package/template/apps/web/src/pages/system/components/AuditActionCell.vue +10 -69
  163. package/template/apps/web/src/pages/system/components/AuditActionCell.webtest.ts +20 -27
  164. package/template/apps/web/src/pages/system/components/AuditLogDetailDialog.vue +134 -0
  165. package/template/apps/web/src/pages/system/components/AuditLogDetailDialog.webtest.ts +76 -0
  166. package/template/apps/web/src/pages/system/components/AuditLogFilters.vue +116 -52
  167. package/template/apps/web/src/pages/system/components/AuditLogFilters.webtest.ts +52 -15
  168. package/template/apps/web/src/pages/system/components/NotificationHistoryDialog.vue +129 -0
  169. package/template/apps/web/src/pages/system/components/NotificationManagementCard.vue +91 -0
  170. package/template/apps/web/src/pages/system/components/NotificationPublishDialog.vue +121 -0
  171. package/template/apps/web/src/pages/system/components/NotificationPublishForm.vue +162 -1
  172. package/template/apps/web/src/pages/system/components/SystemResourceActions.vue +68 -0
  173. package/template/apps/web/src/pages/system/components/SystemResourceEditor.vue +74 -0
  174. package/template/apps/web/src/pages/system/components/SystemResourceFilters.vue +3 -4
  175. package/template/apps/web/src/pages/system/components/SystemResourceLoadError.vue +21 -0
  176. package/template/apps/web/src/pages/system/components/SystemResourceLoadError.webtest.ts +17 -0
  177. package/template/apps/web/src/pages/system/components/SystemResourcePage.vue +96 -108
  178. package/template/apps/web/src/pages/system/components/SystemResourcePage.webtest.ts +68 -0
  179. package/template/apps/web/src/pages/system/components/SystemResourceTable.vue +20 -1
  180. package/template/apps/web/src/pages/system/components/SystemResourceTable.webtest.ts +28 -7
  181. package/template/apps/web/src/pages/system/components/department/DepartmentOrganizationForm.vue +210 -0
  182. package/template/apps/web/src/pages/system/components/department/DepartmentTransitionDialog.vue +112 -0
  183. package/template/apps/web/src/pages/system/components/user-account/UserAccountForm.vue +17 -4
  184. package/template/apps/web/src/pages/system/composables/useDepartmentTransitions.ts +79 -0
  185. package/template/apps/web/src/pages/system/composables/useNotificationPermissions.ts +14 -0
  186. package/template/apps/web/src/pages/system/composables/useSystemResource.ts +2 -0
  187. package/template/apps/web/src/pages/system/composables/useSystemResource.webtest.ts +15 -2
  188. package/template/apps/web/src/pages/system/resource-config.ts +12 -4
  189. package/template/apps/web/src/router/error-navigation.ts +50 -0
  190. package/template/apps/web/src/router/error-navigation.webtest.ts +106 -0
  191. package/template/apps/web/src/router/index.ts +71 -0
  192. package/template/apps/web/src/router/index.webtest.ts +29 -0
  193. package/template/apps/web/src/router/manifest-routes.webtest.ts +4 -0
  194. package/template/apps/web/src/router/shared-scaffold-neutrality.webtest.ts +12 -0
  195. package/template/apps/web/src/services/auth-api.ts +5 -0
  196. package/template/apps/web/src/services/http.ts +43 -6
  197. package/template/apps/web/src/services/http.webtest.ts +70 -0
  198. package/template/apps/web/src/services/notification-api.ts +85 -2
  199. package/template/apps/web/src/services/notification-api.webtest.ts +110 -0
  200. package/template/apps/web/src/services/search-api.ts +39 -0
  201. package/template/apps/web/src/services/system-api.ts +18 -0
  202. package/template/apps/web/vitest.config.ts +1 -0
  203. package/template/docker-compose.yml +66 -0
  204. package/template/docs/architecture/ai-runtime.md +14 -5
  205. package/template/docs/architecture/mcp-business-capabilities.md +107 -0
  206. package/template/docs/architecture/search-provider-protocol.md +38 -2
  207. package/template/docs/development/custom-error-pages.md +78 -0
  208. package/template/docs/development/custom-login-page.md +3 -3
  209. package/template/docs/platform/agent-runtime.md +32 -6
  210. package/template/docs/platform/agent-tools.md +4 -0
  211. package/template/docs/platform/audit-reliability.md +46 -2
  212. package/template/docs/platform/module-configuration.md +13 -4
  213. package/template/docs/platform/notifications.md +67 -11
  214. package/template/docs/platform/organization-membership.md +17 -3
  215. package/template/docs/platform/system-crud-api.md +16 -0
  216. package/template/docs/platform/web-system-crud.md +6 -2
  217. package/template/package.json +4 -0
  218. package/template/packages/config/index.test.ts +45 -0
  219. package/template/packages/config/package.json +1 -1
  220. package/template/packages/config/src/platform.ts +169 -48
  221. package/template/packages/database/drizzle/0035_material_nightshade.sql +10 -0
  222. package/template/packages/database/drizzle/0036_hesitant_speed.sql +35 -0
  223. package/template/packages/database/drizzle/0037_absent_nick_fury.sql +2 -0
  224. package/template/packages/database/drizzle/0038_uneven_wasp.sql +38 -0
  225. package/template/packages/database/drizzle/meta/0035_snapshot.json +7331 -0
  226. package/template/packages/database/drizzle/meta/0036_snapshot.json +7436 -0
  227. package/template/packages/database/drizzle/meta/0037_snapshot.json +7457 -0
  228. package/template/packages/database/drizzle/meta/0038_snapshot.json +7749 -0
  229. package/template/packages/database/drizzle/meta/_journal.json +28 -0
  230. package/template/packages/database/package.json +1 -1
  231. package/template/packages/database/src/schema/identity.ts +7 -0
  232. package/template/packages/database/src/schema/notifications.ts +135 -0
  233. package/template/packages/database/src/schema-notification-delivery.test.ts +54 -0
  234. package/template/packages/database/src/schema-workflow-notification.test.ts +40 -1
  235. package/template/packages/modules/package.json +1 -1
  236. package/template/packages/modules/src/composition-fixtures.test-support.ts +164 -0
  237. package/template/packages/modules/src/composition.test.ts +5 -158
  238. package/template/packages/modules/src/system-api-operational.ts +234 -0
  239. package/template/packages/modules/src/system-api-permissions.ts +14 -181
  240. package/template/packages/modules/src/system-audit-actions.ts +10 -0
  241. package/template/packages/modules/src/system-features.ts +1 -1
  242. package/template/packages/modules/src/system-module-catalog.ts +2 -1
  243. package/template/packages/modules/src/system-module-tasks.ts +86 -0
  244. package/template/packages/modules/src/system-modules-access.test.ts +60 -0
  245. package/template/packages/modules/src/system-modules.test.ts +13 -54
  246. package/template/packages/modules/src/system-modules.ts +2 -72
  247. package/template/packages/modules/src/system-permissions.ts +9 -5
  248. package/template/packages/server-sdk/package.json +1 -1
  249. package/template/packages/shared/index.ts +1 -0
  250. package/template/packages/shared/package.json +1 -1
  251. package/template/packages/shared/src/audit.ts +25 -0
  252. package/template/packages/shared/src/mcp.test.ts +12 -0
  253. package/template/packages/shared/src/mcp.ts +7 -0
  254. package/template/packages/shared/src/module-configuration.ts +5 -0
  255. package/template/packages/shared/src/notification.ts +92 -1
  256. package/template/packages/shared/src/password.ts +7 -2
  257. package/template/packages/shared/src/platform-settings.ts +2 -0
  258. package/template/packages/storage/package.json +1 -1
  259. package/template/packages/storage/src/upload-service.test.ts +16 -0
  260. package/template/packages/storage/src/upload-service.ts +5 -1
  261. package/template/scripts/notification-postgres-regression.ts +27 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-windy",
3
- "version": "0.2.34",
3
+ "version": "0.3.1",
4
4
  "description": "创建单组织、单租户、私有部署优先的 Windy 企业 Dashboard Starter",
5
5
  "type": "module",
6
6
  "bin": {
@@ -13,14 +13,14 @@
13
13
  "README.md"
14
14
  ],
15
15
  "scripts": {
16
- "build": "bun build src/cli.ts --target=node --format=esm --outdir=dist",
16
+ "build": "bun build src/cli.ts --target=bun --format=esm --outdir=dist",
17
17
  "template:sync": "bun run src/sync-template.ts",
18
18
  "prepack": "bun run template:sync && bun run build",
19
19
  "postpack": "bun run src/clean-template.ts",
20
20
  "typecheck": "tsc --noEmit --project tsconfig.json"
21
21
  },
22
22
  "engines": {
23
- "node": ">=20"
23
+ "bun": ">=1.3.14"
24
24
  },
25
25
  "keywords": [
26
26
  "dashboard",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "templateCommit": "28f6b738276d5138a514a4ab374d60884b94e769",
4
- "generatorVersion": "0.2.34",
3
+ "templateCommit": "74bc602b85aa40bdd11761507d8d9821ecd5bb50",
4
+ "generatorVersion": "0.3.1",
5
5
  "modules": [
6
6
  {
7
7
  "name": "system",
@@ -44,6 +44,9 @@
44
44
  `apps/web/src/pages/auth/LoginPage.vue` 或 Router。业务页面复用
45
45
  `useLoginFlow`、`DevelopmentAuthWarning` 和平台品牌设置,保留安全
46
46
  `returnTo`、真实认证与开发认证提示。
47
+ - 定制 404、500、维护中或网络异常页时,只修改 project-owned 的
48
+ `apps/web/src/app/error-pages.ts`,并把业务 SFC 放在 `apps/web/src/app/`;
49
+ 保留四个类型化注册项,不要为换视觉修改 Router、HTTP 核心或平台默认错误页。
47
50
  - 业务 Agent Operation 开启 Provider 出网时,必须在 Manifest 同时声明最小
48
51
  `providerDataPolicy.inputFields` JSON Pointer allowlist 与
49
52
  `envelopeFields`;raw input 会在进入 `prepare` 前裁剪并执行 DLP。接入与升级
@@ -55,6 +58,8 @@
55
58
  或 MCP 暴露时使用的仓库内开发流程。
56
59
  - `docs/development/custom-login-page.md`:完整替换登录页的 ownership、认证复用和
57
60
  升级迁移说明。
61
+ - `docs/development/custom-error-pages.md`:统一错误语义、Request ID 与业务页面
62
+ 替换方式。
58
63
  - `bun run dev`:复用 Docker 镜像启动 PostgreSQL、自动 migration、Server 与支持热更新的 Web。
59
64
  - `bun run dev:build`:依赖、Dockerfile 或 lockfile 变化后重建并启动开发环境。
60
65
  - `bun run dev:web`:启动 Web 开发服务。
@@ -52,6 +52,20 @@ bun run dev:server
52
52
  以终端输出为准。`dev:server` 不会自动启动 PostgreSQL 或执行 migration;未配置
53
53
  `DATABASE_URL` 时使用内存模式。
54
54
 
55
+ ## Agent、MCP 与仓库 Skill
56
+
57
+ 仓库始终包含 `.agents/skills/windy-business-module/SKILL.md`。新增或修改业务模块、
58
+ Agent Tool 或 MCP 暴露时,可以明确要求代码 Agent“使用 `windy-business-module`
59
+ Skill 完成该能力”。Skill 只指导开发流程;Feature、Permission、Schema 和 Tool 的
60
+ 运行时事实仍以 Module Manifest 与平台 Registry 为准。
61
+
62
+ 当前组合未包含 `system.agent`,MCP Server、Agent Tool Host 和相关文档已被
63
+ 物理裁剪。若项目尚可重新生成,请在创建时增加 `--module system.agent` 或使用
64
+ `--all-modules`;部署后的通用 `module add` 尚未交付,不要手工复制 MCP Adapter
65
+ 或另建授权链。仓库 Skill 仍可用于普通业务模块开发。
66
+
67
+
68
+
55
69
 
56
70
  ## 页面与登录
57
71
 
@@ -100,7 +114,7 @@ create-windy 在本机 `.env` 中随机生成的 `WINDY_BOOTSTRAP_ADMIN_PASSWORD
100
114
  | `system.storage` | 未包含 | H2 | 上传、下载和对象生命周期。 |
101
115
  | `system.agent` | 未包含 | H2 | 受控 Agent 工具宿主。 |
102
116
  | `system.scheduler` | 未包含 | H2 | 任务、重试、历史和恢复。 |
103
- | `system.notification` | 未包含 | H2 | 通知发布、阅读和归档。 |
117
+ | `system.notification` | 未包含 | H2 | 通知定向与定时发布、用户偏好、外部渠道投递、修改历史、阅读、收藏和归档。 |
104
118
  | `system.workflow` | 未包含 | H2 | 审批、转交、超时和补偿。 |
105
119
  | `system.bulk-data` | 未包含 | H2 | 批量导入导出与结果留存。 |
106
120
  | `system.search` | 未包含 | H2 | 权限感知搜索与 Provider 聚合。 |
@@ -121,12 +135,14 @@ bun run dev
121
135
  bun run dev:build
122
136
  bun run dev:web
123
137
  bun run dev:server
138
+
124
139
  bun run typecheck
125
140
  bun run test
126
141
  bun run build
127
142
  bun run windy doctor
128
143
  bun run windy update --check
129
144
  bun run windy update --dry-run
145
+ bun run windy reconcile --to <精确目标版本>
130
146
  bun run lint
131
147
  bun run format
132
148
  ```
@@ -135,7 +151,14 @@ bun run format
135
151
 
136
152
  更新前必须保持 Git 工作区干净。`--dry-run` 只生成计划,不写项目;正式更新先备份,
137
153
  再做 package 字段级合并、共享脚手架三方合并与完整验证。任何冲突都会在写入前中止,
138
- 验证失败会自动回滚;中断恢复使用 `bun run windy doctor --repair`。
154
+ 无并发变化的验证失败会自动回滚;中断恢复使用
155
+ `bun run windy doctor --repair`。该命令在提交点前保留并发编辑并回滚其余路径,
156
+ 在 committed 提交点后只完成事务状态与备份清理,不回滚项目文件。
157
+
158
+ 仅当 Windy 发布说明提供确定性 proof 时使用
159
+ `reconcile --to <精确目标版本>`。它默认只演练;显式增加 `--apply` 后也只更新
160
+ 受管清单元数据与无正文报告,不修改项目源码或推进 Project Lock。project-owned、
161
+ 缺失和未知语义差异始终保守未决;shared-scaffold 只有精确命中已发布 proof 才可对账。
139
162
 
140
163
  ## 开发约束
141
164
 
@@ -154,8 +177,9 @@ bun run format
154
177
  create-windy 默认建立 `main` 分支并创建 `chore: initialize project` 首次提交。若当时
155
178
  没有配置 Git 用户身份,文件会保留在暂存区;配置身份后手动提交即可。
156
179
 
157
- 未来的 Windy 更新器会根据 project lock 和文件所有权执行三方合并,不会要求连接
158
- 私有源仓库,也不会静默覆盖项目代码。该更新引擎当前尚未交付。
180
+ 当前已交付的 Windy 更新器会根据 Project Lock 和文件所有权,从 npm 历史 artifact
181
+ 重建 Base 并执行三方合并;它不连接私有源仓库,也不会静默覆盖项目代码。部署期通用
182
+ `module add/update/remove` 尚未交付。
159
183
 
160
184
  ## License
161
185
 
@@ -1,4 +1,8 @@
1
1
  .env
2
+ .env.*
3
+ !.env.example
4
+ !.env.sample
5
+ !.env.template
2
6
  .DS_Store
3
7
  node_modules/
4
8
  dist/
@@ -8,6 +8,7 @@ RUN pip install --no-cache-dir uv==0.9.27 \
8
8
  COPY apps/agent-server/pyproject.toml apps/agent-server/uv.lock ./
9
9
  RUN uv sync --frozen --no-dev --no-install-project
10
10
  COPY apps/agent-server/src ./src
11
+ COPY apps/agent-server/adk_web_agents ./adk_web_agents
11
12
  RUN uv sync --frozen --no-dev
12
13
 
13
14
  ENV PATH="/app/apps/agent-server/.venv/bin:${PATH}"
@@ -1,8 +1,9 @@
1
1
  # Southwind AI Agent Server
2
2
 
3
3
  Python 3.12 Agent Runtime。HTTP 层只公开 Southwind AI canonical Agent
4
- contracts。当前可用 Adapter 连接 OpenAI-compatible `/chat/completions`;Google ADK
5
- 仍只是未配置 Provider 时安全拒绝的内部 Adapter。
4
+ contracts。真实业务 Run 在内部通过 Google ADK 2.5 的 Runner、Session、LlmAgent 和
5
+ Event 执行;ADK 类型不会越过 `AgentEngineAdapter`。模型调用继续复用受治理的
6
+ OpenAI-compatible `/chat/completions` Provider。
6
7
 
7
8
  ```bash
8
9
  uv sync --frozen
@@ -23,7 +24,7 @@ Run 创建使用 `Idempotency-Key`。事件以 SSE 传输,支持 `Last-Event-I
23
24
  断线重放,并周期发送 comment heartbeat。Provider 或框架异常只会映射为 canonical
24
25
  安全错误,不会把原始异常正文暴露给调用方。
25
26
 
26
- 配置以下仅服务端可见的环境变量后,默认运行 OpenAI-compatible Adapter:
27
+ 配置以下仅服务端可见的环境变量后,默认运行 ADK Adapter:
27
28
 
28
29
  ```bash
29
30
  export AGENT_SERVER_INTERNAL_TOKEN='<random-token>'
@@ -40,8 +41,9 @@ uv run uvicorn southwind_agent_server.app:app
40
41
  公网 URL 必须使用 HTTPS 且 Host 精确命中 allowlist;本机、容器服务名和内网地址允许
41
42
  HTTP。Provider 请求包含连接和总超时、响应大小限制、错误脱敏与 `/models`
42
43
  readiness。缺少 URL/Model 时回退
43
- `AdkEngineAdapter` 并返回 unavailable,不调用模型。测试另使用
44
- `DeterministicEngineAdapter`。
44
+ 未配置的 `AdkEngineAdapter` 并返回 unavailable,不调用模型。测试另使用
45
+ `DeterministicEngineAdapter`。每个 ADK Tool 只声明 Operation 已允许的 Key;其执行
46
+ 函数只回调 Southwind AI Tool Host,并携带当前 Run 的 opaque Execution Grant。
45
47
 
46
48
  未设置 `AGENT_RUN_STORE_PATH` 时使用的 `InMemoryRunStore` **仅用于 deterministic
47
49
  测试**。配置路径后使用有界 SQLite Store,可在单副本重启后保留 Run/Event/Result 和
@@ -56,3 +58,14 @@ SQLite append-only 表。审计不保存 prompt、请求正文或 Secret;审
56
58
  出网。记录到期后只由配置的 TTL 清理,清理计数可通过需内部 Token 的
57
59
  `GET /health/provider-governance` 查看。SQLite 实现仅支持单副本;多副本部署必须替换
58
60
  为共享、并发安全的审计 Adapter。
61
+
62
+ 开发者可单独启动 ADK Web:
63
+
64
+ ```bash
65
+ bun run dev:adk-web
66
+ ```
67
+
68
+ 访问 `http://127.0.0.1:8000`。该 `agent-debug` profile 不读取 Qwen、内部 Token 或
69
+ 业务配置,只加载无 Provider、无业务 Tool 的确定性调试 Agent。它用于检查 ADK Web、
70
+ Session 和 Event 交互,不能复现带 Actor/Execution Grant 的真实 Operation,也不能
71
+ 作为生产调用入口。
@@ -0,0 +1 @@
1
+ """Developer-only ADK Web agents."""
@@ -0,0 +1,3 @@
1
+ from .agent import root_agent
2
+
3
+ __all__ = ["root_agent"]
@@ -0,0 +1,40 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import AsyncGenerator
4
+
5
+ from google.adk.agents import LlmAgent
6
+ from google.adk.models.base_llm import BaseLlm
7
+ from google.adk.models.llm_request import LlmRequest
8
+ from google.adk.models.llm_response import LlmResponse
9
+ from google.genai import types
10
+
11
+
12
+ class SafeDebugLlm(BaseLlm):
13
+ async def generate_content_async(
14
+ self,
15
+ llm_request: LlmRequest,
16
+ stream: bool = False,
17
+ ) -> AsyncGenerator[LlmResponse, None]:
18
+ del llm_request, stream
19
+ text = (
20
+ "这是 Windy 的 ADK 开发调试 Agent。"
21
+ "它不连接业务 Repository、Tool Host 或模型 Provider,"
22
+ "不能代表生产业务 Operation。"
23
+ )
24
+ yield LlmResponse(
25
+ content=types.Content(
26
+ role="model",
27
+ parts=[types.Part(text=text)],
28
+ ),
29
+ partial=False,
30
+ )
31
+
32
+
33
+ root_agent = LlmAgent(
34
+ name="safe_debug",
35
+ model=SafeDebugLlm(model="windy-safe-debug"),
36
+ instruction=(
37
+ "仅说明开发调试边界;不访问业务数据,不调用 Tool,不连接模型 Provider。"
38
+ ),
39
+ tools=[],
40
+ )
@@ -21,7 +21,7 @@ dev = [
21
21
 
22
22
  [tool.pytest.ini_options]
23
23
  asyncio_mode = "auto"
24
- pythonpath = ["src"]
24
+ pythonpath = [".", "src"]
25
25
  testpaths = ["tests"]
26
26
 
27
27
  [tool.ruff]
@@ -1,39 +1,214 @@
1
1
  from __future__ import annotations
2
2
 
3
- from collections.abc import AsyncIterator, Mapping
3
+ import asyncio
4
+ from collections.abc import AsyncIterator
4
5
 
6
+ from google.adk.agents import LlmAgent
7
+ from google.adk.agents.run_config import RunConfig, StreamingMode
8
+ from google.adk.events import Event
9
+ from google.adk.runners import Runner
10
+ from google.adk.sessions import InMemorySessionService
11
+ from google.genai import types
12
+
13
+ from .adk_failure import AdkFailureState
14
+ from .adk_model import GovernedOpenAiLlm
15
+ from .adk_tools import GovernedTool
16
+ from .contracts import JsonValue
5
17
  from .engine import (
6
18
  AgentEngineAdapter,
19
+ EngineCompleted,
7
20
  EngineRunRequest,
8
21
  EngineSignal,
22
+ OutputDelta,
9
23
  SafeEngineError,
24
+ ToolCompleted,
25
+ ToolRequested,
26
+ UsageReported,
10
27
  )
28
+ from .openai_engine import cancelled, validate_runtime_request
29
+ from .openai_provider import OpenAiCompatibleProvider
30
+ from .provider_governance import ProviderRequestGovernance
31
+ from .tool_host import ToolHostClient
11
32
 
12
33
 
13
34
  class AdkEngineAdapter(AgentEngineAdapter):
14
- """Google ADK implementation skeleton.
15
-
16
- Agent objects remain opaque and internal. A later slice will create ADK Runners,
17
- consume ADK Events, and translate them into EngineSignal values at this seam.
18
- """
35
+ """Google ADK Runner implementation behind the stable engine seam."""
19
36
 
20
- def __init__(self, agents: Mapping[str, object] | None = None) -> None:
21
- self._agents = dict(agents or {})
37
+ def __init__(
38
+ self,
39
+ provider: OpenAiCompatibleProvider | None = None,
40
+ tool_host: ToolHostClient | None = None,
41
+ governance: ProviderRequestGovernance | None = None,
42
+ ) -> None:
43
+ self._provider = provider
44
+ self._tool_host = tool_host
45
+ self._governance = governance
46
+ self._cancellations: dict[str, asyncio.Event] = {}
22
47
 
23
48
  def supports(self, operation_key: str) -> bool:
24
- return operation_key in self._agents
49
+ return bool(operation_key.strip())
25
50
 
26
51
  async def execute(
27
52
  self,
28
53
  request: EngineRunRequest,
29
54
  ) -> AsyncIterator[EngineSignal]:
30
- del request
31
- raise SafeEngineError(
32
- "RUNTIME_UNAVAILABLE",
33
- "Agent Runtime 尚未配置",
34
- retryable=True,
55
+ provider, tool_host, governance = self._configured()
56
+ validate_runtime_request(request, provider.config.deployment_key)
57
+ cancellation = self._cancellations.setdefault(
58
+ request.run_id,
59
+ asyncio.Event(),
35
60
  )
36
- yield # pragma: no cover - keeps this method an async generator
61
+ output = ""
62
+ output_bytes = 0
63
+ failures = AdkFailureState()
64
+ event_failure: SafeEngineError | None = None
65
+ try:
66
+ session_service = InMemorySessionService() # type: ignore[no-untyped-call]
67
+ await session_service.create_session(
68
+ app_name="southwind_runtime",
69
+ user_id="platform",
70
+ session_id=request.run_id,
71
+ )
72
+ runner = Runner(
73
+ app_name="southwind_runtime",
74
+ agent=LlmAgent(
75
+ name="southwind_operation",
76
+ model=GovernedOpenAiLlm(
77
+ request,
78
+ provider,
79
+ governance,
80
+ cancellation,
81
+ failures,
82
+ ),
83
+ instruction=request.instructions,
84
+ tools=[
85
+ GovernedTool(
86
+ tool,
87
+ request,
88
+ tool_host,
89
+ cancellation,
90
+ failures,
91
+ )
92
+ for tool in request.allowed_tools
93
+ ],
94
+ ),
95
+ session_service=session_service,
96
+ )
97
+ async for event in runner.run_async(
98
+ user_id="platform",
99
+ session_id=request.run_id,
100
+ new_message=types.Content(
101
+ role="user",
102
+ parts=[types.Part(text=request.user_prompt)],
103
+ ),
104
+ run_config=RunConfig(
105
+ streaming_mode=StreamingMode.SSE,
106
+ max_llm_calls=provider.config.max_tool_rounds,
107
+ ),
108
+ ):
109
+ cancelled(cancellation)
110
+ if event.error_code:
111
+ event_failure = failures.failure or SafeEngineError(
112
+ "PROVIDER_UNAVAILABLE",
113
+ "模型服务暂不可用",
114
+ retryable=True,
115
+ )
116
+ continue
117
+ async for signal in signals_for_event(event):
118
+ if isinstance(signal, OutputDelta):
119
+ output_bytes += len(signal.text.encode())
120
+ if output_bytes > request.limits.max_output_bytes:
121
+ raise SafeEngineError(
122
+ "BUDGET_EXCEEDED",
123
+ "Agent 输出超过 Operation 上限",
124
+ retryable=False,
125
+ )
126
+ output += signal.text
127
+ yield signal
128
+ if event_failure is not None:
129
+ raise event_failure
130
+ cancelled(cancellation)
131
+ yield EngineCompleted({"text": output})
132
+ except SafeEngineError:
133
+ raise
134
+ except asyncio.CancelledError:
135
+ raise SafeEngineError(
136
+ "RUN_CANCELLED",
137
+ "Agent Run 已取消",
138
+ retryable=False,
139
+ ) from None
140
+ except Exception:
141
+ raise SafeEngineError(
142
+ "RUNTIME_UNAVAILABLE",
143
+ "Agent Runtime 执行失败",
144
+ retryable=True,
145
+ ) from None
146
+ finally:
147
+ self._cancellations.pop(request.run_id, None)
37
148
 
38
149
  async def cancel(self, run_id: str) -> None:
39
- del run_id
150
+ cancellation = self._cancellations.get(run_id)
151
+ if cancellation is not None:
152
+ cancellation.set()
153
+
154
+ async def health(self) -> None:
155
+ provider, _, _ = self._configured()
156
+ await provider.health()
157
+
158
+ def governance_health(self) -> dict[str, int | float | str | None]:
159
+ _, _, governance = self._configured()
160
+ return governance.health()
161
+
162
+ def _configured(
163
+ self,
164
+ ) -> tuple[
165
+ OpenAiCompatibleProvider,
166
+ ToolHostClient,
167
+ ProviderRequestGovernance,
168
+ ]:
169
+ if not self._provider or not self._tool_host or not self._governance:
170
+ raise SafeEngineError(
171
+ "RUNTIME_UNAVAILABLE",
172
+ "Agent Runtime 尚未配置",
173
+ retryable=True,
174
+ )
175
+ return self._provider, self._tool_host, self._governance
176
+
177
+
178
+ async def signals_for_event(event: Event) -> AsyncIterator[EngineSignal]:
179
+ for call in event.get_function_calls():
180
+ if not call.id or not call.name:
181
+ raise SafeEngineError(
182
+ "TOOL_DENIED",
183
+ "模型请求了无效 Tool",
184
+ retryable=False,
185
+ )
186
+ yield ToolRequested(call.id, call.name)
187
+ for response in event.get_function_responses():
188
+ if not response.id:
189
+ raise SafeEngineError(
190
+ "TOOL_DENIED",
191
+ "Agent Tool 响应缺少稳定标识",
192
+ retryable=False,
193
+ )
194
+ yield ToolCompleted(response.id)
195
+ if event.partial and event.content:
196
+ for part in event.content.parts or []:
197
+ if part.text and not part.thought:
198
+ yield OutputDelta(part.text)
199
+ usage = southwind_usage(event)
200
+ if usage is not None:
201
+ yield UsageReported(usage)
202
+
203
+
204
+ def southwind_usage(event: Event) -> dict[str, JsonValue] | None:
205
+ metadata = event.custom_metadata or {}
206
+ value = metadata.get("southwindUsage")
207
+ if not isinstance(value, dict):
208
+ return None
209
+ return {
210
+ key: item
211
+ for key, item in value.items()
212
+ if isinstance(key, str)
213
+ and (item is None or isinstance(item, str | int | float | bool | list | dict))
214
+ }
@@ -0,0 +1,13 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+
5
+ from .engine import SafeEngineError
6
+
7
+
8
+ @dataclass
9
+ class AdkFailureState:
10
+ failure: SafeEngineError | None = None
11
+
12
+ def capture(self, error: SafeEngineError) -> None:
13
+ self.failure = error