create-windy 0.9.1 → 0.10.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 (253) hide show
  1. package/dist/cli.js +1691 -1151
  2. package/package.json +2 -2
  3. package/template/.agents/skills/windy-business-module/SKILL.md +33 -1
  4. package/template/.windy-template.json +6 -2
  5. package/template/AGENTS.md +4 -0
  6. package/template/README.md +2 -0
  7. package/template/apps/agent-server/Dockerfile +1 -1
  8. package/template/apps/agent-server/README.md +1 -1
  9. package/template/apps/agent-server/native/EXTENSIONS.md +2 -2
  10. package/template/apps/agent-server/native/parallel-harness.ts +2 -0
  11. package/template/apps/agent-server/native/storage-lifecycle.test.ts +2 -1
  12. package/template/apps/agent-server/package.json +42 -41
  13. package/template/apps/agent-server/plugins/downloads/README.md +1 -1
  14. package/template/apps/agent-server/plugins/drop-overlay/README.md +1 -1
  15. package/template/apps/agent-server/plugins/settings/README.md +1 -1
  16. package/template/apps/agent-server/plugins/skill-library/client-chunks.test.ts +4 -1
  17. package/template/apps/agent-server/plugins/theme/README.md +5 -1
  18. package/template/apps/agent-server/plugins/theme/source-tokens.ts +0 -1
  19. package/template/apps/agent-server/plugins/theme/tokens.json +0 -4
  20. package/template/apps/agent-server/plugins/tool-catalog/README.md +6 -3
  21. package/template/apps/agent-server/plugins/tool-catalog/discovery.mjs +13 -10
  22. package/template/apps/agent-server/plugins/tool-catalog/discovery.test.ts +68 -6
  23. package/template/apps/agent-server/runtime/compatibility.ts +7 -1
  24. package/template/apps/agent-server/runtime/dsh-engine.ts +2 -0
  25. package/template/apps/agent-server/runtime/questions-workflow.nodecheck.ts +2 -0
  26. package/template/apps/server/Dockerfile +2 -1
  27. package/template/apps/server/package.json +11 -11
  28. package/template/apps/server/scripts/validate-module-composition-once.ts +2 -0
  29. package/template/apps/server/scripts/validate-module-composition.ts +8 -4
  30. package/template/apps/server/src/admin/routes.test.ts +29 -1
  31. package/template/apps/server/src/admin/routes.ts +20 -2
  32. package/template/apps/server/src/agent/client-session/completion.ts +1 -1
  33. package/template/apps/server/src/agent/client-session/manifest-admission.ts +1 -1
  34. package/template/apps/server/src/agent/client-session/request.ts +1 -1
  35. package/template/apps/server/src/agent/context-version-routes.ts +37 -13
  36. package/template/apps/server/src/agent/run-facade.ts +1 -1
  37. package/template/apps/server/src/agent/run-input-verification.ts +1 -1
  38. package/template/apps/server/src/agent/run-routes.ts +1 -14
  39. package/template/apps/server/src/agent/run-start-preparation.ts +1 -1
  40. package/template/apps/server/src/agent/runtime-bootstrap-input.ts +2 -0
  41. package/template/apps/server/src/agent/runtime-bootstrap.ts +49 -157
  42. package/template/apps/server/src/agent/runtime-disabled-composition.ts +2 -1
  43. package/template/apps/server/src/agent/session-invalidation/authorization-revocation.ts +54 -0
  44. package/template/apps/server/src/agent/session-runtime-composition.ts +1 -51
  45. package/template/apps/server/src/agent/unavailable-routes.ts +13 -2
  46. package/template/apps/server/src/agent-workflow/runtime-composition.ts +3 -0
  47. package/template/apps/server/src/agent-workflow/service.ts +17 -1
  48. package/template/apps/server/src/ai-artifact/media-resource-route.test.ts +134 -0
  49. package/template/apps/server/src/ai-artifact/routes.ts +1 -1
  50. package/template/apps/server/src/ai-artifact/runtime.ts +12 -0
  51. package/template/apps/server/src/ai-runtime-readiness/operation-port.test-support.ts +1 -1
  52. package/template/apps/server/src/ai-runtime-readiness/operation-port.ts +8 -0
  53. package/template/apps/server/src/ai-runtime-security/internal-token.ts +14 -0
  54. package/template/apps/server/src/app/antivirus-composition.test.ts +63 -0
  55. package/template/apps/server/src/app/antivirus-composition.ts +29 -0
  56. package/template/apps/server/src/app/dsh-workbench-socket-audit.test.ts +2 -1
  57. package/template/apps/server/src/configuration/definition.ts +15 -11
  58. package/template/apps/server/src/document/facade-support.ts +2 -2
  59. package/template/apps/server/src/document/facade.ts +2 -2
  60. package/template/apps/server/src/document/output-artifact-composition.ts +9 -5
  61. package/template/apps/server/src/document/output-artifact.test-support.ts +1 -1
  62. package/template/apps/server/src/embedding/facade.ts +1 -1
  63. package/template/apps/server/src/embedding/input.ts +1 -1
  64. package/template/apps/server/src/embedding/routes.ts +1 -1
  65. package/template/apps/server/src/index.ts +60 -60
  66. package/template/apps/server/src/license/routes.ts +4 -1
  67. package/template/apps/server/src/license/runtime-business-access.test.ts +261 -0
  68. package/template/apps/server/src/media-runtime/composition.ts +157 -0
  69. package/template/apps/server/src/media-runtime/media-only-composition.ts +44 -0
  70. package/template/apps/server/src/media-runtime/module-ai-port-factory.test.ts +69 -0
  71. package/template/apps/server/src/media-runtime/module-ai-port-factory.ts +72 -0
  72. package/template/apps/server/src/{agent → media-runtime}/runtime-readiness-sources.ts +14 -6
  73. package/template/apps/server/src/media-runtime/shared-composition.ts +104 -0
  74. package/template/apps/server/src/module-composition.test.ts +22 -0
  75. package/template/apps/server/src/module-composition.ts +48 -0
  76. package/template/apps/server/src/module-host/ai-operation-port.ts +97 -30
  77. package/template/apps/server/src/module-host/ai-operation-speech-normalize.test.ts +1 -1
  78. package/template/apps/server/src/module-host/http-runtime.ts +9 -3
  79. package/template/apps/server/src/module-host/static-route-authorization.test.ts +6 -3
  80. package/template/apps/server/src/module-host/storage-authorization-binding.test.ts +4 -0
  81. package/template/apps/server/src/module-runtime-validation.ts +2 -0
  82. package/template/apps/server/src/observability/diagnostic-index.ts +26 -1
  83. package/template/apps/server/src/observability/diagnostic-repository.ts +40 -11
  84. package/template/apps/server/src/platform-http-runtime.ts +1 -1
  85. package/template/apps/server/src/runtime-feature.ts +5 -1
  86. package/template/apps/server/src/runtime.ts +3 -0
  87. package/template/apps/server/src/settings/drizzle-watermark-repository.ts +35 -4
  88. package/template/apps/server/src/settings/watermark-repository.ts +14 -0
  89. package/template/apps/server/src/settings/watermark-routes.test.ts +84 -2
  90. package/template/apps/server/src/settings/watermark-routes.ts +109 -0
  91. package/template/apps/server/src/settings/watermark-transfer.ts +79 -0
  92. package/template/apps/server/src/speech/facade-validation.ts +1 -1
  93. package/template/apps/server/src/speech/facade.ts +2 -2
  94. package/template/apps/server/src/startup-composition-validation.test.ts +32 -0
  95. package/template/apps/server/src/startup-finalization.ts +2 -0
  96. package/template/apps/server/src/startup-runtime.ts +77 -0
  97. package/template/apps/server/src/system/ai-runtime-build.ts +3 -0
  98. package/template/apps/server/src/system/ai-runtime-configuration.test.ts +36 -0
  99. package/template/apps/server/src/system/ai-runtime-configuration.ts +58 -0
  100. package/template/apps/server/src/system/diagnostic-routes.test.ts +45 -0
  101. package/template/apps/server/src/system/diagnostic-routes.ts +35 -0
  102. package/template/apps/server/src/system/environment-policy-reader.test.ts +74 -0
  103. package/template/apps/server/src/system/environment-policy-reader.ts +62 -0
  104. package/template/apps/server/src/system/feature-environment-assessment.test.ts +148 -0
  105. package/template/apps/server/src/system/feature-environment-assessment.ts +179 -0
  106. package/template/apps/server/src/system/host-diagnostics.test.ts +155 -0
  107. package/template/apps/server/src/system/host-diagnostics.ts +225 -0
  108. package/template/apps/server/src/system/menu-registry.test.ts +26 -0
  109. package/template/apps/server/src/system/menu-registry.ts +9 -7
  110. package/template/apps/server/src/system/operations.test.ts +5 -0
  111. package/template/apps/server/src/system/operations.ts +36 -12
  112. package/template/apps/server/src/system/role-authorization-postgres.integration.test.ts +181 -0
  113. package/template/apps/web/Dockerfile +7 -3
  114. package/template/apps/web/dev/dev-port.test.ts +6 -6
  115. package/template/apps/web/dev/dev-port.ts +1 -1
  116. package/template/apps/web/dev/start.ts +6 -1
  117. package/template/apps/web/index.html +1 -0
  118. package/template/apps/web/package.json +16 -16
  119. package/template/apps/web/runtime-server.test.ts +22 -1
  120. package/template/apps/web/runtime-server.ts +6 -0
  121. package/template/apps/web/src/App.vue +6 -3
  122. package/template/apps/web/src/assets/windy.svg +4 -0
  123. package/template/apps/web/src/components/auth/LoginForm.vue +2 -2
  124. package/template/apps/web/src/components/auth/PasswordChangeForm.vue +14 -3
  125. package/template/apps/web/src/components/common/FormDialog.vue +1 -1
  126. package/template/apps/web/src/components/license/LicenseFlow.webtest.ts +3 -0
  127. package/template/apps/web/src/components/license/LicenseMachineCodeQr.vue +99 -0
  128. package/template/apps/web/src/components/license/LicenseMachineCodeQr.webtest.ts +83 -0
  129. package/template/apps/web/src/components/license/LicensePairingCard.vue +1 -1
  130. package/template/apps/web/src/components/license/LicenseStatusCard.vue +14 -2
  131. package/template/apps/web/src/composables/useLoginFlow.ts +2 -2
  132. package/template/apps/web/src/composables/usePlatformSettings.ts +1 -1
  133. package/template/apps/web/src/composables/useWatermarkSettings.ts +1 -0
  134. package/template/apps/web/src/layout/AppSidebar.vue +5 -9
  135. package/template/apps/web/src/layout/AppSidebar.webtest.ts +4 -1
  136. package/template/apps/web/src/pages/auth/ChangePasswordPage.vue +67 -6
  137. package/template/apps/web/src/pages/auth/LoginPage.vue +3 -12
  138. package/template/apps/web/src/pages/configuration/components/ModuleConfigurationEditor.vue +30 -0
  139. package/template/apps/web/src/pages/configuration/components/ModuleConfigurationWorkbench.vue +25 -14
  140. package/template/apps/web/src/pages/configuration/components/TimeZoneSelect.vue +55 -0
  141. package/template/apps/web/src/pages/profile/PersonalSettingsPage.vue +64 -11
  142. package/template/apps/web/src/pages/profile/PersonalSettingsPage.webtest.ts +21 -1
  143. package/template/apps/web/src/pages/settings/BrandingSettingsSection.vue +7 -18
  144. package/template/apps/web/src/pages/settings/BrandingSettingsSection.webtest.ts +9 -4
  145. package/template/apps/web/src/pages/settings/GlobalSettingsPage.vue +51 -6
  146. package/template/apps/web/src/pages/settings/GlobalSettingsPage.webtest.ts +19 -3
  147. package/template/apps/web/src/pages/settings/WatermarkSettingsSection.vue +1 -0
  148. package/template/apps/web/src/pages/settings/WatermarkYamlTransfer.vue +211 -0
  149. package/template/apps/web/src/pages/system/DiagnosticLookupPage.vue +18 -3
  150. package/template/apps/web/src/pages/system/DiagnosticLookupPage.webtest.ts +4 -1
  151. package/template/apps/web/src/pages/system/SystemOperationsPage.vue +23 -0
  152. package/template/apps/web/src/pages/system/components/DiagnosticLogList.vue +120 -0
  153. package/template/apps/web/src/pages/system/components/OperationEnvironmentPanel.vue +237 -0
  154. package/template/apps/web/src/pages/system/components/OperationFeatureAssessmentPanel.vue +131 -0
  155. package/template/apps/web/src/pages/system/components/PagedSelectionList.vue +31 -24
  156. package/template/apps/web/src/pages/system/components/SystemResourceActions.vue +2 -1
  157. package/template/apps/web/src/pages/system/components/SystemResourceEditor.vue +11 -2
  158. package/template/apps/web/src/pages/system/components/SystemResourcePage.vue +1 -0
  159. package/template/apps/web/src/pages/system/components/SystemResourcePage.webtest.ts +6 -2
  160. package/template/apps/web/src/pages/system/components/agent-skills/AgentSkillImportDialog.vue +18 -9
  161. package/template/apps/web/src/pages/system/components/agent-workbench/SessionReplayTimeline.vue +18 -9
  162. package/template/apps/web/src/pages/system/components/agent-workbench/TestRunComposer.vue +66 -34
  163. package/template/apps/web/src/pages/system/components/agent-workbench/ToolCatalogPanel.vue +48 -33
  164. package/template/apps/web/src/pages/system/components/agent-workbench/ToolCatalogPanel.webtest.ts +9 -2
  165. package/template/apps/web/src/pages/system/components/agent-workbench/ToolRuleDetail.vue +23 -16
  166. package/template/apps/web/src/pages/system/components/dictionary-bulk/DictionaryBulkJobDetail.vue +10 -7
  167. package/template/apps/web/src/pages/system/components/user-account/RolePermissionSummary.vue +81 -57
  168. package/template/apps/web/src/pages/system/components/user-account/UserRoleSelector.vue +6 -4
  169. package/template/apps/web/src/pages/system/components/user-account/UserRoleSelector.webtest.ts +20 -4
  170. package/template/apps/web/src/pages/system/resource-config.ts +9 -0
  171. package/template/apps/web/src/pages/work-orders/WorkOrderListPage.vue +1 -1
  172. package/template/apps/web/src/router/disabled-feature-loading.webtest.ts +78 -0
  173. package/template/apps/web/src/router/index.ts +3 -6
  174. package/template/apps/web/src/router/manifest-routes.ts +2 -3
  175. package/template/apps/web/src/router/platform-admin-pages.ts +21 -62
  176. package/template/apps/web/src/router/platform-admin-route-bindings.ts +4 -4
  177. package/template/apps/web/src/services/diagnostics-api.ts +13 -1
  178. package/template/apps/web/src/services/operations-api.ts +4 -0
  179. package/template/apps/web/src/services/platform-settings-api.ts +35 -1
  180. package/template/apps/web/vite.config.ts +9 -3
  181. package/template/deploy/environment/windy.environment.example.yaml +53 -0
  182. package/template/docker-compose.yml +4 -2
  183. package/template/docs/architecture/agent-admin-workbench-implementation.md +1 -1
  184. package/template/docs/architecture/agent-admin-workbench-plan.md +1 -1
  185. package/template/docs/architecture/agent-workflow.md +8 -0
  186. package/template/docs/architecture/durable-jobs.md +17 -0
  187. package/template/docs/architecture/embedded-dsh-integration.md +1 -1
  188. package/template/docs/development/dsh-plugins.md +1 -1
  189. package/template/docs/development/performance-engineering.md +24 -0
  190. package/template/docs/operations/admin-settings-yaml.md +29 -0
  191. package/template/docs/operations/dsh-agent-migration.md +2 -2
  192. package/template/docs/operations/environment-capabilities.md +185 -0
  193. package/template/docs/platform/module-configuration.md +18 -3
  194. package/template/docs/platform/platform-authentication.md +1 -1
  195. package/template/package.json +10 -8
  196. package/template/packages/config/package.json +2 -2
  197. package/template/packages/config/src/definition.ts +14 -4
  198. package/template/packages/config/src/environment-loader.ts +27 -3
  199. package/template/packages/config/src/platform-ai-runtime.test.ts +94 -0
  200. package/template/packages/config/src/platform.ts +5 -2
  201. package/template/packages/database/drizzle/0065_durable_job_lease_snapshot_lookup.sql +1 -0
  202. package/template/packages/database/drizzle/0066_agent_source_sequence_bigint.sql +3 -0
  203. package/template/packages/database/drizzle/0067_media_runtime_access.sql +46 -0
  204. package/template/packages/database/drizzle/meta/0065_snapshot.json +15370 -0
  205. package/template/packages/database/drizzle/meta/0066_snapshot.json +15370 -0
  206. package/template/packages/database/drizzle/meta/0067_snapshot.json +15370 -0
  207. package/template/packages/database/drizzle/meta/_journal.json +21 -0
  208. package/template/packages/database/package.json +3 -3
  209. package/template/packages/database/src/schema/agent-session.ts +4 -3
  210. package/template/packages/database/src/schema/durable-jobs.ts +4 -0
  211. package/template/packages/database/src/schema/index.ts +3 -1
  212. package/template/packages/database/src/schema-durable-recovery.test.ts +21 -1
  213. package/template/packages/database/src/schema-source-sequence.test.ts +24 -0
  214. package/template/packages/example-work-order/package.json +2 -2
  215. package/template/packages/modules/package.json +1 -1
  216. package/template/packages/modules/src/admin-ui-boundary.test.ts +33 -0
  217. package/template/packages/modules/src/composition.ts +11 -28
  218. package/template/packages/modules/src/manifest.ts +2 -0
  219. package/template/packages/modules/src/menu-composition.ts +24 -0
  220. package/template/packages/modules/src/system-admin-routes.ts +2 -2
  221. package/template/packages/modules/src/system-admin-ui-catalog.ts +6 -1
  222. package/template/packages/modules/src/system-ai-api-bindings.ts +0 -16
  223. package/template/packages/modules/src/system-api-control-plane.ts +9 -1
  224. package/template/packages/modules/src/system-api-permissions.ts +7 -0
  225. package/template/packages/modules/src/system-api-watermark.ts +21 -0
  226. package/template/packages/modules/src/system-audit-actions.ts +3 -1
  227. package/template/packages/modules/src/system-features.ts +21 -3
  228. package/template/packages/modules/src/system-media-api-bindings.ts +97 -0
  229. package/template/packages/modules/src/system-module-audit-selection.ts +2 -0
  230. package/template/packages/modules/src/system-module-catalog.test.ts +13 -6
  231. package/template/packages/modules/src/system-module-catalog.ts +6 -241
  232. package/template/packages/modules/src/system-module-definitions.ts +260 -0
  233. package/template/packages/modules/src/system-modules-access.test.ts +2 -0
  234. package/template/packages/modules/src/system-modules.test.ts +7 -1
  235. package/template/packages/modules/src/system-modules.ts +25 -13
  236. package/template/packages/modules/src/system-permissions.ts +12 -0
  237. package/template/packages/server-sdk/package.json +1 -1
  238. package/template/packages/shared/index.ts +3 -0
  239. package/template/packages/shared/package.json +1 -1
  240. package/template/packages/shared/src/environment-assessment.ts +68 -0
  241. package/template/packages/shared/src/environment-policy.ts +205 -0
  242. package/template/packages/shared/src/license-console-capabilities.ts +7 -0
  243. package/template/packages/shared/src/license.ts +1 -0
  244. package/template/packages/shared/src/module-configuration.ts +2 -1
  245. package/template/scripts/operations/collect-device-info.py +230 -0
  246. package/template/apps/server/src/agent/module-ai-port-factory.ts +0 -41
  247. /package/template/apps/server/src/{agent → ai-runtime-security}/execution-grants.ts +0 -0
  248. /package/template/apps/server/src/{agent → ai-runtime-security}/idempotency-key.test.ts +0 -0
  249. /package/template/apps/server/src/{agent → ai-runtime-security}/idempotency-key.ts +0 -0
  250. /package/template/apps/server/src/{agent → ai-runtime-security}/provider-input-governance.test.ts +0 -0
  251. /package/template/apps/server/src/{agent → ai-runtime-security}/provider-input-governance.ts +0 -0
  252. /package/template/apps/server/src/{agent → media-runtime}/required-environment.ts +0 -0
  253. /package/template/apps/server/src/{agent → media-runtime}/runtime-readiness-sources.test.ts +0 -0
@@ -91,7 +91,16 @@ onMounted(() => window.addEventListener("beforeunload", preventDirtyUnload));
91
91
  onBeforeUnmount(() =>
92
92
  window.removeEventListener("beforeunload", preventDirtyUnload),
93
93
  );
94
- const title = computed(() => (props.item ? "编辑记录" : "新增记录"));
94
+ const title = computed(
95
+ () =>
96
+ `${props.item ? "编辑" : "新增"}${props.config.entityLabel ?? props.config.title}`,
97
+ );
98
+ const contentClass = computed(() => {
99
+ if (["users", "departments"].includes(props.config.key)) {
100
+ return "sm:max-w-[calc(100%-2rem)]";
101
+ }
102
+ return props.config.key === "roles" ? "sm:max-w-4xl" : undefined;
103
+ });
95
104
  </script>
96
105
 
97
106
  <template>
@@ -101,7 +110,7 @@ const title = computed(() => (props.item ? "编辑记录" : "新增记录"));
101
110
  :description="config.description"
102
111
  :loading="loading || saving"
103
112
  :before-close="beforeClose"
104
- :content-class="config.key === 'roles' ? 'sm:max-w-4xl' : undefined"
113
+ :content-class="contentClass"
105
114
  @submit="saveForm"
106
115
  >
107
116
  <p v-if="error" class="text-sm text-destructive" role="alert">
@@ -200,6 +200,7 @@ async function importData(file: File) {
200
200
  <CardTitle class="text-base">数据列表</CardTitle>
201
201
  <SystemResourceActions
202
202
  :can-create="resource.canCreate.value"
203
+ :create-label="config.key === 'users' ? '新增人员' : undefined"
203
204
  :can-import="resource.canImport.value"
204
205
  :replaces-native-transfer="config.replacesNativeTransfer"
205
206
  @refresh="resource.reload"
@@ -280,10 +280,14 @@ describe("SystemResourcePage", () => {
280
280
 
281
281
  const add = wrapper
282
282
  .findAll("button")
283
- .find((button) => button.text() === "新增");
284
- await add?.trigger("click");
283
+ .find((button) => button.text() === "新增人员");
284
+ expect(add).toBeDefined();
285
+ await add!.trigger("click");
285
286
  await flushPromises();
286
287
 
288
+ expect(
289
+ document.body.querySelector('[role="dialog"]')?.textContent,
290
+ ).toContain("新增人员");
287
291
  expect(document.body.textContent).toContain("所属部门");
288
292
  expect(document.body.textContent).toContain("新建部门");
289
293
  expect(document.body.textContent).toContain("每页 10 条");
@@ -1,4 +1,12 @@
1
1
  <script setup lang="ts">
2
+ import {
3
+ Select,
4
+ SelectContent,
5
+ SelectItem,
6
+ SelectTrigger,
7
+ SelectValue,
8
+ } from "@/components/ui/select";
9
+
2
10
  import { computed, onBeforeUnmount, shallowRef, watch } from "vue";
3
11
  import { onBeforeRouteLeave } from "vue-router";
4
12
  import type {
@@ -229,15 +237,16 @@ onBeforeUnmount(() => {
229
237
  <div class="grid gap-4 sm:grid-cols-2">
230
238
  <label class="space-y-2 text-sm"
231
239
  ><span>共享范围</span
232
- ><select
233
- v-model="scope"
234
- class="h-9 w-full rounded-md border bg-background px-3 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
235
- :disabled="saving"
236
- >
237
- <option value="tenant">全租户</option>
238
- <option value="department">当前部门</option>
239
- <option value="personal">仅本人</option>
240
- </select></label
240
+ ><Select v-model="scope" :disabled="saving">
241
+ <SelectTrigger aria-label="共享范围" class="w-full"
242
+ ><SelectValue
243
+ /></SelectTrigger>
244
+ <SelectContent>
245
+ <SelectItem value="tenant">全租户</SelectItem>
246
+ <SelectItem value="department">当前部门</SelectItem>
247
+ <SelectItem value="personal">仅本人</SelectItem>
248
+ </SelectContent>
249
+ </Select></label
241
250
  ><label class="space-y-2 text-sm"
242
251
  ><span>当前版本(新技能填 0)</span
243
252
  ><Input
@@ -1,4 +1,12 @@
1
1
  <script setup lang="ts">
2
+ import {
3
+ Select,
4
+ SelectContent,
5
+ SelectItem,
6
+ SelectTrigger,
7
+ SelectValue,
8
+ } from "@/components/ui/select";
9
+
2
10
  import { computed } from "vue";
3
11
  import type { AgentWorkbenchRecordingV1 } from "@southwind-ai/shared";
4
12
  import { Button } from "@/components/ui/button";
@@ -68,15 +76,16 @@ const replay = useSessionReplay(events);
68
76
  :disabled="replay.cursor.value >= entries.length - 1"
69
77
  @click="replay.seek(replay.cursor.value + 1)"
70
78
  >下一事件</Button
71
- ><select
72
- v-model.number="replay.speed.value"
73
- aria-label="回放速度"
74
- class="h-9 rounded-md border bg-background px-2 text-sm"
75
- >
76
- <option :value="0.5">0.5 倍速</option>
77
- <option :value="1">1 倍速</option>
78
- <option :value="2">2 倍速</option>
79
- <option :value="4">4 倍速</option></select
79
+ ><Select v-model="replay.speed.value">
80
+ <SelectTrigger aria-label="回放速度"><SelectValue /></SelectTrigger>
81
+ <SelectContent>
82
+ <SelectItem
83
+ v-for="speed in [0.5, 1, 2, 4]"
84
+ :key="speed"
85
+ :value="speed"
86
+ >{{ speed }} 倍速</SelectItem
87
+ >
88
+ </SelectContent> </Select
80
89
  ><span class="text-xs text-muted-foreground"
81
90
  >{{ replay.cursor.value + 1 }} / {{ entries.length }}</span
82
91
  >
@@ -1,7 +1,23 @@
1
1
  <script setup lang="ts">
2
+ import {
3
+ Select,
4
+ SelectContent,
5
+ SelectItem,
6
+ SelectTrigger,
7
+ SelectValue,
8
+ } from "@/components/ui/select";
9
+
2
10
  import { computed } from "vue";
3
11
  import type { AgentAdminOperationCatalogItem } from "@southwind-ai/shared";
4
12
  import { Button } from "@/components/ui/button";
13
+ import {
14
+ Sheet,
15
+ SheetContent,
16
+ SheetDescription,
17
+ SheetHeader,
18
+ SheetTitle,
19
+ SheetTrigger,
20
+ } from "@/components/ui/sheet";
5
21
  import { availabilityLabel, formatJson } from "./catalog-presenter";
6
22
  const props = defineProps<{
7
23
  operations: readonly AgentAdminOperationCatalogItem[];
@@ -31,44 +47,60 @@ const operation = computed(() =>
31
47
  </p>
32
48
  <label class="grid gap-2 text-sm"
33
49
  ><span>Operation</span
34
- ><select
50
+ ><Select
35
51
  required
36
- :value="operationKey"
52
+ name="operationKey"
53
+ :model-value="operationKey || null"
37
54
  :disabled="starting || running || !canManage"
38
- class="h-9 rounded-md border bg-background px-2 user-invalid:border-destructive"
39
- @change="$emit('operation', ($event.target as HTMLSelectElement).value)"
55
+ @update:model-value="$emit('operation', String($event ?? ''))"
40
56
  >
41
- <option value="" disabled>请选择已注册操作</option>
42
- <option
43
- v-for="item in operations"
44
- :key="item.key"
45
- :value="item.key"
46
- :disabled="!item.selectable"
47
- >
48
- {{ item.key }} · {{ item.moduleLabel
49
- }}{{
50
- item.selectable
51
- ? ""
52
- : `(${availabilityLabel(item.availabilityReason)})`
53
- }}
54
- </option>
55
- </select></label
57
+ <SelectTrigger aria-label="Operation" class="w-full"
58
+ ><SelectValue placeholder="请选择已注册操作"
59
+ /></SelectTrigger>
60
+ <SelectContent>
61
+ <SelectItem
62
+ v-for="item in operations"
63
+ :key="item.key"
64
+ :value="item.key"
65
+ :disabled="!item.selectable"
66
+ >
67
+ {{ item.key }} · {{ item.moduleLabel
68
+ }}{{
69
+ item.selectable
70
+ ? ""
71
+ : `(${availabilityLabel(item.availabilityReason)})`
72
+ }}
73
+ </SelectItem>
74
+ </SelectContent>
75
+ </Select></label
56
76
  >
57
- <details v-if="operation">
58
- <summary class="cursor-pointer text-xs">
59
- 查看输入 Schema 与运行规则
60
- </summary>
61
- <pre
62
- class="mt-2 max-h-64 overflow-auto rounded-md bg-muted p-3 text-xs"
63
- >{{ formatJson(operation.inputSchema) }}</pre>
64
- <p class="mt-2 text-xs text-muted-foreground">
65
- {{ availabilityLabel(operation.availabilityReason) }};最长
66
- {{ operation.limits.maxDurationSeconds }} 秒;输入
67
- {{ operation.limits.maxInputBytes }} 字节。允许工具:{{
68
- operation.allowedToolKeys.join("、") || "无"
69
- }}
70
- </p>
71
- </details>
77
+ <Sheet v-if="operation" :key="operation.key">
78
+ <SheetTrigger as-child>
79
+ <Button type="button" variant="outline" size="sm">
80
+ 查看输入 Schema 与运行规则
81
+ </Button>
82
+ </SheetTrigger>
83
+ <SheetContent class="w-full overflow-y-auto sm:max-w-xl">
84
+ <SheetHeader>
85
+ <SheetTitle>输入 Schema 与运行规则</SheetTitle>
86
+ <SheetDescription class="break-all">{{
87
+ operation.key
88
+ }}</SheetDescription>
89
+ </SheetHeader>
90
+ <div class="space-y-4 px-4 pb-4">
91
+ <p class="text-sm text-muted-foreground">
92
+ {{ availabilityLabel(operation.availabilityReason) }};最长
93
+ {{ operation.limits.maxDurationSeconds }} 秒;输入
94
+ {{ operation.limits.maxInputBytes }} 字节。允许工具:{{
95
+ operation.allowedToolKeys.join("、") || "无"
96
+ }}
97
+ </p>
98
+ <pre class="overflow-auto rounded-md bg-muted p-3 text-xs">{{
99
+ formatJson(operation.inputSchema)
100
+ }}</pre>
101
+ </div>
102
+ </SheetContent>
103
+ </Sheet>
72
104
  <label class="grid gap-2 text-sm"
73
105
  ><span>测试输入(JSON)</span
74
106
  ><textarea
@@ -1,6 +1,13 @@
1
1
  <script setup lang="ts">
2
2
  import type { AgentAdminToolCatalogItem } from "@southwind-ai/shared";
3
3
  import { computed, shallowRef } from "vue";
4
+ import {
5
+ Select,
6
+ SelectContent,
7
+ SelectItem,
8
+ SelectTrigger,
9
+ SelectValue,
10
+ } from "@/components/ui/select";
4
11
  import { Input } from "@/components/ui/input";
5
12
  import { availabilityLabel } from "./catalog-presenter";
6
13
  const props = defineProps<{
@@ -9,9 +16,9 @@ const props = defineProps<{
9
16
  }>();
10
17
  defineEmits<{ select: [key: string] }>();
11
18
  const query = shallowRef("");
12
- const moduleKey = shallowRef("");
13
- const operationKey = shallowRef("");
14
- const availability = shallowRef("");
19
+ const moduleKey = shallowRef("*");
20
+ const operationKey = shallowRef("*");
21
+ const availability = shallowRef("*");
15
22
  const modules = computed(() =>
16
23
  [...new Set(props.tools.map((tool) => tool.module))].sort(),
17
24
  );
@@ -21,10 +28,10 @@ const operations = computed(() =>
21
28
  const filtered = computed(() =>
22
29
  props.tools.filter(
23
30
  (tool) =>
24
- (!moduleKey.value || tool.module === moduleKey.value) &&
25
- (!operationKey.value ||
31
+ (moduleKey.value === "*" || tool.module === moduleKey.value) &&
32
+ (operationKey.value === "*" ||
26
33
  tool.allowedOperationKeys.includes(operationKey.value)) &&
27
- (!availability.value ||
34
+ (availability.value === "*" ||
28
35
  tool.allowed === (availability.value === "allowed")) &&
29
36
  `${tool.key} ${tool.label} ${tool.description}`
30
37
  .toLocaleLowerCase()
@@ -43,33 +50,41 @@ const filtered = computed(() =>
43
50
  placeholder="搜索名称、说明或 Key"
44
51
  />
45
52
  <div class="grid gap-2 sm:grid-cols-3 lg:grid-cols-1">
46
- <select
47
- v-model="moduleKey"
48
- aria-label="所属模块筛选"
49
- class="h-9 rounded-md border bg-background px-2 text-sm"
50
- >
51
- <option value="">所有模块</option>
52
- <option v-for="module in modules" :key="module">{{ module }}</option>
53
- </select>
54
- <select
55
- v-model="operationKey"
56
- aria-label="Operation 筛选"
57
- class="h-9 rounded-md border bg-background px-2 text-sm"
58
- >
59
- <option value="">所有 Operations</option>
60
- <option v-for="operation in operations" :key="operation">
61
- {{ operation }}
62
- </option>
63
- </select>
64
- <select
65
- v-model="availability"
66
- aria-label="调用条件筛选"
67
- class="h-9 rounded-md border bg-background px-2 text-sm"
68
- >
69
- <option value="">所有调用状态</option>
70
- <option value="allowed">具备调用条件</option>
71
- <option value="denied">当前不可调用</option>
72
- </select>
53
+ <Select v-model="moduleKey">
54
+ <SelectTrigger aria-label="所属模块筛选" class="w-full"
55
+ ><SelectValue
56
+ /></SelectTrigger>
57
+ <SelectContent>
58
+ <SelectItem value="*">所有模块</SelectItem>
59
+ <SelectItem v-for="module in modules" :key="module" :value="module">{{
60
+ module
61
+ }}</SelectItem>
62
+ </SelectContent>
63
+ </Select>
64
+ <Select v-model="operationKey">
65
+ <SelectTrigger aria-label="Operation 筛选" class="w-full"
66
+ ><SelectValue
67
+ /></SelectTrigger>
68
+ <SelectContent>
69
+ <SelectItem value="*">所有 Operations</SelectItem>
70
+ <SelectItem
71
+ v-for="operation in operations"
72
+ :key="operation"
73
+ :value="operation"
74
+ >{{ operation }}</SelectItem
75
+ >
76
+ </SelectContent>
77
+ </Select>
78
+ <Select v-model="availability">
79
+ <SelectTrigger aria-label="调用条件筛选" class="w-full"
80
+ ><SelectValue
81
+ /></SelectTrigger>
82
+ <SelectContent>
83
+ <SelectItem value="*">所有调用状态</SelectItem>
84
+ <SelectItem value="allowed">具备调用条件</SelectItem>
85
+ <SelectItem value="denied">当前不可调用</SelectItem>
86
+ </SelectContent>
87
+ </Select>
73
88
  </div>
74
89
  <p class="text-xs text-muted-foreground">
75
90
  {{ filtered.length }} /
@@ -1,6 +1,7 @@
1
1
  import { mount } from "@vue/test-utils";
2
2
  import { describe, expect, test } from "vitest";
3
3
  import type { AgentAdminToolCatalogItem } from "@southwind-ai/shared";
4
+ import { Select } from "@/components/ui/select";
4
5
  import ToolCatalogPanel from "./ToolCatalogPanel.vue";
5
6
  import ToolRuleDetail from "./ToolRuleDetail.vue";
6
7
  const tool: AgentAdminToolCatalogItem = {
@@ -39,10 +40,16 @@ describe("动态工具目录", () => {
39
40
  await wrapper.get("input").setValue("copilot");
40
41
  expect(wrapper.text()).toContain("没有匹配");
41
42
  await wrapper.get("input").setValue("位置");
42
- await wrapper.get("button").trigger("click");
43
+ await wrapper.get("button[aria-pressed]").trigger("click");
43
44
  expect(wrapper.emitted("select")).toEqual([[tool.key]]);
44
- await wrapper.get('[aria-label="调用条件筛选"]').setValue("allowed");
45
+ await wrapper
46
+ .findAllComponents(Select)[2]!
47
+ .vm.$emit("update:modelValue", "allowed");
45
48
  expect(wrapper.text()).toContain("没有匹配");
49
+ await wrapper
50
+ .findAllComponents(Select)[2]!
51
+ .vm.$emit("update:modelValue", "*");
52
+ expect(wrapper.text()).toContain("位置查询");
46
53
  });
47
54
  test("Schema 和审批/范围/限制展示使用实际注册投影", () => {
48
55
  const wrapper = mount(ToolRuleDetail, { props: { tool } });
@@ -1,4 +1,5 @@
1
1
  <script setup lang="ts">
2
+ import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
2
3
  import type { AgentAdminToolCatalogItem } from "@southwind-ai/shared";
3
4
  import { availabilityLabel, formatJson } from "./catalog-presenter";
4
5
  defineProps<{ tool?: AgentAdminToolCatalogItem }>();
@@ -60,22 +61,28 @@ defineProps<{ tool?: AgentAdminToolCatalogItem }>();
60
61
  {{ tool.allowedOperationKeys.join("、") || "没有已注册操作允许调用" }}
61
62
  </dd>
62
63
  </dl>
63
- <details open class="mb-3">
64
- <summary class="cursor-pointer text-sm font-medium">
65
- 输入 Schema · {{ tool.inputSchemaKey }}
66
- </summary>
67
- <pre
68
- class="mt-2 max-h-80 overflow-auto rounded-md bg-muted p-3 text-xs"
69
- >{{ formatJson(tool.inputSchema) }}</pre>
70
- </details>
71
- <details open>
72
- <summary class="cursor-pointer text-sm font-medium">
73
- 输出 Schema · {{ tool.outputSchemaKey }}
74
- </summary>
75
- <pre
76
- class="mt-2 max-h-80 overflow-auto rounded-md bg-muted p-3 text-xs"
77
- >{{ formatJson(tool.outputSchema) }}</pre>
78
- </details>
64
+ <Tabs :key="tool.key" default-value="input">
65
+ <TabsList aria-label="工具 Schema">
66
+ <TabsTrigger value="input">输入 Schema</TabsTrigger>
67
+ <TabsTrigger value="output">输出 Schema</TabsTrigger>
68
+ </TabsList>
69
+ <TabsContent value="input">
70
+ <p class="break-all font-mono text-xs text-muted-foreground">
71
+ {{ tool.inputSchemaKey }}
72
+ </p>
73
+ <pre
74
+ class="mt-2 max-h-80 overflow-auto rounded-md bg-muted p-3 text-xs"
75
+ >{{ formatJson(tool.inputSchema) }}</pre>
76
+ </TabsContent>
77
+ <TabsContent value="output">
78
+ <p class="break-all font-mono text-xs text-muted-foreground">
79
+ {{ tool.outputSchemaKey }}
80
+ </p>
81
+ <pre
82
+ class="mt-2 max-h-80 overflow-auto rounded-md bg-muted p-3 text-xs"
83
+ >{{ formatJson(tool.outputSchema) }}</pre>
84
+ </TabsContent>
85
+ </Tabs>
79
86
  </template>
80
87
  </section>
81
88
  </template>
@@ -71,13 +71,6 @@ const detail = computed(() => {
71
71
  <dd class="mt-1">{{ detail.retryAt }}</dd>
72
72
  </div>
73
73
  </dl>
74
- <details class="rounded-md bg-muted/50 p-3 text-xs">
75
- <summary class="cursor-pointer font-medium">技术信息</summary>
76
- <p class="mt-2 text-muted-foreground">
77
- 防重复令牌由浏览器自动生成,同一次网络重试会复用,避免重复创建任务。
78
- </p>
79
- <p class="mt-2 break-all font-mono">{{ job.idempotencyKey }}</p>
80
- </details>
81
74
  <p v-if="job.error" class="rounded-md bg-muted p-3 text-sm">
82
75
  最近一次系统错误:{{ job.error }}
83
76
  </p>
@@ -104,6 +97,16 @@ const detail = computed(() => {
104
97
  <p v-if="detail.failuresAvailable" class="text-xs text-muted-foreground">
105
98
  失败明细仅含行号、错误分类、安全消息和输入摘要,不回显原始输入行。
106
99
  </p>
100
+ <section class="grid gap-2 border-t pt-3 text-xs">
101
+ <h4 class="font-medium">技术信息</h4>
102
+ <dl class="grid gap-1">
103
+ <dt class="text-muted-foreground">防重复令牌</dt>
104
+ <dd class="break-all font-mono">{{ job.idempotencyKey }}</dd>
105
+ </dl>
106
+ <p class="text-muted-foreground">
107
+ 同一次网络重试会复用此令牌,避免重复创建任务。
108
+ </p>
109
+ </section>
107
110
  </template>
108
111
  </aside>
109
112
  </template>
@@ -2,6 +2,14 @@
2
2
  import { computed, shallowRef, watch } from "vue";
3
3
  import { Input } from "@/components/ui/input";
4
4
  import { Button } from "@/components/ui/button";
5
+ import {
6
+ Sheet,
7
+ SheetContent,
8
+ SheetDescription,
9
+ SheetHeader,
10
+ SheetTitle,
11
+ SheetTrigger,
12
+ } from "@/components/ui/sheet";
5
13
  import type { PermissionDefinition } from "@southwind-ai/shared";
6
14
  import {
7
15
  groupPermissions,
@@ -9,6 +17,7 @@ import {
9
17
  } from "../role-policy/permission-tree";
10
18
 
11
19
  const props = defineProps<{
20
+ roleName: string;
12
21
  permissionKeys: string[];
13
22
  permissions: PermissionDefinition[];
14
23
  }>();
@@ -54,64 +63,79 @@ const unknownKeys = computed(() =>
54
63
  >
55
64
  未分配功能权限
56
65
  </p>
57
- <details v-else class="mt-3 border-t pt-3 text-xs">
58
- <summary
59
- class="cursor-pointer select-none font-medium text-muted-foreground hover:text-foreground"
60
- >
61
- 查看 {{ permissionKeys.length }} 项功能权限
62
- </summary>
63
- <div class="mt-3 grid gap-3">
64
- <Input
65
- v-model="keyword"
66
- @keydown.enter.prevent
67
- aria-label="搜索角色权限摘要"
68
- placeholder="搜索功能权限"
69
- />
70
- <section v-for="group in groups" :key="group.key" class="grid gap-2">
71
- <p class="font-medium text-foreground">{{ group.label }}</p>
72
- <div
73
- v-for="resource in group.resources"
74
- :key="resource.key"
75
- class="grid gap-1 sm:grid-cols-[8rem_1fr]"
76
- >
77
- <span class="text-muted-foreground">{{ resource.label }}</span>
78
- <span class="leading-5">
79
- {{ resource.permissions.map(({ label }) => label).join("、") }}
80
- </span>
81
- </div>
82
- </section>
83
- <section v-if="unknownKeys.length" class="grid gap-1">
84
- <p class="font-medium text-amber-700 dark:text-amber-400">
85
- 未注册的历史权限
86
- </p>
87
- <code class="break-all leading-5">{{ unknownKeys.join("、") }}</code>
88
- </section>
89
- <div
90
- class="flex flex-wrap items-center justify-between gap-2 text-muted-foreground"
91
- >
92
- <span
93
- >共 {{ filteredKeys.length }} 条,每页 10 条,第 {{ page }} /
94
- {{ pageCount }} 页</span
66
+ <div v-else class="mt-3 border-t pt-3">
67
+ <Sheet>
68
+ <SheetTrigger as-child>
69
+ <Button
70
+ type="button"
71
+ variant="outline"
72
+ size="sm"
73
+ data-testid="role-permissions-trigger"
95
74
  >
96
- <div class="flex gap-2">
97
- <Button
98
- type="button"
99
- size="sm"
100
- variant="outline"
101
- :disabled="page <= 1"
102
- @click="page--"
103
- >上一页</Button
104
- >
105
- <Button
106
- type="button"
107
- size="sm"
108
- variant="outline"
109
- :disabled="page >= pageCount"
110
- @click="page++"
111
- >下一页</Button
75
+ 查看 {{ permissionKeys.length }} 项功能权限
76
+ </Button>
77
+ </SheetTrigger>
78
+ <SheetContent class="w-full overflow-y-auto sm:max-w-lg">
79
+ <SheetHeader>
80
+ <SheetTitle>角色功能权限</SheetTitle>
81
+ <SheetDescription class="break-all">{{ roleName }}</SheetDescription>
82
+ </SheetHeader>
83
+ <div class="grid gap-3 px-4 pb-4">
84
+ <Input
85
+ v-model="keyword"
86
+ @keydown.enter.prevent
87
+ aria-label="搜索角色权限摘要"
88
+ placeholder="搜索功能权限"
89
+ />
90
+ <section v-for="group in groups" :key="group.key" class="grid gap-2">
91
+ <p class="font-medium text-foreground">{{ group.label }}</p>
92
+ <div
93
+ v-for="resource in group.resources"
94
+ :key="resource.key"
95
+ class="grid gap-1 sm:grid-cols-[8rem_1fr]"
96
+ >
97
+ <span class="text-muted-foreground">{{ resource.label }}</span>
98
+ <span class="leading-5">
99
+ {{ resource.permissions.map(({ label }) => label).join("、") }}
100
+ </span>
101
+ </div>
102
+ </section>
103
+ <section v-if="unknownKeys.length" class="grid gap-1">
104
+ <p class="font-medium text-amber-700 dark:text-amber-400">
105
+ 未注册的历史权限
106
+ </p>
107
+ <code class="break-all leading-5">{{
108
+ unknownKeys.join("、")
109
+ }}</code>
110
+ </section>
111
+ <div
112
+ class="flex flex-wrap items-center justify-between gap-2 text-muted-foreground"
112
113
  >
114
+ <span
115
+ >共 {{ filteredKeys.length }} 条,每页 10 条,第 {{ page }} /
116
+ {{ pageCount }} 页</span
117
+ >
118
+ <div class="flex gap-2">
119
+ <Button
120
+ type="button"
121
+ size="sm"
122
+ variant="outline"
123
+ :disabled="page <= 1"
124
+ @click="page--"
125
+ >上一页</Button
126
+ >
127
+ <Button
128
+ type="button"
129
+ size="sm"
130
+ variant="outline"
131
+ :disabled="page >= pageCount"
132
+ @click="page++"
133
+ >下一页</Button
134
+ >
135
+ </div>
136
+ </div>
113
137
  </div>
114
- </div>
115
- </div>
116
- </details>
138
+ </SheetContent>
139
+ </Sheet>
140
+ </div>
117
141
  </template>