plugin-agent-orchestrator 1.0.13 → 1.0.15

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 (255) hide show
  1. package/README.md +16 -291
  2. package/dist/client/AIEmployeesContext.d.ts +7 -0
  3. package/dist/client/OrchestratorSettings.d.ts +2 -1
  4. package/dist/client/index.js +1 -1
  5. package/dist/client/plugin.d.ts +1 -0
  6. package/dist/client/skill-hub/components/ExecutionHistory.d.ts +2 -0
  7. package/dist/client/skill-hub/components/ExecutionProgress.d.ts +20 -0
  8. package/dist/client/skill-hub/components/GitSkillImport.d.ts +7 -0
  9. package/dist/client/skill-hub/components/SkillEditor.d.ts +7 -0
  10. package/dist/client/skill-hub/components/SkillManager.d.ts +2 -0
  11. package/dist/client/skill-hub/components/SkillMetrics.d.ts +2 -0
  12. package/dist/client/skill-hub/components/SkillTestPanel.d.ts +7 -0
  13. package/dist/client/skill-hub/index.d.ts +10 -0
  14. package/dist/client/skill-hub/locale.d.ts +3 -0
  15. package/dist/client/skill-hub/tools/InteractionSchemasProvider.d.ts +19 -0
  16. package/dist/client/skill-hub/tools/SkillHubCard.d.ts +3 -0
  17. package/dist/client/skill-hub/utils/jsonFields.d.ts +3 -0
  18. package/dist/externalVersion.js +6 -6
  19. package/dist/node_modules/adm-zip/LICENSE +21 -0
  20. package/dist/node_modules/adm-zip/adm-zip.js +1 -0
  21. package/dist/node_modules/adm-zip/headers/entryHeader.js +377 -0
  22. package/dist/node_modules/adm-zip/headers/index.js +2 -0
  23. package/dist/node_modules/adm-zip/headers/mainHeader.js +130 -0
  24. package/dist/node_modules/adm-zip/methods/deflater.js +33 -0
  25. package/dist/node_modules/adm-zip/methods/index.js +3 -0
  26. package/dist/node_modules/adm-zip/methods/inflater.js +34 -0
  27. package/dist/node_modules/adm-zip/methods/zipcrypto.js +175 -0
  28. package/dist/node_modules/adm-zip/package.json +1 -0
  29. package/dist/node_modules/adm-zip/util/constants.js +142 -0
  30. package/dist/node_modules/adm-zip/util/decoder.js +5 -0
  31. package/dist/node_modules/adm-zip/util/errors.js +63 -0
  32. package/dist/node_modules/adm-zip/util/fattr.js +76 -0
  33. package/dist/node_modules/adm-zip/util/index.js +5 -0
  34. package/dist/node_modules/adm-zip/util/utils.js +339 -0
  35. package/dist/node_modules/adm-zip/zipEntry.js +405 -0
  36. package/dist/node_modules/adm-zip/zipFile.js +446 -0
  37. package/dist/node_modules/simple-git/dist/cjs/index.js +7399 -0
  38. package/dist/node_modules/simple-git/dist/esm/index.js +4745 -0
  39. package/dist/node_modules/simple-git/dist/esm/package.json +3 -0
  40. package/dist/node_modules/simple-git/dist/src/lib/api.d.ts +13 -0
  41. package/dist/node_modules/simple-git/dist/src/lib/args/log-format.d.ts +9 -0
  42. package/dist/node_modules/simple-git/dist/src/lib/errors/git-construct-error.d.ts +15 -0
  43. package/dist/node_modules/simple-git/dist/src/lib/errors/git-error.d.ts +30 -0
  44. package/dist/node_modules/simple-git/dist/src/lib/errors/git-plugin-error.d.ts +7 -0
  45. package/dist/node_modules/simple-git/dist/src/lib/errors/git-response-error.d.ts +32 -0
  46. package/dist/node_modules/simple-git/dist/src/lib/errors/task-configuration-error.d.ts +12 -0
  47. package/dist/node_modules/simple-git/dist/src/lib/git-factory.d.ts +15 -0
  48. package/dist/node_modules/simple-git/dist/src/lib/git-logger.d.ts +21 -0
  49. package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-branch-delete.d.ts +5 -0
  50. package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-branch.d.ts +2 -0
  51. package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-commit.d.ts +2 -0
  52. package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-diff-summary.d.ts +3 -0
  53. package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-fetch.d.ts +2 -0
  54. package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-list-log-summary.d.ts +6 -0
  55. package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-merge.d.ts +11 -0
  56. package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-move.d.ts +2 -0
  57. package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-pull.d.ts +6 -0
  58. package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-push.d.ts +4 -0
  59. package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-remote-messages.d.ts +5 -0
  60. package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-remote-objects.d.ts +3 -0
  61. package/dist/node_modules/simple-git/dist/src/lib/plugins/abort-plugin.d.ts +3 -0
  62. package/dist/node_modules/simple-git/dist/src/lib/plugins/block-unsafe-operations-plugin.d.ts +3 -0
  63. package/dist/node_modules/simple-git/dist/src/lib/plugins/command-config-prefixing-plugin.d.ts +2 -0
  64. package/dist/node_modules/simple-git/dist/src/lib/plugins/completion-detection.plugin.d.ts +3 -0
  65. package/dist/node_modules/simple-git/dist/src/lib/plugins/custom-binary.plugin.d.ts +3 -0
  66. package/dist/node_modules/simple-git/dist/src/lib/plugins/error-detection.plugin.d.ts +7 -0
  67. package/dist/node_modules/simple-git/dist/src/lib/plugins/index.d.ts +11 -0
  68. package/dist/node_modules/simple-git/dist/src/lib/plugins/plugin-store.d.ts +11 -0
  69. package/dist/node_modules/simple-git/dist/src/lib/plugins/progress-monitor-plugin.d.ts +3 -0
  70. package/dist/node_modules/simple-git/dist/src/lib/plugins/simple-git-plugin.d.ts +48 -0
  71. package/dist/node_modules/simple-git/dist/src/lib/plugins/spawn-options-plugin.d.ts +3 -0
  72. package/dist/node_modules/simple-git/dist/src/lib/plugins/suffix-paths.plugin.d.ts +2 -0
  73. package/dist/node_modules/simple-git/dist/src/lib/plugins/timout-plugin.d.ts +3 -0
  74. package/dist/node_modules/simple-git/dist/src/lib/responses/BranchDeleteSummary.d.ts +12 -0
  75. package/dist/node_modules/simple-git/dist/src/lib/responses/BranchSummary.d.ts +14 -0
  76. package/dist/node_modules/simple-git/dist/src/lib/responses/CheckIgnore.d.ts +4 -0
  77. package/dist/node_modules/simple-git/dist/src/lib/responses/CleanSummary.d.ts +9 -0
  78. package/dist/node_modules/simple-git/dist/src/lib/responses/ConfigList.d.ts +13 -0
  79. package/dist/node_modules/simple-git/dist/src/lib/responses/DiffSummary.d.ts +10 -0
  80. package/dist/node_modules/simple-git/dist/src/lib/responses/FileStatusSummary.d.ts +9 -0
  81. package/dist/node_modules/simple-git/dist/src/lib/responses/GetRemoteSummary.d.ts +11 -0
  82. package/dist/node_modules/simple-git/dist/src/lib/responses/InitSummary.d.ts +9 -0
  83. package/dist/node_modules/simple-git/dist/src/lib/responses/MergeSummary.d.ts +16 -0
  84. package/dist/node_modules/simple-git/dist/src/lib/responses/PullSummary.d.ts +25 -0
  85. package/dist/node_modules/simple-git/dist/src/lib/responses/StatusSummary.d.ts +19 -0
  86. package/dist/node_modules/simple-git/dist/src/lib/responses/TagList.d.ts +7 -0
  87. package/dist/node_modules/simple-git/dist/src/lib/runners/git-executor-chain.d.ts +25 -0
  88. package/dist/node_modules/simple-git/dist/src/lib/runners/git-executor.d.ts +14 -0
  89. package/dist/node_modules/simple-git/dist/src/lib/runners/promise-wrapped.d.ts +2 -0
  90. package/dist/node_modules/simple-git/dist/src/lib/runners/scheduler.d.ts +11 -0
  91. package/dist/node_modules/simple-git/dist/src/lib/runners/tasks-pending-queue.d.ts +23 -0
  92. package/dist/node_modules/simple-git/dist/src/lib/simple-git-api.d.ts +20 -0
  93. package/dist/node_modules/simple-git/dist/src/lib/task-callback.d.ts +2 -0
  94. package/dist/node_modules/simple-git/dist/src/lib/tasks/apply-patch.d.ts +3 -0
  95. package/dist/node_modules/simple-git/dist/src/lib/tasks/branch.d.ts +7 -0
  96. package/dist/node_modules/simple-git/dist/src/lib/tasks/change-working-directory.d.ts +2 -0
  97. package/dist/node_modules/simple-git/dist/src/lib/tasks/check-ignore.d.ts +2 -0
  98. package/dist/node_modules/simple-git/dist/src/lib/tasks/check-is-repo.d.ts +9 -0
  99. package/dist/node_modules/simple-git/dist/src/lib/tasks/checkout.d.ts +2 -0
  100. package/dist/node_modules/simple-git/dist/src/lib/tasks/clean.d.ts +25 -0
  101. package/dist/node_modules/simple-git/dist/src/lib/tasks/clone.d.ts +9 -0
  102. package/dist/node_modules/simple-git/dist/src/lib/tasks/commit.d.ts +4 -0
  103. package/dist/node_modules/simple-git/dist/src/lib/tasks/config.d.ts +8 -0
  104. package/dist/node_modules/simple-git/dist/src/lib/tasks/count-objects.d.ts +12 -0
  105. package/dist/node_modules/simple-git/dist/src/lib/tasks/diff-name-status.d.ts +12 -0
  106. package/dist/node_modules/simple-git/dist/src/lib/tasks/diff.d.ts +5 -0
  107. package/dist/node_modules/simple-git/dist/src/lib/tasks/fetch.d.ts +4 -0
  108. package/dist/node_modules/simple-git/dist/src/lib/tasks/first-commit.d.ts +2 -0
  109. package/dist/node_modules/simple-git/dist/src/lib/tasks/grep.d.ts +12 -0
  110. package/dist/node_modules/simple-git/dist/src/lib/tasks/hash-object.d.ts +5 -0
  111. package/dist/node_modules/simple-git/dist/src/lib/tasks/init.d.ts +3 -0
  112. package/dist/node_modules/simple-git/dist/src/lib/tasks/log.d.ts +32 -0
  113. package/dist/node_modules/simple-git/dist/src/lib/tasks/merge.d.ts +4 -0
  114. package/dist/node_modules/simple-git/dist/src/lib/tasks/move.d.ts +3 -0
  115. package/dist/node_modules/simple-git/dist/src/lib/tasks/pull.d.ts +3 -0
  116. package/dist/node_modules/simple-git/dist/src/lib/tasks/push.d.ts +9 -0
  117. package/dist/node_modules/simple-git/dist/src/lib/tasks/remote.d.ts +8 -0
  118. package/dist/node_modules/simple-git/dist/src/lib/tasks/reset.d.ts +11 -0
  119. package/dist/node_modules/simple-git/dist/src/lib/tasks/show.d.ts +2 -0
  120. package/dist/node_modules/simple-git/dist/src/lib/tasks/stash-list.d.ts +4 -0
  121. package/dist/node_modules/simple-git/dist/src/lib/tasks/status.d.ts +3 -0
  122. package/dist/node_modules/simple-git/dist/src/lib/tasks/sub-module.d.ts +5 -0
  123. package/dist/node_modules/simple-git/dist/src/lib/tasks/tag.d.ts +18 -0
  124. package/dist/node_modules/simple-git/dist/src/lib/tasks/task.d.ts +14 -0
  125. package/dist/node_modules/simple-git/dist/src/lib/tasks/version.d.ts +9 -0
  126. package/dist/node_modules/simple-git/dist/src/lib/types/handlers.d.ts +21 -0
  127. package/dist/node_modules/simple-git/dist/src/lib/types/index.d.ts +136 -0
  128. package/dist/node_modules/simple-git/dist/src/lib/types/tasks.d.ts +19 -0
  129. package/dist/node_modules/simple-git/dist/src/lib/utils/argument-filters.d.ts +14 -0
  130. package/dist/node_modules/simple-git/dist/src/lib/utils/exit-codes.d.ts +10 -0
  131. package/dist/node_modules/simple-git/dist/src/lib/utils/git-output-streams.d.ts +7 -0
  132. package/dist/node_modules/simple-git/dist/src/lib/utils/index.d.ts +8 -0
  133. package/dist/node_modules/simple-git/dist/src/lib/utils/line-parser.d.ts +15 -0
  134. package/dist/node_modules/simple-git/dist/src/lib/utils/simple-git-options.d.ts +2 -0
  135. package/dist/node_modules/simple-git/dist/src/lib/utils/task-options.d.ts +13 -0
  136. package/dist/node_modules/simple-git/dist/src/lib/utils/task-parser.d.ts +5 -0
  137. package/dist/node_modules/simple-git/dist/src/lib/utils/util.d.ts +47 -0
  138. package/dist/node_modules/simple-git/dist/typings/errors.d.ts +5 -0
  139. package/dist/node_modules/simple-git/dist/typings/index.d.ts +14 -0
  140. package/dist/node_modules/simple-git/dist/typings/response.d.ts +556 -0
  141. package/dist/node_modules/simple-git/dist/typings/simple-git.d.ts +1033 -0
  142. package/dist/node_modules/simple-git/dist/typings/types.d.ts +22 -0
  143. package/dist/node_modules/simple-git/node_modules/debug/package.json +64 -0
  144. package/dist/node_modules/simple-git/node_modules/debug/src/browser.js +272 -0
  145. package/dist/node_modules/simple-git/node_modules/debug/src/common.js +292 -0
  146. package/dist/node_modules/simple-git/node_modules/debug/src/index.js +10 -0
  147. package/dist/node_modules/simple-git/node_modules/debug/src/node.js +263 -0
  148. package/dist/node_modules/simple-git/package.json +1 -0
  149. package/dist/node_modules/simple-git/promise.js +17 -0
  150. package/dist/server/collections/agent-execution-spans.d.ts +9 -0
  151. package/dist/server/collections/agent-execution-spans.js +152 -0
  152. package/dist/server/collections/orchestrator-config.d.ts +1 -1
  153. package/dist/server/collections/orchestrator-config.js +6 -0
  154. package/dist/server/collections/orchestrator-logs.d.ts +1 -1
  155. package/dist/server/collections/skill-definitions.d.ts +2 -0
  156. package/dist/server/collections/skill-definitions.js +158 -0
  157. package/dist/server/collections/skill-executions.d.ts +2 -0
  158. package/dist/server/collections/skill-executions.js +123 -0
  159. package/dist/server/collections/skill-worker-configs.d.ts +2 -0
  160. package/dist/server/collections/skill-worker-configs.js +115 -0
  161. package/dist/server/migrations/20260423000000-add-progress-fields.d.ts +4 -0
  162. package/dist/server/migrations/20260423000000-add-progress-fields.js +69 -0
  163. package/dist/server/migrations/20260425000000-add-interaction-schema.d.ts +4 -0
  164. package/dist/server/migrations/20260425000000-add-interaction-schema.js +61 -0
  165. package/dist/server/migrations/20260427000000-change-packages-to-text.d.ts +4 -0
  166. package/dist/server/migrations/20260427000000-change-packages-to-text.js +70 -0
  167. package/dist/server/migrations/20260427000001-change-other-json-to-text.d.ts +4 -0
  168. package/dist/server/migrations/20260427000001-change-other-json-to-text.js +80 -0
  169. package/dist/server/migrations/20260429000000-add-llm-fields.js +8 -0
  170. package/dist/server/migrations/20260429000000-fix-inputargs-json-to-text.d.ts +16 -0
  171. package/dist/server/migrations/20260429000000-fix-inputargs-json-to-text.js +51 -0
  172. package/dist/server/migrations/20260503000000-add-orchestrator-trace-fields.d.ts +7 -0
  173. package/dist/server/migrations/20260503000000-add-orchestrator-trace-fields.js +57 -0
  174. package/dist/server/plugin.d.ts +3 -0
  175. package/dist/server/plugin.js +37 -1
  176. package/dist/server/resources/tracing.js +154 -11
  177. package/dist/server/services/CodeValidator.d.ts +32 -0
  178. package/dist/server/services/CodeValidator.js +206 -0
  179. package/dist/server/services/ExecutionSpanService.d.ts +44 -0
  180. package/dist/server/services/ExecutionSpanService.js +104 -0
  181. package/dist/server/services/FileManager.d.ts +28 -0
  182. package/dist/server/services/FileManager.js +151 -0
  183. package/dist/server/services/SandboxRunner.d.ts +41 -0
  184. package/dist/server/services/SandboxRunner.js +167 -0
  185. package/dist/server/services/SkillManager.d.ts +6 -0
  186. package/dist/server/services/SkillManager.js +640 -0
  187. package/dist/server/services/SkillRepositoryService.d.ts +22 -0
  188. package/dist/server/services/SkillRepositoryService.js +157 -0
  189. package/dist/server/services/WorkerEnvManager.d.ts +26 -0
  190. package/dist/server/services/WorkerEnvManager.js +120 -0
  191. package/dist/server/skill-hub/actions/git-import.d.ts +21 -0
  192. package/dist/server/skill-hub/actions/git-import.js +413 -0
  193. package/dist/server/skill-hub/mcp/McpController.d.ts +15 -0
  194. package/dist/server/skill-hub/mcp/McpController.js +111 -0
  195. package/dist/server/skill-hub/plugin.d.ts +58 -0
  196. package/dist/server/skill-hub/plugin.js +694 -0
  197. package/dist/server/skill-hub/sandbox-config.json +6 -0
  198. package/dist/server/skill-hub/tasks/SkillExecutionTask.d.ts +16 -0
  199. package/dist/server/skill-hub/tasks/SkillExecutionTask.js +389 -0
  200. package/dist/server/skill-hub/utils/json-fields.d.ts +7 -0
  201. package/dist/server/skill-hub/utils/json-fields.js +88 -0
  202. package/dist/server/tools/delegate-task.d.ts +4 -0
  203. package/dist/server/tools/delegate-task.js +606 -104
  204. package/dist/server/tools/skill-execute.d.ts +36 -0
  205. package/dist/server/tools/skill-execute.js +167 -0
  206. package/package.json +3 -1
  207. package/src/client/AIEmployeeSelect.tsx +1 -3
  208. package/src/client/AIEmployeesContext.tsx +28 -13
  209. package/src/client/OrchestratorSettings.tsx +43 -5
  210. package/src/client/RulesTab.tsx +253 -32
  211. package/src/client/TracingTab.tsx +277 -213
  212. package/src/client/index.tsx +1 -1
  213. package/src/client/plugin.tsx +54 -15
  214. package/src/client/skill-hub/components/ExecutionHistory.tsx +201 -0
  215. package/src/client/skill-hub/components/ExecutionProgress.tsx +55 -0
  216. package/src/client/skill-hub/components/GitSkillImport.tsx +555 -0
  217. package/src/client/skill-hub/components/SkillEditor.tsx +456 -0
  218. package/src/client/skill-hub/components/SkillManager.tsx +181 -0
  219. package/src/client/skill-hub/components/SkillMetrics.tsx +124 -0
  220. package/src/client/skill-hub/components/SkillTestPanel.tsx +144 -0
  221. package/src/client/skill-hub/index.tsx +75 -0
  222. package/src/client/skill-hub/locale.ts +16 -0
  223. package/src/client/skill-hub/tools/InteractionSchemasProvider.tsx +59 -0
  224. package/src/client/skill-hub/tools/SkillHubCard.tsx +78 -0
  225. package/src/client/skill-hub/utils/jsonFields.ts +37 -0
  226. package/src/server/collections/agent-execution-spans.ts +129 -0
  227. package/src/server/collections/orchestrator-config.ts +7 -0
  228. package/src/server/collections/skill-definitions.ts +128 -0
  229. package/src/server/collections/skill-executions.ts +94 -0
  230. package/src/server/collections/skill-worker-configs.ts +86 -0
  231. package/src/server/migrations/20260423000000-add-progress-fields.ts +50 -0
  232. package/src/server/migrations/20260425000000-add-interaction-schema.ts +35 -0
  233. package/src/server/migrations/20260427000000-add-tracing-detail-fields.ts +5 -5
  234. package/src/server/migrations/20260427000000-change-packages-to-text.ts +47 -0
  235. package/src/server/migrations/20260427000001-change-other-json-to-text.ts +57 -0
  236. package/src/server/migrations/20260429000000-add-llm-fields.ts +11 -2
  237. package/src/server/migrations/20260429000000-fix-inputargs-json-to-text.ts +38 -0
  238. package/src/server/migrations/20260503000000-add-orchestrator-trace-fields.ts +32 -0
  239. package/src/server/plugin.ts +94 -46
  240. package/src/server/resources/tracing.ts +182 -15
  241. package/src/server/services/CodeValidator.ts +159 -0
  242. package/src/server/services/ExecutionSpanService.ts +106 -0
  243. package/src/server/services/FileManager.ts +144 -0
  244. package/src/server/services/SandboxRunner.ts +205 -0
  245. package/src/server/services/SkillManager.ts +623 -0
  246. package/src/server/services/SkillRepositoryService.ts +142 -0
  247. package/src/server/services/WorkerEnvManager.ts +113 -0
  248. package/src/server/skill-hub/actions/git-import.ts +486 -0
  249. package/src/server/skill-hub/mcp/McpController.ts +86 -0
  250. package/src/server/skill-hub/plugin.ts +771 -0
  251. package/src/server/skill-hub/sandbox-config.json +6 -0
  252. package/src/server/skill-hub/tasks/SkillExecutionTask.ts +443 -0
  253. package/src/server/skill-hub/utils/json-fields.ts +57 -0
  254. package/src/server/tools/delegate-task.ts +803 -127
  255. package/src/server/tools/skill-execute.ts +157 -0
@@ -0,0 +1,456 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import { Modal, Form, Input, Select, InputNumber, Switch, message, Upload, Radio, Button, Space, theme } from 'antd';
3
+ import { InboxOutlined, CloseOutlined, SaveOutlined } from '@ant-design/icons';
4
+ import { useAPIClient } from '@nocobase/client';
5
+ import { useT } from '../locale';
6
+ import { formatJsonText, stringifyJsonText, parseJsonText } from '../utils/jsonFields';
7
+
8
+ const { TextArea } = Input;
9
+ const { useToken } = theme;
10
+
11
+ interface SkillEditorProps {
12
+ skill: any | null;
13
+ onClose: (saved?: boolean) => void;
14
+ }
15
+
16
+ export const SkillEditor: React.FC<SkillEditorProps> = ({ skill, onClose }) => {
17
+ const api = useAPIClient();
18
+ const t = useT();
19
+ const { token } = useToken();
20
+ const [form] = Form.useForm();
21
+ const isEditing = !!skill;
22
+ const [templates, setTemplates] = useState<any[]>([]);
23
+
24
+ useEffect(() => {
25
+ if (!isEditing) {
26
+ api
27
+ .request({ url: 'skillHub:listTemplates' })
28
+ .then(({ data }) => {
29
+ const responseData = data?.data?.data || data?.data || data;
30
+ let t = responseData;
31
+ if (t && t.data && Array.isArray(t.data)) t = t.data;
32
+ setTemplates(Array.isArray(t) ? t : []);
33
+ })
34
+ .catch(() => {
35
+ setTemplates([]);
36
+ });
37
+ }
38
+ }, [api, isEditing]);
39
+
40
+ useEffect(() => {
41
+ if (skill) {
42
+ form.setFieldsValue({
43
+ ...skill,
44
+ inputSchema: formatJsonText(skill.inputSchema, null),
45
+ interactionSchema: formatJsonText(skill.interactionSchema, null),
46
+ packages: formatJsonText(skill.packages, []),
47
+ });
48
+ } else {
49
+ form.resetFields();
50
+ form.setFieldsValue({
51
+ storageType: 'database',
52
+ language: 'python',
53
+ timeoutSeconds: 60,
54
+ maxOutputSizeMb: 50,
55
+ enabled: true,
56
+ toolScope: 'CUSTOM',
57
+ autoCall: false,
58
+ packages: '[]',
59
+ });
60
+ }
61
+ }, [skill, form]);
62
+
63
+ const storageType = Form.useWatch('storageType', form) || 'database';
64
+
65
+ // Overwrite local UI for plugin binding
66
+ useEffect(() => {
67
+ if (storageType === 'plugin') {
68
+ const pSource = form.getFieldValue('pluginSource');
69
+ if (pSource) {
70
+ const tmpl = templates.find((t) => t.name === pSource);
71
+ if (tmpl) {
72
+ form.setFieldsValue({
73
+ name: tmpl.name,
74
+ title: tmpl.title,
75
+ description: tmpl.description,
76
+ language: tmpl.language,
77
+ instructions: tmpl.instructions || '',
78
+ inputSchema: formatJsonText(tmpl.inputSchema, null),
79
+ interactionSchema: formatJsonText(tmpl.interactionSchema, null),
80
+ packages: formatJsonText(tmpl.packages, []),
81
+ timeoutSeconds: tmpl.timeoutSeconds || 60,
82
+ maxOutputSizeMb: tmpl.maxOutputSizeMb || 50,
83
+ toolScope: tmpl.toolScope || 'CUSTOM',
84
+ storageUrl: tmpl.storageUrl,
85
+ });
86
+ }
87
+ }
88
+ }
89
+ }, [storageType, templates, form]);
90
+
91
+ const handleTemplateSelect = (templateName: string) => {
92
+ const tmpl = templates.find((t) => t.name === templateName);
93
+ if (!tmpl) return;
94
+
95
+ if (storageType === 'plugin') {
96
+ form.setFieldsValue({
97
+ name: tmpl.name,
98
+ title: tmpl.title,
99
+ description: tmpl.description || '',
100
+ language: tmpl.language || 'python',
101
+ instructions: tmpl.instructions || '',
102
+ inputSchema: formatJsonText(tmpl.inputSchema, null),
103
+ interactionSchema: formatJsonText(tmpl.interactionSchema, null),
104
+ packages: formatJsonText(tmpl.packages, []),
105
+ timeoutSeconds: tmpl.timeoutSeconds || 60,
106
+ maxOutputSizeMb: tmpl.maxOutputSizeMb || 50,
107
+ toolScope: tmpl.toolScope || 'CUSTOM',
108
+ storageUrl: tmpl.storageUrl,
109
+ });
110
+ } else {
111
+ form.setFieldsValue({
112
+ name: tmpl.name,
113
+ title: tmpl.title,
114
+ description: tmpl.description || '',
115
+ instructions: tmpl.instructions || '',
116
+ language: tmpl.language || 'python',
117
+ codeTemplate: tmpl.codeTemplate || '',
118
+ inputSchema: formatJsonText(tmpl.inputSchema, null),
119
+ interactionSchema: formatJsonText(tmpl.interactionSchema, null),
120
+ packages: formatJsonText(tmpl.packages, []),
121
+ timeoutSeconds: tmpl.timeoutSeconds || 60,
122
+ maxOutputSizeMb: tmpl.maxOutputSizeMb || 50,
123
+ toolScope: tmpl.toolScope || 'CUSTOM',
124
+ enabled: tmpl.enabled ?? true,
125
+ });
126
+ }
127
+ message.success(t('Template applied'));
128
+ };
129
+
130
+ const handleSave = async () => {
131
+ try {
132
+ const values = await form.validateFields();
133
+
134
+ // Parse JSON fields
135
+ try {
136
+ if (values.inputSchema) JSON.parse(values.inputSchema);
137
+ } catch {
138
+ message.error(t('Invalid JSON in Input Schema'));
139
+ return;
140
+ }
141
+
142
+ try {
143
+ if (values.interactionSchema) JSON.parse(values.interactionSchema);
144
+ } catch {
145
+ message.error(t('Invalid JSON in Interaction Schema'));
146
+ return;
147
+ }
148
+
149
+ try {
150
+ if (values.packages) JSON.parse(values.packages);
151
+ } catch {
152
+ message.error(t('Invalid JSON in Packages'));
153
+ return;
154
+ }
155
+
156
+ const data = {
157
+ ...values,
158
+ inputSchema: values.inputSchema ? stringifyJsonText(values.inputSchema) : null,
159
+ interactionSchema: values.interactionSchema ? stringifyJsonText(values.interactionSchema) : null,
160
+ packages: stringifyJsonText(values.packages || [], []),
161
+ };
162
+
163
+ if (isEditing) {
164
+ await api.request({
165
+ url: 'skillDefinitions:update',
166
+ method: 'POST',
167
+ params: { filterByTk: skill.id },
168
+ data,
169
+ });
170
+ } else {
171
+ await api.request({
172
+ url: 'skillDefinitions:create',
173
+ method: 'POST',
174
+ data,
175
+ });
176
+ }
177
+
178
+ message.success(t(isEditing ? 'Skill updated' : 'Skill created'));
179
+ onClose(true);
180
+ } catch (err: any) {
181
+ if (err?.errorFields) return; // Form validation error
182
+ message.error(t('Failed to save skill'));
183
+ }
184
+ };
185
+
186
+ return (
187
+ <Modal
188
+ open
189
+ title={isEditing ? t('Edit Skill') : t('New Skill')}
190
+ onCancel={() => onClose()}
191
+ width={720}
192
+ destroyOnClose
193
+ footer={null}
194
+ styles={{
195
+ body: { padding: 0, display: 'flex', flexDirection: 'column', maxHeight: 'calc(100vh - 120px)' },
196
+ }}
197
+ style={{ top: 40 }}
198
+ >
199
+ <Form
200
+ form={form}
201
+ layout="vertical"
202
+ size="middle"
203
+ component="div"
204
+ style={{ display: 'flex', flexDirection: 'column', maxHeight: 'calc(100vh - 120px)' }}
205
+ >
206
+ <Form.Item name="storageUrl" hidden>
207
+ <Input />
208
+ </Form.Item>
209
+
210
+ {/* ─── Fixed Header Action Bar ─── */}
211
+ <div
212
+ style={{
213
+ flexShrink: 0,
214
+ background: token.colorBgContainer,
215
+ borderBottom: `1px solid ${token.colorBorderSecondary}`,
216
+ padding: '12px 24px',
217
+ display: 'flex',
218
+ alignItems: 'center',
219
+ justifyContent: 'space-between',
220
+ flexWrap: 'wrap',
221
+ gap: 12,
222
+ }}
223
+ >
224
+ {/* Left: Skill Data Source */}
225
+ <Form.Item name="storageType" noStyle>
226
+ <Radio.Group optionType="button" buttonStyle="solid" size="small">
227
+ <Radio value="database">{t('Database Editor')}</Radio>
228
+ <Radio value="local">{t('ZIP Package')}</Radio>
229
+ <Radio value="plugin" disabled={!Array.isArray(templates) || templates.length === 0}>
230
+ {t('Bind to Plugin')}
231
+ </Radio>
232
+ </Radio.Group>
233
+ </Form.Item>
234
+
235
+ {/* Center: Toggles */}
236
+ <Space size={16}>
237
+ <Space size={4}>
238
+ <span style={{ fontSize: 12, color: token.colorTextSecondary }}>{t('Enabled')}</span>
239
+ <Form.Item name="enabled" valuePropName="checked" noStyle>
240
+ <Switch size="small" />
241
+ </Form.Item>
242
+ </Space>
243
+ <Space size={4}>
244
+ <span style={{ fontSize: 12, color: token.colorTextSecondary }}>{t('Auto Call')}</span>
245
+ <Form.Item name="autoCall" valuePropName="checked" noStyle>
246
+ <Switch size="small" />
247
+ </Form.Item>
248
+ </Space>
249
+ </Space>
250
+
251
+ {/* Right: Buttons */}
252
+ <Space>
253
+ <Button size="small" icon={<CloseOutlined />} onClick={() => onClose()}>
254
+ {t('Cancel')}
255
+ </Button>
256
+ <Button type="primary" size="small" icon={<SaveOutlined />} onClick={handleSave}>
257
+ {isEditing ? t('Save') : t('Create')}
258
+ </Button>
259
+ </Space>
260
+ </div>
261
+
262
+ {/* ─── Scrollable Body Content ─── */}
263
+ <div
264
+ style={{
265
+ flex: 1,
266
+ overflowY: 'auto',
267
+ padding: '16px 24px 24px',
268
+ minHeight: 0,
269
+ }}
270
+ >
271
+ {storageType === 'database' && !isEditing && Array.isArray(templates) && templates.length > 0 && (
272
+ <Form.Item label={t('Import Template to Pre-fill code (Optional)')} style={{ marginBottom: 24 }}>
273
+ <Select placeholder={t('Select a template to pre-fill')} onChange={handleTemplateSelect} allowClear>
274
+ {templates.map((tmpl) => (
275
+ <Select.Option key={tmpl.name} value={tmpl.name}>
276
+ {tmpl.title} ({tmpl.pluginSource || tmpl.name})
277
+ </Select.Option>
278
+ ))}
279
+ </Select>
280
+ </Form.Item>
281
+ )}
282
+
283
+ {storageType === 'plugin' && (
284
+ <>
285
+ <Form.Item name="inputSchema" hidden>
286
+ <TextArea />
287
+ </Form.Item>
288
+ <Form.Item name="packages" hidden>
289
+ <Input />
290
+ </Form.Item>
291
+ <Form.Item
292
+ name="pluginSource"
293
+ label={t('Select Plugin Skill')}
294
+ rules={[{ required: true }]}
295
+ style={{
296
+ marginBottom: 24,
297
+ padding: 12,
298
+ background: '#e6f4ff',
299
+ borderRadius: 8,
300
+ border: '1px solid #91caff',
301
+ }}
302
+ extra={
303
+ <div style={{ fontSize: 12, color: '#1677ff', marginTop: 8 }}>
304
+ {t(
305
+ 'Binding dynamically delegates execution to the plugin logic. Code, Language, and Schemas are managed externally.',
306
+ )}
307
+ </div>
308
+ }
309
+ >
310
+ <Select
311
+ placeholder={t('Choose an enabled plugin skill to attach')}
312
+ onChange={handleTemplateSelect}
313
+ allowClear
314
+ >
315
+ {Array.isArray(templates) &&
316
+ templates.map((tmpl) => (
317
+ <Select.Option key={tmpl.name} value={tmpl.name}>
318
+ {tmpl.title} ({tmpl.pluginSource || tmpl.name})
319
+ </Select.Option>
320
+ ))}
321
+ </Select>
322
+ </Form.Item>
323
+ </>
324
+ )}
325
+
326
+ <Form.Item name="name" label={t('Name (Internal Identifier)')} rules={[{ required: true }]}>
327
+ <Input placeholder="generate-word-report" disabled={isEditing || storageType === 'plugin'} />
328
+ </Form.Item>
329
+
330
+ <Form.Item name="title" label={t('Title')} rules={[{ required: true }]}>
331
+ <Input placeholder="Generate Word Report" disabled={storageType === 'plugin'} />
332
+ </Form.Item>
333
+
334
+ <Form.Item name="description" label={t('Description')}>
335
+ <TextArea
336
+ rows={2}
337
+ placeholder="Description for AI employee to understand this skill"
338
+ disabled={storageType === 'plugin'}
339
+ />
340
+ </Form.Item>
341
+
342
+ <Form.Item name="instructions" label={t('Instructions / Documentation')}>
343
+ <TextArea
344
+ rows={6}
345
+ placeholder="Detailed instructions or markdown documentation for this skill"
346
+ disabled={storageType === 'plugin'}
347
+ />
348
+ </Form.Item>
349
+
350
+ {storageType === 'local' && (
351
+ <Form.Item
352
+ label={t('Skill Package ZIP')}
353
+ name="fileId"
354
+ valuePropName="fileId"
355
+ getValueFromEvent={(e: any) =>
356
+ e?.file?.response?.data?.id || e?.fileList?.[0]?.response?.data?.id || undefined
357
+ }
358
+ rules={[{ required: true }]}
359
+ >
360
+ <Upload.Dragger
361
+ name="file"
362
+ action="/api/attachments:create"
363
+ headers={{ Authorization: `Bearer ${api.auth.getToken()}` }}
364
+ maxCount={1}
365
+ accept=".zip"
366
+ >
367
+ <p className="ant-upload-drag-icon">
368
+ <InboxOutlined />
369
+ </p>
370
+ <p className="ant-upload-text">{t('Click or drag ZIP file to this area to upload')}</p>
371
+ <p className="ant-upload-hint">
372
+ {t(
373
+ 'Upload a skill package zip containing SKILL.md and index.py/.js. Metadata will be extracted automatically.',
374
+ )}
375
+ </p>
376
+ </Upload.Dragger>
377
+ </Form.Item>
378
+ )}
379
+
380
+ {storageType !== 'plugin' && (
381
+ <Form.Item name="language" label={t('Language')}>
382
+ <Select>
383
+ <Select.Option value="python">Python</Select.Option>
384
+ <Select.Option value="node">Node.js</Select.Option>
385
+ </Select>
386
+ </Form.Item>
387
+ )}
388
+
389
+ {storageType === 'database' && (
390
+ <Form.Item
391
+ name="codeTemplate"
392
+ label={t('Code Template')}
393
+ extra={t('Use {{placeholder}} for input parameters. Use OUTPUT_DIR env var for output directory.')}
394
+ >
395
+ <TextArea
396
+ rows={12}
397
+ style={{ fontFamily: 'monospace', fontSize: 13 }}
398
+ placeholder={'import os\n\noutput_dir = os.environ.get("OUTPUT_DIR", "/output")\n# Your code here'}
399
+ />
400
+ </Form.Item>
401
+ )}
402
+
403
+ {storageType !== 'plugin' && (
404
+ <Form.Item
405
+ name="inputSchema"
406
+ label={t('Input Schema (JSON)')}
407
+ extra={t('JSON Schema defining input parameters for this skill')}
408
+ >
409
+ <TextArea
410
+ rows={6}
411
+ style={{ fontFamily: 'monospace', fontSize: 13 }}
412
+ placeholder={'{\n "type": "object",\n "properties": {},\n "required": []\n}'}
413
+ />
414
+ </Form.Item>
415
+ )}
416
+
417
+ <Form.Item
418
+ name="interactionSchema"
419
+ label={t('Interaction Schema (optional)')}
420
+ extra={t('If set, user is prompted to fill / confirm input before execution. Type: form | select | confirm.')}
421
+ >
422
+ <TextArea
423
+ rows={6}
424
+ style={{ fontFamily: 'monospace', fontSize: 13 }}
425
+ placeholder={'{\n "type": "form",\n "prompt": "Confirm parameters",\n "fields": {\n "fileName": { "type": "string", "title": "File name", "required": true }\n }\n}'}
426
+ />
427
+ </Form.Item>
428
+
429
+ {storageType !== 'plugin' && (
430
+ <Form.Item name="packages" label={t('Packages (JSON array)')}>
431
+ <Input placeholder='["python-docx", "openpyxl"]' style={{ fontFamily: 'monospace' }} />
432
+ </Form.Item>
433
+ )}
434
+
435
+ <div style={{ display: 'flex', gap: 16 }}>
436
+ <Form.Item name="timeoutSeconds" label={t('Timeout (seconds)')} style={{ flex: 1 }}>
437
+ <InputNumber min={5} max={300} style={{ width: '100%' }} />
438
+ </Form.Item>
439
+
440
+ <Form.Item name="maxOutputSizeMb" label={t('Max Output (MB)')} style={{ flex: 1 }}>
441
+ <InputNumber min={1} max={200} style={{ width: '100%' }} />
442
+ </Form.Item>
443
+
444
+ <Form.Item name="toolScope" label={t('Tool Scope')} style={{ flex: 1 }}>
445
+ <Select>
446
+ <Select.Option value="CUSTOM">CUSTOM</Select.Option>
447
+ <Select.Option value="GENERAL">GENERAL</Select.Option>
448
+ <Select.Option value="SPECIFIED">SPECIFIED</Select.Option>
449
+ </Select>
450
+ </Form.Item>
451
+ </div>
452
+ </div>
453
+ </Form>
454
+ </Modal>
455
+ );
456
+ };
@@ -0,0 +1,181 @@
1
+ import React, { useState, useEffect, useCallback } from 'react';
2
+ import {
3
+ Card,
4
+ Button,
5
+ Space,
6
+ Modal,
7
+ Form,
8
+ Input,
9
+ Select,
10
+ Switch,
11
+ InputNumber,
12
+ message,
13
+ Popconfirm,
14
+ Tag,
15
+ List,
16
+ Typography,
17
+ Tooltip,
18
+ } from 'antd';
19
+ import { PlusOutlined, EditOutlined, DeleteOutlined, PlayCircleOutlined, BranchesOutlined } from '@ant-design/icons';
20
+ import { useAPIClient } from '@nocobase/client';
21
+ import { useT } from '../locale';
22
+ import { SkillEditor } from './SkillEditor';
23
+ import { SkillTestPanel } from './SkillTestPanel';
24
+ import { GitSkillImport } from './GitSkillImport';
25
+
26
+ const { TextArea } = Input;
27
+
28
+ export const SkillManager: React.FC = () => {
29
+ const api = useAPIClient();
30
+ const t = useT();
31
+ const [skills, setSkills] = useState<any[]>([]);
32
+ const [loading, setLoading] = useState(false);
33
+ const [editorVisible, setEditorVisible] = useState(false);
34
+ const [testVisible, setTestVisible] = useState(false);
35
+ const [editingSkill, setEditingSkill] = useState<any>(null);
36
+ const [testingSkill, setTestingSkill] = useState<any>(null);
37
+ const [gitImportVisible, setGitImportVisible] = useState(false);
38
+
39
+ const fetchSkills = useCallback(async () => {
40
+ setLoading(true);
41
+ try {
42
+ const { data } = await api.request({ url: 'skillDefinitions:list', params: { pageSize: 100 } });
43
+ const rawData = data?.data?.data ?? data?.data ?? [];
44
+ setSkills(Array.isArray(rawData) ? rawData : []);
45
+ } catch {
46
+ message.error(t('Failed to load skills'));
47
+ } finally {
48
+ setLoading(false);
49
+ }
50
+ }, [api, t]);
51
+
52
+ useEffect(() => {
53
+ fetchSkills();
54
+ }, [fetchSkills]);
55
+
56
+ const handleCreate = () => {
57
+ setEditingSkill(null);
58
+ setEditorVisible(true);
59
+ };
60
+
61
+ const handleEdit = (record: any) => {
62
+ setEditingSkill(record);
63
+ setEditorVisible(true);
64
+ };
65
+
66
+ const handleTest = (record: any) => {
67
+ setTestingSkill(record);
68
+ setTestVisible(true);
69
+ };
70
+
71
+ const handleDelete = async (id: number) => {
72
+ try {
73
+ await api.request({ url: 'skillDefinitions:destroy', method: 'POST', params: { filterByTk: id } });
74
+ message.success(t('Deleted'));
75
+ fetchSkills();
76
+ } catch {
77
+ message.error(t('Failed to delete'));
78
+ }
79
+ };
80
+
81
+ const handleToggleEnabled = async (record: any) => {
82
+ try {
83
+ await api.request({
84
+ url: 'skillDefinitions:update',
85
+ method: 'POST',
86
+ params: { filterByTk: record.id },
87
+ data: { enabled: !record.enabled },
88
+ });
89
+ fetchSkills();
90
+ } catch {
91
+ message.error(t('Failed to update'));
92
+ }
93
+ };
94
+
95
+ const handleEditorClose = (saved?: boolean) => {
96
+ setEditorVisible(false);
97
+ setEditingSkill(null);
98
+ if (saved) fetchSkills();
99
+ };
100
+
101
+ // Table columns definition removed in favor of List rendering
102
+
103
+ return (
104
+ <Card
105
+ title={t('Skill Definitions')}
106
+ extra={
107
+ <Space>
108
+ <Button icon={<BranchesOutlined />} onClick={() => setGitImportVisible(true)}>
109
+ {t('Import from Git')}
110
+ </Button>
111
+ <Button type="primary" icon={<PlusOutlined />} onClick={handleCreate}>
112
+ {t('New Skill')}
113
+ </Button>
114
+ </Space>
115
+ }
116
+ >
117
+ <List
118
+ grid={{ gutter: 16, xs: 1, sm: 2, md: 3, lg: 3, xl: 4, xxl: 4 }}
119
+ dataSource={skills}
120
+ loading={loading}
121
+ renderItem={(skill) => (
122
+ <List.Item>
123
+ <Card
124
+ size="small"
125
+ title={<Typography.Text ellipsis title={skill.title}>{skill.title}</Typography.Text>}
126
+ extra={<Tag color={skill.language === 'python' ? 'blue' : 'green'}>{skill.language}</Tag>}
127
+ actions={[
128
+ <Tooltip title={t('Test')}>
129
+ <PlayCircleOutlined key="test" onClick={() => handleTest(skill)} />
130
+ </Tooltip>,
131
+ <Tooltip title={t('Edit')}>
132
+ <EditOutlined key="edit" onClick={() => handleEdit(skill)} />
133
+ </Tooltip>,
134
+ <Popconfirm title={t('Delete?')} onConfirm={() => handleDelete(skill.id)}>
135
+ <Tooltip title={t('Delete')}>
136
+ <DeleteOutlined key="delete" style={{ color: 'red' }} />
137
+ </Tooltip>
138
+ </Popconfirm>,
139
+ ]}
140
+ style={{ boxShadow: '0 2px 8px rgba(0,0,0,0.05)', borderRadius: 8 }}
141
+ >
142
+ <Card.Meta
143
+ title={<Typography.Text type="secondary" style={{ fontSize: 13 }}>{skill.name}</Typography.Text>}
144
+ description={
145
+ <div style={{ height: 60, overflow: 'hidden', display: '-webkit-box', WebkitLineClamp: 3, WebkitBoxOrient: 'vertical', fontSize: 13 }}>
146
+ {skill.description || t('No description')}
147
+ </div>
148
+ }
149
+ />
150
+ <div style={{ marginTop: 16, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
151
+ <Space size={4}>
152
+ <Switch checked={skill.enabled} onChange={() => handleToggleEnabled(skill)} size="small" />
153
+ <span style={{ fontSize: 12 }}>{skill.enabled ? t('Enabled') : t('Disabled')}</span>
154
+ </Space>
155
+ <Tag color="purple" style={{ margin: 0, fontSize: 11 }}>
156
+ {skill.storageType ? skill.storageType.toUpperCase() : 'DB'}
157
+ </Tag>
158
+ </div>
159
+ </Card>
160
+ </List.Item>
161
+ )}
162
+ />
163
+
164
+ {editorVisible && (
165
+ <SkillEditor skill={editingSkill} onClose={handleEditorClose} />
166
+ )}
167
+
168
+ {testVisible && testingSkill && (
169
+ <SkillTestPanel skill={testingSkill} onClose={() => setTestVisible(false)} />
170
+ )}
171
+
172
+ <GitSkillImport
173
+ open={gitImportVisible}
174
+ onClose={(synced) => {
175
+ setGitImportVisible(false);
176
+ if (synced) fetchSkills();
177
+ }}
178
+ />
179
+ </Card>
180
+ );
181
+ };