plugin-agent-orchestrator 1.0.6 → 1.0.14

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 (257) 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.js +16 -0
  153. package/dist/server/collections/orchestrator-logs.js +19 -2
  154. package/dist/server/collections/skill-definitions.d.ts +3 -0
  155. package/dist/server/collections/skill-definitions.js +158 -0
  156. package/dist/server/collections/skill-executions.d.ts +3 -0
  157. package/dist/server/collections/skill-executions.js +123 -0
  158. package/dist/server/collections/skill-worker-configs.d.ts +3 -0
  159. package/dist/server/collections/skill-worker-configs.js +115 -0
  160. package/dist/server/migrations/20260423000000-add-progress-fields.d.ts +4 -0
  161. package/dist/server/migrations/20260423000000-add-progress-fields.js +69 -0
  162. package/dist/server/migrations/20260425000000-add-interaction-schema.d.ts +4 -0
  163. package/dist/server/migrations/20260425000000-add-interaction-schema.js +61 -0
  164. package/dist/server/migrations/20260427000000-add-tracing-detail-fields.d.ts +7 -0
  165. package/dist/server/migrations/20260427000000-add-tracing-detail-fields.js +62 -0
  166. package/dist/server/migrations/20260427000000-change-packages-to-text.d.ts +4 -0
  167. package/dist/server/migrations/20260427000000-change-packages-to-text.js +70 -0
  168. package/dist/server/migrations/20260427000001-change-other-json-to-text.d.ts +4 -0
  169. package/dist/server/migrations/20260427000001-change-other-json-to-text.js +80 -0
  170. package/dist/server/migrations/20260429000000-add-llm-fields.d.ts +7 -0
  171. package/dist/server/migrations/20260429000000-add-llm-fields.js +68 -0
  172. package/dist/server/migrations/20260429000000-fix-inputargs-json-to-text.d.ts +16 -0
  173. package/dist/server/migrations/20260429000000-fix-inputargs-json-to-text.js +51 -0
  174. package/dist/server/migrations/20260503000000-add-orchestrator-trace-fields.d.ts +7 -0
  175. package/dist/server/migrations/20260503000000-add-orchestrator-trace-fields.js +57 -0
  176. package/dist/server/plugin.d.ts +3 -0
  177. package/dist/server/plugin.js +37 -1
  178. package/dist/server/resources/tracing.js +160 -12
  179. package/dist/server/services/CodeValidator.d.ts +32 -0
  180. package/dist/server/services/CodeValidator.js +205 -0
  181. package/dist/server/services/ExecutionSpanService.d.ts +44 -0
  182. package/dist/server/services/ExecutionSpanService.js +104 -0
  183. package/dist/server/services/FileManager.d.ts +28 -0
  184. package/dist/server/services/FileManager.js +151 -0
  185. package/dist/server/services/SandboxRunner.d.ts +41 -0
  186. package/dist/server/services/SandboxRunner.js +167 -0
  187. package/dist/server/services/SkillManager.d.ts +6 -0
  188. package/dist/server/services/SkillManager.js +640 -0
  189. package/dist/server/services/SkillRepositoryService.d.ts +22 -0
  190. package/dist/server/services/SkillRepositoryService.js +157 -0
  191. package/dist/server/services/WorkerEnvManager.d.ts +26 -0
  192. package/dist/server/services/WorkerEnvManager.js +120 -0
  193. package/dist/server/skill-hub/actions/git-import.d.ts +21 -0
  194. package/dist/server/skill-hub/actions/git-import.js +413 -0
  195. package/dist/server/skill-hub/mcp/McpController.d.ts +15 -0
  196. package/dist/server/skill-hub/mcp/McpController.js +111 -0
  197. package/dist/server/skill-hub/plugin.d.ts +58 -0
  198. package/dist/server/skill-hub/plugin.js +694 -0
  199. package/dist/server/skill-hub/sandbox-config.json +6 -0
  200. package/dist/server/skill-hub/tasks/SkillExecutionTask.d.ts +14 -0
  201. package/dist/server/skill-hub/tasks/SkillExecutionTask.js +267 -0
  202. package/dist/server/skill-hub/utils/json-fields.d.ts +7 -0
  203. package/dist/server/skill-hub/utils/json-fields.js +88 -0
  204. package/dist/server/tools/delegate-task.d.ts +4 -0
  205. package/dist/server/tools/delegate-task.js +832 -119
  206. package/dist/server/tools/skill-execute.d.ts +36 -0
  207. package/dist/server/tools/skill-execute.js +167 -0
  208. package/package.json +3 -1
  209. package/src/client/AIEmployeeSelect.tsx +1 -3
  210. package/src/client/AIEmployeesContext.tsx +28 -13
  211. package/src/client/OrchestratorSettings.tsx +43 -5
  212. package/src/client/RulesTab.tsx +368 -21
  213. package/src/client/TracingTab.tsx +316 -102
  214. package/src/client/plugin.tsx +39 -0
  215. package/src/client/skill-hub/components/ExecutionHistory.tsx +201 -0
  216. package/src/client/skill-hub/components/ExecutionProgress.tsx +55 -0
  217. package/src/client/skill-hub/components/GitSkillImport.tsx +555 -0
  218. package/src/client/skill-hub/components/SkillEditor.tsx +456 -0
  219. package/src/client/skill-hub/components/SkillManager.tsx +181 -0
  220. package/src/client/skill-hub/components/SkillMetrics.tsx +124 -0
  221. package/src/client/skill-hub/components/SkillTestPanel.tsx +144 -0
  222. package/src/client/skill-hub/index.tsx +75 -0
  223. package/src/client/skill-hub/locale.ts +16 -0
  224. package/src/client/skill-hub/tools/InteractionSchemasProvider.tsx +59 -0
  225. package/src/client/skill-hub/tools/SkillHubCard.tsx +78 -0
  226. package/src/client/skill-hub/utils/jsonFields.ts +37 -0
  227. package/src/server/collections/agent-execution-spans.ts +129 -0
  228. package/src/server/collections/orchestrator-config.ts +17 -0
  229. package/src/server/collections/orchestrator-logs.ts +19 -2
  230. package/src/server/collections/skill-definitions.ts +128 -0
  231. package/src/server/collections/skill-executions.ts +94 -0
  232. package/src/server/collections/skill-worker-configs.ts +86 -0
  233. package/src/server/migrations/20260423000000-add-progress-fields.ts +50 -0
  234. package/src/server/migrations/20260425000000-add-interaction-schema.ts +35 -0
  235. package/src/server/migrations/20260427000000-add-tracing-detail-fields.ts +41 -0
  236. package/src/server/migrations/20260427000000-change-packages-to-text.ts +47 -0
  237. package/src/server/migrations/20260427000001-change-other-json-to-text.ts +57 -0
  238. package/src/server/migrations/20260429000000-add-llm-fields.ts +46 -0
  239. package/src/server/migrations/20260429000000-fix-inputargs-json-to-text.ts +38 -0
  240. package/src/server/migrations/20260503000000-add-orchestrator-trace-fields.ts +32 -0
  241. package/src/server/plugin.ts +51 -3
  242. package/src/server/resources/tracing.ts +187 -16
  243. package/src/server/services/CodeValidator.ts +159 -0
  244. package/src/server/services/ExecutionSpanService.ts +106 -0
  245. package/src/server/services/FileManager.ts +144 -0
  246. package/src/server/services/SandboxRunner.ts +205 -0
  247. package/src/server/services/SkillManager.ts +623 -0
  248. package/src/server/services/SkillRepositoryService.ts +142 -0
  249. package/src/server/services/WorkerEnvManager.ts +113 -0
  250. package/src/server/skill-hub/actions/git-import.ts +486 -0
  251. package/src/server/skill-hub/mcp/McpController.ts +86 -0
  252. package/src/server/skill-hub/plugin.ts +771 -0
  253. package/src/server/skill-hub/sandbox-config.json +6 -0
  254. package/src/server/skill-hub/tasks/SkillExecutionTask.ts +297 -0
  255. package/src/server/skill-hub/utils/json-fields.ts +57 -0
  256. package/src/server/tools/delegate-task.ts +1085 -147
  257. package/src/server/tools/skill-execute.ts +157 -0
@@ -0,0 +1,486 @@
1
+ import { Context } from '@nocobase/actions';
2
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
3
+ import * as path from 'path';
4
+ import { parseJsonText, stringifyJsonText, parseJsonLike, parseSkillMarkdown } from '../utils/json-fields';
5
+
6
+ type SkillManifestEntry = Record<string, any> & {
7
+ folder?: string;
8
+ name?: string;
9
+ title?: string;
10
+ description?: string;
11
+ language?: string;
12
+ storageType?: string;
13
+ pluginSource?: string;
14
+ codeTemplate?: string;
15
+ codeFile?: string;
16
+ };
17
+
18
+ type SkillManifest = {
19
+ name?: string;
20
+ description?: string;
21
+ skills?: SkillManifestEntry[];
22
+ initializedAt?: string;
23
+ };
24
+
25
+ const CODE_FILES = [
26
+ ['index.py', 'python'],
27
+ ['index.js', 'node'],
28
+ ['main.py', 'python'],
29
+ ] as const;
30
+
31
+ /**
32
+ * Git integration actions for skill-hub.
33
+ *
34
+ * Supported manifest shape:
35
+ * {
36
+ * "skills": [
37
+ * { "folder": "my-skill", "name": "my-skill", "language": "python" },
38
+ * { "name": "pptx-advanced-export", "storageType": "plugin", "pluginSource": "pptx-advanced-export" }
39
+ * ]
40
+ * }
41
+ */
42
+ export async function gitListSkills(ctx: Context, next: () => Promise<void>) {
43
+ const { repositoryId, ref = 'HEAD', prefix = '' } = ctx.action.params;
44
+ const rootFolder = normalizeRootFolder(ctx.action.params.rootFolder);
45
+
46
+ if (!repositoryId) {
47
+ ctx.throw(400, 'repositoryId and rootFolder are required');
48
+ }
49
+
50
+ const gitPlugin = ctx.app.pm.get('plugin-git-manager') as any;
51
+ if (!gitPlugin) {
52
+ ctx.throw(400, 'plugin-git-manager is not installed');
53
+ }
54
+
55
+ try {
56
+ const repo = await ctx.db.getRepository('gitRepositories').findOne({ filterByTk: repositoryId });
57
+ if (!repo) ctx.throw(404, 'Repository not found');
58
+
59
+ const simpleGit = require('simple-git').default;
60
+ const localPath = getLocalPath(repo.get('localPath'));
61
+ const git = simpleGit(localPath);
62
+ const configPath = joinGitPath(rootFolder, 'skills.json');
63
+
64
+ const loaded = await loadSkillsManifest(git, ref, localPath, configPath);
65
+ let config = loaded.config;
66
+ let initialized = false;
67
+
68
+ if (!loaded.exists) {
69
+ const discovered = await discoverSkills(git, ref, rootFolder);
70
+ config = createSkillsManifest(rootFolder, discovered);
71
+ initialized = initSkillsManifestFile(localPath, configPath, config);
72
+ }
73
+
74
+ const manifestSkills = Array.isArray(config.skills) ? config.skills.filter((skill) => getSkillKey(skill)) : [];
75
+ const enriched = manifestSkills.map((skill) => enrichListedSkill(skill, prefix));
76
+
77
+ const existingSkills = enriched.length
78
+ ? await ctx.db.getRepository('skillDefinitions').find({
79
+ filter: { name: { $in: enriched.map((s) => s.name) } },
80
+ fields: ['name'],
81
+ })
82
+ : [];
83
+ const existingNames = new Set(existingSkills.map((s: any) => s.get('name')));
84
+
85
+ ctx.body = {
86
+ data: enriched.map((s) => ({
87
+ ...s,
88
+ existsInDb: existingNames.has(s.name),
89
+ })),
90
+ config: {
91
+ name: config.name || rootFolder || 'skills',
92
+ description: config.description || '',
93
+ rootFolder,
94
+ path: configPath,
95
+ initializedSkillsJson: initialized,
96
+ },
97
+ };
98
+ await next();
99
+ } catch (err: any) {
100
+ ctx.throw(400, err.message);
101
+ }
102
+ }
103
+
104
+ /**
105
+ * Sync selected skills from git into skillDefinitions.
106
+ *
107
+ * Code is optional. Regular git skills may provide code via codeTemplate,
108
+ * codeFile, or conventional files under skills/<folder>. Plugin skills only
109
+ * need storageType=plugin and pluginSource.
110
+ */
111
+ export async function gitSyncSkills(ctx: Context, next: () => Promise<void>) {
112
+ const { repositoryId, ref = 'HEAD' } = ctx.action.params;
113
+ const rootFolder = normalizeRootFolder(ctx.action.params.rootFolder);
114
+ const { skills: selectedKeys, overwrite = false, prefix = '' } = ctx.action.params.values || ctx.action.params;
115
+
116
+ if (!repositoryId || !Array.isArray(selectedKeys) || selectedKeys.length === 0) {
117
+ ctx.throw(400, 'repositoryId, rootFolder and skills[] are required');
118
+ }
119
+
120
+ const repo = await ctx.db.getRepository('gitRepositories').findOne({ filterByTk: repositoryId });
121
+ if (!repo) ctx.throw(404, 'Repository not found');
122
+
123
+ const simpleGit = require('simple-git').default;
124
+ const localPath = getLocalPath(repo.get('localPath'));
125
+ const git = simpleGit(localPath);
126
+ const configPath = joinGitPath(rootFolder, 'skills.json');
127
+
128
+ const loaded = await loadSkillsManifest(git, ref, localPath, configPath);
129
+ let config = loaded.config;
130
+ if (!loaded.exists) {
131
+ const discovered = await discoverSkills(git, ref, rootFolder);
132
+ config = createSkillsManifest(rootFolder, discovered);
133
+ initSkillsManifestFile(localPath, configPath, config);
134
+ }
135
+
136
+ const manifest = new Map<string, SkillManifestEntry>();
137
+ for (const entry of config.skills || []) {
138
+ const key = getSkillKey(entry);
139
+ if (key) {
140
+ manifest.set(key, entry);
141
+ }
142
+ }
143
+
144
+ const results: any[] = [];
145
+ const skillRepo = ctx.db.getRepository('skillDefinitions');
146
+
147
+ for (const key of selectedKeys) {
148
+ const meta: SkillManifestEntry = manifest.get(key) || { folder: key, name: key };
149
+ const isPluginSkill = isPluginStorage(meta);
150
+ const rawName = meta.name || meta.pluginSource || meta.folder || key;
151
+ const skillName = `${prefix}${rawName}`;
152
+ const skillsSubDir = meta.folder ? joinGitPath(rootFolder, 'skills', meta.folder) : '';
153
+ const skillBaseDir = skillsSubDir || rootFolder;
154
+
155
+ try {
156
+ let frontmatter: Record<string, any> = {};
157
+ let instructions = '';
158
+
159
+ if (skillBaseDir || !meta.folder) {
160
+ try {
161
+ const skillMd = await git.show([`${ref}:${joinGitPath(skillBaseDir, 'SKILL.md')}`]);
162
+ const parsed = parseSkillMarkdown(skillMd);
163
+ frontmatter = parsed.metadata;
164
+ instructions = parsed.body;
165
+
166
+ const otherMds = await fetchAllMarkdownInFolder(git, ref, skillBaseDir);
167
+ if (otherMds) instructions += otherMds;
168
+ } catch {
169
+ // SKILL.md is optional; manifest data is enough.
170
+ }
171
+ }
172
+
173
+ const storageType = normalizeStorageType(
174
+ frontmatter.storageType || meta.storageType || (isPluginSkill ? 'plugin' : 'git'),
175
+ );
176
+ const pluginSource =
177
+ frontmatter.pluginSource || meta.pluginSource || (storageType === 'plugin' ? rawName : undefined);
178
+
179
+ let detectedLanguage = frontmatter.language || meta.language || 'python';
180
+ let codeTemplate = frontmatter.codeTemplate || meta.codeTemplate || '';
181
+
182
+ if (!codeTemplate && meta.codeFile) {
183
+ codeTemplate = await readOptionalGitFile(git, ref, joinGitPath(skillBaseDir, meta.codeFile));
184
+ }
185
+
186
+ if (!codeTemplate && storageType !== 'plugin') {
187
+ const codeFile = await readConventionalCodeFile(git, ref, skillBaseDir);
188
+ if (codeFile) {
189
+ codeTemplate = codeFile.content;
190
+ detectedLanguage = codeFile.language;
191
+ }
192
+ }
193
+
194
+ const merged: Record<string, any> = {
195
+ name: skillName,
196
+ title: frontmatter.title || meta.title || rawName,
197
+ description: frontmatter.description || meta.description || '',
198
+ language: detectedLanguage,
199
+ storageType,
200
+ storageUrl:
201
+ storageType === 'plugin'
202
+ ? `git://${repositoryId}/${rootFolder || ''}@${ref}#${pluginSource || rawName}`
203
+ : `git://${repositoryId}/${skillsSubDir || rootFolder || ''}@${ref}`,
204
+ timeoutSeconds: parseInteger(frontmatter.timeoutSeconds ?? meta.timeoutSeconds, 60),
205
+ maxOutputSizeMb: parseInteger(frontmatter.maxOutputSizeMb ?? meta.maxOutputSizeMb, 50),
206
+ toolScope: frontmatter.toolScope || meta.toolScope || 'CUSTOM',
207
+ enabled: parseBoolean(frontmatter.enabled ?? meta.enabled, true),
208
+ autoCall: parseBoolean(frontmatter.autoCall ?? meta.autoCall, false),
209
+ packages: stringifyJsonText(parseJsonLike(meta.packages ?? frontmatter.packages, []), []),
210
+ };
211
+
212
+ if (codeTemplate) {
213
+ merged.codeTemplate = codeTemplate;
214
+ }
215
+ if (pluginSource) {
216
+ merged.pluginSource = pluginSource;
217
+ }
218
+ if (instructions) {
219
+ merged.instructions = instructions.trim();
220
+ }
221
+
222
+ const inputSchema = parseJsonLike(frontmatter.inputSchema ?? meta.inputSchema, null);
223
+ if (inputSchema) {
224
+ merged.inputSchema = stringifyJsonText(inputSchema);
225
+ }
226
+
227
+ const interactionSchema = parseJsonLike(frontmatter.interactionSchema ?? meta.interactionSchema, null);
228
+ if (interactionSchema) {
229
+ merged.interactionSchema = stringifyJsonText(interactionSchema);
230
+ }
231
+
232
+ const existing = await skillRepo.findOne({ filter: { name: skillName } });
233
+ if (existing && !overwrite) {
234
+ results.push({ folder: key, name: skillName, status: 'skipped', reason: 'Already exists' });
235
+ continue;
236
+ }
237
+
238
+ if (existing) {
239
+ await skillRepo.update({ filterByTk: existing.get('id'), values: merged });
240
+ results.push({ folder: key, name: skillName, status: 'updated' });
241
+ } else {
242
+ await skillRepo.create({ values: merged });
243
+ results.push({ folder: key, name: skillName, status: 'created' });
244
+ }
245
+ } catch (err: any) {
246
+ results.push({ folder: key, name: skillName, status: 'error', reason: err.message });
247
+ }
248
+ }
249
+
250
+ ctx.body = { data: results };
251
+ await next();
252
+ }
253
+
254
+ async function loadSkillsManifest(git: any, ref: string, localPath: string, configPath: string) {
255
+ let raw: string | null = null;
256
+
257
+ try {
258
+ raw = await git.show([`${ref}:${configPath}`]);
259
+ } catch {
260
+ const filePath = resolveRepoFile(localPath, configPath);
261
+ if (existsSync(filePath)) {
262
+ raw = readFileSync(filePath, 'utf8');
263
+ }
264
+ }
265
+
266
+ if (!raw) {
267
+ return { exists: false, config: {} as SkillManifest };
268
+ }
269
+
270
+ try {
271
+ return { exists: true, config: JSON.parse(raw) as SkillManifest };
272
+ } catch (err: any) {
273
+ throw new Error(`Invalid ${configPath}: ${err.message}`);
274
+ }
275
+ }
276
+
277
+ async function discoverSkills(git: any, ref: string, rootFolder: string): Promise<SkillManifestEntry[]> {
278
+ const folderSkills = await discoverSkillFolders(git, ref, rootFolder);
279
+ if (folderSkills.length > 0) {
280
+ return folderSkills;
281
+ }
282
+
283
+ const pluginSkill = await discoverPluginSkill(git, ref, rootFolder);
284
+ return pluginSkill ? [pluginSkill] : [];
285
+ }
286
+
287
+ async function discoverSkillFolders(git: any, ref: string, rootFolder: string): Promise<SkillManifestEntry[]> {
288
+ const baseDir = joinGitPath(rootFolder, 'skills');
289
+
290
+ try {
291
+ const dirs = await git.raw(['ls-tree', '-d', '--name-only', `${ref}:${baseDir}/`]);
292
+ return dirs
293
+ .trim()
294
+ .split('\n')
295
+ .filter(Boolean)
296
+ .map((folder: string) => ({
297
+ folder,
298
+ name: folder,
299
+ title: folder,
300
+ storageType: 'git',
301
+ }));
302
+ } catch {
303
+ return [];
304
+ }
305
+ }
306
+
307
+ async function discoverPluginSkill(git: any, ref: string, rootFolder: string): Promise<SkillManifestEntry | null> {
308
+ const packageJsonPath = joinGitPath(rootFolder, 'package.json');
309
+ let packageJson: any;
310
+
311
+ try {
312
+ packageJson = JSON.parse(await git.show([`${ref}:${packageJsonPath}`]));
313
+ } catch {
314
+ return null;
315
+ }
316
+
317
+ const definition =
318
+ (await readOptionalGitFile(git, ref, joinGitPath(rootFolder, 'src/server/skill-definition.ts'))) ||
319
+ (await readOptionalGitFile(git, ref, joinGitPath(rootFolder, 'src/server/skill-definition.js')));
320
+ const templateName = definition ? extractStringProperty(definition, 'name') : null;
321
+ const title = definition ? extractStringProperty(definition, 'title') : null;
322
+ const language = definition ? extractStringProperty(definition, 'language') : null;
323
+
324
+ const pluginSource = templateName || packageJson.name;
325
+ if (!pluginSource) {
326
+ return null;
327
+ }
328
+
329
+ return {
330
+ name: pluginSource,
331
+ title: title || packageJson.displayName || packageJson.name || pluginSource,
332
+ description: packageJson.description || '',
333
+ language: language || 'python',
334
+ storageType: 'plugin',
335
+ pluginSource,
336
+ };
337
+ }
338
+
339
+ function createSkillsManifest(rootFolder: string, skills: SkillManifestEntry[]): SkillManifest {
340
+ return {
341
+ name: rootFolder || 'skills',
342
+ description: '',
343
+ initializedAt: new Date().toISOString(),
344
+ skills,
345
+ };
346
+ }
347
+
348
+ function initSkillsManifestFile(localPath: string, configPath: string, config: SkillManifest) {
349
+ const filePath = resolveRepoFile(localPath, configPath);
350
+ if (existsSync(filePath)) {
351
+ return false;
352
+ }
353
+
354
+ mkdirSync(path.dirname(filePath), { recursive: true });
355
+ writeFileSync(filePath, `${JSON.stringify(config, null, 2)}\n`, 'utf8');
356
+ return true;
357
+ }
358
+
359
+ async function readConventionalCodeFile(git: any, ref: string, skillsSubDir: string) {
360
+ for (const [file, language] of CODE_FILES) {
361
+ const content = await readOptionalGitFile(git, ref, joinGitPath(skillsSubDir, file));
362
+ if (content) {
363
+ return { content, language };
364
+ }
365
+ }
366
+ return null;
367
+ }
368
+
369
+ async function readOptionalGitFile(git: any, ref: string, filePath: string): Promise<string> {
370
+ try {
371
+ return await git.show([`${ref}:${filePath}`]);
372
+ } catch {
373
+ return '';
374
+ }
375
+ }
376
+
377
+ function enrichListedSkill(skill: SkillManifestEntry, prefix: string) {
378
+ const rawName = skill.name || skill.pluginSource || skill.folder || '';
379
+ const finalName = `${prefix}${rawName}`;
380
+
381
+ return {
382
+ folder: getSkillKey(skill),
383
+ name: finalName,
384
+ title: skill.title || rawName,
385
+ description: skill.description || '',
386
+ language: skill.language || 'python',
387
+ storageType: normalizeStorageType(skill.storageType || (skill.pluginSource ? 'plugin' : 'git')),
388
+ pluginSource: skill.pluginSource,
389
+ ...(skill.timeoutSeconds ? { timeoutSeconds: skill.timeoutSeconds } : {}),
390
+ ...(skill.maxOutputSizeMb ? { maxOutputSizeMb: skill.maxOutputSizeMb } : {}),
391
+ ...(skill.packages ? { packages: skill.packages } : {}),
392
+ ...(skill.inputSchema ? { inputSchema: skill.inputSchema } : {}),
393
+ ...(skill.toolScope ? { toolScope: skill.toolScope } : {}),
394
+ };
395
+ }
396
+
397
+ function getSkillKey(skill: SkillManifestEntry) {
398
+ return String(skill.folder || skill.name || skill.pluginSource || '').trim();
399
+ }
400
+
401
+ function isPluginStorage(skill: SkillManifestEntry) {
402
+ return normalizeStorageType(skill.storageType) === 'plugin' || !!skill.pluginSource;
403
+ }
404
+
405
+ function normalizeStorageType(storageType: any) {
406
+ const value = typeof storageType === 'string' ? storageType.toLowerCase() : '';
407
+ if (value === 'plugin') return 'plugin';
408
+ if (value === 'local') return 'local';
409
+ if (value === 'database') return 'database';
410
+ return 'git';
411
+ }
412
+
413
+ function parseInteger(value: any, fallback: number) {
414
+ const parsed = parseInt(value, 10);
415
+ return Number.isFinite(parsed) ? parsed : fallback;
416
+ }
417
+
418
+ function parseBoolean(value: any, fallback: boolean) {
419
+ if (value === undefined || value === null || value === '') return fallback;
420
+ if (typeof value === 'boolean') return value;
421
+ if (typeof value === 'string') return !['false', '0', 'no'].includes(value.toLowerCase());
422
+ return Boolean(value);
423
+ }
424
+
425
+
426
+
427
+ function extractStringProperty(source: string, property: string) {
428
+ const match = source.match(new RegExp(`${property}\\s*:\\s*(['"\`])([\\s\\S]*?)\\1`));
429
+ return match ? match[2] : null;
430
+ }
431
+
432
+ function normalizeRootFolder(rootFolder: any) {
433
+ if (rootFolder === undefined || rootFolder === null) {
434
+ throw new Error('repositoryId and rootFolder are required');
435
+ }
436
+
437
+ const normalized = String(rootFolder)
438
+ .replace(/\\/g, '/')
439
+ .replace(/^\/+|\/+$/g, '');
440
+ if (normalized.includes('..') || normalized.includes('\0')) {
441
+ throw new Error('Invalid rootFolder');
442
+ }
443
+ return normalized;
444
+ }
445
+
446
+ function joinGitPath(...parts: Array<string | undefined>) {
447
+ return parts
448
+ .filter((part) => part !== undefined && part !== '')
449
+ .join('/')
450
+ .replace(/\/+/g, '/');
451
+ }
452
+
453
+ function resolveRepoFile(localPath: string, gitPath: string): string {
454
+ const basePath = path.resolve(localPath);
455
+ const resolved = path.resolve(basePath, ...gitPath.split('/').filter(Boolean));
456
+ if (resolved !== basePath && !resolved.startsWith(basePath + path.sep)) {
457
+ throw new Error('Invalid file path');
458
+ }
459
+ return resolved;
460
+ }
461
+
462
+ function getLocalPath(localPath: string): string {
463
+ const basePath = process.env.GIT_REPOS_BASE_PATH || path.join(process.cwd(), 'storage', 'git-repos');
464
+ if (path.isAbsolute(localPath)) return localPath;
465
+ return path.resolve(basePath, localPath);
466
+ }
467
+
468
+ async function fetchAllMarkdownInFolder(git: any, ref: string, folderPath: string): Promise<string> {
469
+ let combined = '';
470
+ try {
471
+ const filesOut = await git.raw(['ls-tree', '-r', '--name-only', `${ref}:${folderPath}/`]);
472
+ const files = filesOut.trim().split('\n').filter(Boolean);
473
+
474
+ for (const file of files) {
475
+ if (file.toLowerCase().endsWith('.md') && file.toUpperCase() !== 'SKILL.md') {
476
+ const content = await readOptionalGitFile(git, ref, joinGitPath(folderPath, file));
477
+ if (content) {
478
+ combined += `\n\n--- Content from ${file} ---\n\n${content}`;
479
+ }
480
+ }
481
+ }
482
+ } catch (err) {}
483
+ return combined;
484
+ }
485
+
486
+
@@ -0,0 +1,86 @@
1
+ import type PluginSkillHubServer from '../plugin';
2
+ import { parseJsonText } from '../utils/json-fields';
3
+
4
+ export class McpController {
5
+ constructor(private plugin: PluginSkillHubServer) {}
6
+
7
+ /**
8
+ * List all enabled skills in standard MCP format.
9
+ * Route: GET /api/skillHub:mcpListTools
10
+ */
11
+ async listTools(ctx: any, next: any) {
12
+ const skills = await this.plugin.db.getRepository('skillDefinitions').find({
13
+ filter: { enabled: true },
14
+ });
15
+
16
+ const tools = await Promise.all(skills.map(async (skill: any) => ({
17
+ name: skill.get('name').toLowerCase().replace(/[^a-z0-9_]/g, '_').replace(/_+/g, '_'),
18
+ description: typeof this.plugin.getSkillDescriptionForAI === 'function'
19
+ ? await this.plugin.getSkillDescriptionForAI(skill)
20
+ : skill.get('description'),
21
+ inputSchema: parseJsonText(skill.get('inputSchema'), null),
22
+ })));
23
+
24
+ ctx.body = {
25
+ tools,
26
+ };
27
+
28
+ await next();
29
+ }
30
+
31
+ /**
32
+ * Execute a skill in standard MCP format.
33
+ * Route: POST /api/skillHub:mcpCallTool
34
+ */
35
+ async callTool(ctx: any, next: any) {
36
+ const { name, arguments: args } = ctx.request.body || {};
37
+
38
+ if (!name) {
39
+ ctx.throw(400, 'Missing tool name');
40
+ }
41
+
42
+ // Try finding the exact skill
43
+ const skills = await this.plugin.db.getRepository('skillDefinitions').find({
44
+ filter: { enabled: true },
45
+ });
46
+
47
+ const skill = skills.find((s: any) =>
48
+ s.get('name').toLowerCase().replace(/[^a-z0-9_]/g, '_').replace(/_+/g, '_') === name
49
+ );
50
+
51
+ if (!skill) {
52
+ ctx.throw(404, `Tool ${name} not found`);
53
+ }
54
+
55
+ try {
56
+ const result = await this.plugin.executeSkill(skill, args || {}, ctx);
57
+
58
+ let textContent = `Executed successfully.`;
59
+ if (result.stdout) textContent += `\nOutput:\n${result.stdout}`;
60
+ if (result.stderr) textContent += `\nErrors:\n${result.stderr}`;
61
+
62
+ if (result.files?.length) {
63
+ textContent += `\nFiles generated:\n` + result.files.map((f: any) => {
64
+ return `- [${f.name}](${f.downloadUrl})`;
65
+ }).join('\n');
66
+ }
67
+
68
+ ctx.body = {
69
+ content: [
70
+ {
71
+ type: 'text',
72
+ text: textContent,
73
+ }
74
+ ],
75
+ isError: result.status !== 'succeeded',
76
+ };
77
+ } catch (err: any) {
78
+ ctx.body = {
79
+ content: [{ type: 'text', text: `Skill Execution Error: ${err.message}` }],
80
+ isError: true,
81
+ };
82
+ }
83
+
84
+ await next();
85
+ }
86
+ }