plugin-agent-orchestrator 1.0.13 → 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 (251) 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 +6 -0
  153. package/dist/server/collections/skill-definitions.d.ts +3 -0
  154. package/dist/server/collections/skill-definitions.js +158 -0
  155. package/dist/server/collections/skill-executions.d.ts +3 -0
  156. package/dist/server/collections/skill-executions.js +123 -0
  157. package/dist/server/collections/skill-worker-configs.d.ts +3 -0
  158. package/dist/server/collections/skill-worker-configs.js +115 -0
  159. package/dist/server/migrations/20260423000000-add-progress-fields.d.ts +4 -0
  160. package/dist/server/migrations/20260423000000-add-progress-fields.js +69 -0
  161. package/dist/server/migrations/20260425000000-add-interaction-schema.d.ts +4 -0
  162. package/dist/server/migrations/20260425000000-add-interaction-schema.js +61 -0
  163. package/dist/server/migrations/20260427000000-change-packages-to-text.d.ts +4 -0
  164. package/dist/server/migrations/20260427000000-change-packages-to-text.js +70 -0
  165. package/dist/server/migrations/20260427000001-change-other-json-to-text.d.ts +4 -0
  166. package/dist/server/migrations/20260427000001-change-other-json-to-text.js +80 -0
  167. package/dist/server/migrations/20260429000000-add-llm-fields.js +8 -0
  168. package/dist/server/migrations/20260429000000-fix-inputargs-json-to-text.d.ts +16 -0
  169. package/dist/server/migrations/20260429000000-fix-inputargs-json-to-text.js +51 -0
  170. package/dist/server/migrations/20260503000000-add-orchestrator-trace-fields.d.ts +7 -0
  171. package/dist/server/migrations/20260503000000-add-orchestrator-trace-fields.js +57 -0
  172. package/dist/server/plugin.d.ts +3 -0
  173. package/dist/server/plugin.js +37 -1
  174. package/dist/server/resources/tracing.js +154 -11
  175. package/dist/server/services/CodeValidator.d.ts +32 -0
  176. package/dist/server/services/CodeValidator.js +205 -0
  177. package/dist/server/services/ExecutionSpanService.d.ts +44 -0
  178. package/dist/server/services/ExecutionSpanService.js +104 -0
  179. package/dist/server/services/FileManager.d.ts +28 -0
  180. package/dist/server/services/FileManager.js +151 -0
  181. package/dist/server/services/SandboxRunner.d.ts +41 -0
  182. package/dist/server/services/SandboxRunner.js +167 -0
  183. package/dist/server/services/SkillManager.d.ts +6 -0
  184. package/dist/server/services/SkillManager.js +640 -0
  185. package/dist/server/services/SkillRepositoryService.d.ts +22 -0
  186. package/dist/server/services/SkillRepositoryService.js +157 -0
  187. package/dist/server/services/WorkerEnvManager.d.ts +26 -0
  188. package/dist/server/services/WorkerEnvManager.js +120 -0
  189. package/dist/server/skill-hub/actions/git-import.d.ts +21 -0
  190. package/dist/server/skill-hub/actions/git-import.js +413 -0
  191. package/dist/server/skill-hub/mcp/McpController.d.ts +15 -0
  192. package/dist/server/skill-hub/mcp/McpController.js +111 -0
  193. package/dist/server/skill-hub/plugin.d.ts +58 -0
  194. package/dist/server/skill-hub/plugin.js +694 -0
  195. package/dist/server/skill-hub/sandbox-config.json +6 -0
  196. package/dist/server/skill-hub/tasks/SkillExecutionTask.d.ts +14 -0
  197. package/dist/server/skill-hub/tasks/SkillExecutionTask.js +267 -0
  198. package/dist/server/skill-hub/utils/json-fields.d.ts +7 -0
  199. package/dist/server/skill-hub/utils/json-fields.js +88 -0
  200. package/dist/server/tools/delegate-task.d.ts +4 -0
  201. package/dist/server/tools/delegate-task.js +606 -104
  202. package/dist/server/tools/skill-execute.d.ts +36 -0
  203. package/dist/server/tools/skill-execute.js +167 -0
  204. package/package.json +3 -1
  205. package/src/client/AIEmployeeSelect.tsx +1 -3
  206. package/src/client/AIEmployeesContext.tsx +28 -13
  207. package/src/client/OrchestratorSettings.tsx +43 -5
  208. package/src/client/RulesTab.tsx +253 -32
  209. package/src/client/TracingTab.tsx +277 -213
  210. package/src/client/plugin.tsx +39 -0
  211. package/src/client/skill-hub/components/ExecutionHistory.tsx +201 -0
  212. package/src/client/skill-hub/components/ExecutionProgress.tsx +55 -0
  213. package/src/client/skill-hub/components/GitSkillImport.tsx +555 -0
  214. package/src/client/skill-hub/components/SkillEditor.tsx +456 -0
  215. package/src/client/skill-hub/components/SkillManager.tsx +181 -0
  216. package/src/client/skill-hub/components/SkillMetrics.tsx +124 -0
  217. package/src/client/skill-hub/components/SkillTestPanel.tsx +144 -0
  218. package/src/client/skill-hub/index.tsx +75 -0
  219. package/src/client/skill-hub/locale.ts +16 -0
  220. package/src/client/skill-hub/tools/InteractionSchemasProvider.tsx +59 -0
  221. package/src/client/skill-hub/tools/SkillHubCard.tsx +78 -0
  222. package/src/client/skill-hub/utils/jsonFields.ts +37 -0
  223. package/src/server/collections/agent-execution-spans.ts +129 -0
  224. package/src/server/collections/orchestrator-config.ts +7 -0
  225. package/src/server/collections/skill-definitions.ts +128 -0
  226. package/src/server/collections/skill-executions.ts +94 -0
  227. package/src/server/collections/skill-worker-configs.ts +86 -0
  228. package/src/server/migrations/20260423000000-add-progress-fields.ts +50 -0
  229. package/src/server/migrations/20260425000000-add-interaction-schema.ts +35 -0
  230. package/src/server/migrations/20260427000000-change-packages-to-text.ts +47 -0
  231. package/src/server/migrations/20260427000001-change-other-json-to-text.ts +57 -0
  232. package/src/server/migrations/20260429000000-add-llm-fields.ts +9 -0
  233. package/src/server/migrations/20260429000000-fix-inputargs-json-to-text.ts +38 -0
  234. package/src/server/migrations/20260503000000-add-orchestrator-trace-fields.ts +32 -0
  235. package/src/server/plugin.ts +51 -3
  236. package/src/server/resources/tracing.ts +182 -15
  237. package/src/server/services/CodeValidator.ts +159 -0
  238. package/src/server/services/ExecutionSpanService.ts +106 -0
  239. package/src/server/services/FileManager.ts +144 -0
  240. package/src/server/services/SandboxRunner.ts +205 -0
  241. package/src/server/services/SkillManager.ts +623 -0
  242. package/src/server/services/SkillRepositoryService.ts +142 -0
  243. package/src/server/services/WorkerEnvManager.ts +113 -0
  244. package/src/server/skill-hub/actions/git-import.ts +486 -0
  245. package/src/server/skill-hub/mcp/McpController.ts +86 -0
  246. package/src/server/skill-hub/plugin.ts +771 -0
  247. package/src/server/skill-hub/sandbox-config.json +6 -0
  248. package/src/server/skill-hub/tasks/SkillExecutionTask.ts +297 -0
  249. package/src/server/skill-hub/utils/json-fields.ts +57 -0
  250. package/src/server/tools/delegate-task.ts +803 -127
  251. package/src/server/tools/skill-execute.ts +157 -0
@@ -0,0 +1,623 @@
1
+ import { Database } from '@nocobase/database';
2
+ import { stringifyJsonText } from '../skill-hub/utils/json-fields';
3
+
4
+ export class SkillManager {
5
+ constructor(private db: Database) {}
6
+
7
+ async seedDefaults() {
8
+ const repo = this.db.getRepository('skillDefinitions');
9
+
10
+ const seeds = [
11
+ {
12
+ name: 'generate-word-report',
13
+ title: 'Generate Word Report',
14
+ description: 'Generate a Word document (.docx) with title, content, and optional table data.',
15
+ language: 'python',
16
+ codeTemplate: SEED_WORD_REPORT,
17
+ inputSchema: {
18
+ type: 'object',
19
+ properties: {
20
+ title: { type: 'string', description: 'Report title' },
21
+ content: { type: 'string', description: 'Report body text' },
22
+ tableData: {
23
+ type: 'array',
24
+ items: { type: 'object' },
25
+ description: 'Optional array of objects for table rows',
26
+ },
27
+ },
28
+ required: ['title', 'content'],
29
+ },
30
+ packages: ['python-docx'],
31
+ timeoutSeconds: 30,
32
+ enabled: true,
33
+ toolScope: 'CUSTOM',
34
+ },
35
+ {
36
+ name: 'generate-excel',
37
+ title: 'Generate Excel Spreadsheet',
38
+ description: 'Generate an Excel file (.xlsx) with headers and row data.',
39
+ language: 'python',
40
+ codeTemplate: SEED_EXCEL,
41
+ inputSchema: {
42
+ type: 'object',
43
+ properties: {
44
+ sheetName: { type: 'string', description: 'Sheet name', default: 'Sheet1' },
45
+ headers: { type: 'array', items: { type: 'string' }, description: 'Column headers' },
46
+ rows: { type: 'array', items: { type: 'array' }, description: 'Row data (array of arrays)' },
47
+ },
48
+ required: ['headers', 'rows'],
49
+ },
50
+ packages: ['openpyxl'],
51
+ timeoutSeconds: 30,
52
+ enabled: true,
53
+ toolScope: 'CUSTOM',
54
+ },
55
+ {
56
+ name: 'generate-pdf-report',
57
+ title: 'Generate PDF Report',
58
+ description:
59
+ 'Generate a professional PDF report with title, sections, and optional table. Suitable for CRM reports, customer summaries, and sales reports.',
60
+ language: 'python',
61
+ codeTemplate: SEED_PDF_REPORT,
62
+ inputSchema: {
63
+ type: 'object',
64
+ properties: {
65
+ title: { type: 'string', description: 'Report title' },
66
+ sections: {
67
+ type: 'array',
68
+ items: {
69
+ type: 'object',
70
+ properties: {
71
+ heading: { type: 'string' },
72
+ body: { type: 'string' },
73
+ },
74
+ },
75
+ description: 'Array of {heading, body} sections',
76
+ },
77
+ tableData: {
78
+ type: 'array',
79
+ items: { type: 'object' },
80
+ description: 'Optional array of objects for a summary table',
81
+ },
82
+ },
83
+ required: ['title', 'sections'],
84
+ },
85
+ packages: ['reportlab'],
86
+ timeoutSeconds: 30,
87
+ enabled: true,
88
+ toolScope: 'CUSTOM',
89
+ },
90
+ {
91
+ name: 'generate-chart-image',
92
+ title: 'Generate Chart Image',
93
+ description:
94
+ 'Generate a chart image (PNG) from data. Supports bar, line, pie charts. Useful for visualizing CRM metrics like sales, leads, revenue.',
95
+ language: 'python',
96
+ codeTemplate: SEED_CHART,
97
+ inputSchema: {
98
+ type: 'object',
99
+ properties: {
100
+ chartType: {
101
+ type: 'string',
102
+ enum: ['bar', 'line', 'pie'],
103
+ description: 'Chart type',
104
+ },
105
+ title: { type: 'string', description: 'Chart title' },
106
+ labels: { type: 'array', items: { type: 'string' }, description: 'X-axis labels or pie labels' },
107
+ values: { type: 'array', items: { type: 'number' }, description: 'Data values' },
108
+ xlabel: { type: 'string', description: 'X-axis label (bar/line only)' },
109
+ ylabel: { type: 'string', description: 'Y-axis label (bar/line only)' },
110
+ },
111
+ required: ['chartType', 'title', 'labels', 'values'],
112
+ },
113
+ packages: ['matplotlib'],
114
+ timeoutSeconds: 30,
115
+ enabled: true,
116
+ toolScope: 'CUSTOM',
117
+ },
118
+ {
119
+ name: 'generate-invoice-pdf',
120
+ title: 'Generate Invoice PDF',
121
+ description:
122
+ 'Generate a professional invoice PDF with company info, line items, and totals. For CRM billing and quotation workflows.',
123
+ language: 'python',
124
+ codeTemplate: SEED_INVOICE,
125
+ inputSchema: {
126
+ type: 'object',
127
+ properties: {
128
+ invoiceNumber: { type: 'string', description: 'Invoice number' },
129
+ date: { type: 'string', description: 'Invoice date (YYYY-MM-DD)' },
130
+ companyName: { type: 'string', description: 'Your company name' },
131
+ customerName: { type: 'string', description: 'Customer name' },
132
+ customerAddress: { type: 'string', description: 'Customer address' },
133
+ items: {
134
+ type: 'array',
135
+ items: {
136
+ type: 'object',
137
+ properties: {
138
+ description: { type: 'string' },
139
+ quantity: { type: 'number' },
140
+ unitPrice: { type: 'number' },
141
+ },
142
+ },
143
+ description: 'Line items with description, quantity, unitPrice',
144
+ },
145
+ currency: { type: 'string', description: 'Currency symbol', default: '$' },
146
+ notes: { type: 'string', description: 'Optional notes or payment terms' },
147
+ },
148
+ required: ['invoiceNumber', 'date', 'companyName', 'customerName', 'items'],
149
+ },
150
+ packages: ['reportlab'],
151
+ timeoutSeconds: 30,
152
+ enabled: true,
153
+ toolScope: 'CUSTOM',
154
+ },
155
+ {
156
+ name: 'data-summary-report',
157
+ title: 'Data Summary & Analysis Report',
158
+ description:
159
+ 'Analyze tabular data and generate a Word report with summary statistics, top records, and insights. Ideal for CRM data analysis — leads, deals, customers.',
160
+ language: 'python',
161
+ codeTemplate: SEED_DATA_SUMMARY,
162
+ inputSchema: {
163
+ type: 'object',
164
+ properties: {
165
+ title: { type: 'string', description: 'Report title' },
166
+ data: {
167
+ type: 'array',
168
+ items: { type: 'object' },
169
+ description: 'Array of data objects (e.g. deals, leads, customers)',
170
+ },
171
+ groupByField: { type: 'string', description: 'Optional field to group and summarize by' },
172
+ sortByField: { type: 'string', description: 'Optional field to sort by (descending)' },
173
+ topN: { type: 'number', description: 'Number of top records to include', default: 10 },
174
+ },
175
+ required: ['title', 'data'],
176
+ },
177
+ packages: ['pandas', 'python-docx'],
178
+ timeoutSeconds: 60,
179
+ enabled: true,
180
+ toolScope: 'CUSTOM',
181
+ },
182
+ {
183
+ name: 'data-transform',
184
+ title: 'Data Transform (CSV/JSON)',
185
+ description: 'Transform data array to CSV or JSON file for download.',
186
+ language: 'node',
187
+ codeTemplate: SEED_DATA_TRANSFORM,
188
+ inputSchema: {
189
+ type: 'object',
190
+ properties: {
191
+ data: { type: 'array', items: { type: 'object' }, description: 'Array of data objects' },
192
+ format: { type: 'string', enum: ['csv', 'json'], description: 'Output format' },
193
+ filename: { type: 'string', description: 'Output filename (without extension)' },
194
+ },
195
+ required: ['data', 'format'],
196
+ },
197
+ packages: [],
198
+ timeoutSeconds: 30,
199
+ enabled: true,
200
+ toolScope: 'CUSTOM',
201
+ },
202
+ ];
203
+
204
+ for (const seed of seeds) {
205
+ try {
206
+ const count = await repo.count({ filter: { name: seed.name } });
207
+ if (count === 0) {
208
+ await repo.create({
209
+ values: {
210
+ ...seed,
211
+ inputSchema: stringifyJsonText(seed.inputSchema),
212
+ packages: stringifyJsonText(seed.packages, []),
213
+ },
214
+ });
215
+ }
216
+ } catch (err) {
217
+ console.error(`[import-skill] Failed to insert ${seed.name}:`, err);
218
+ // Skip if already exists (unique constraint on name)
219
+ }
220
+ }
221
+ }
222
+ }
223
+
224
+ // ─── Seed Code Templates ───
225
+
226
+ const SEED_WORD_REPORT = `import os, json
227
+ from docx import Document
228
+
229
+ title = json.loads('''{{title}}''') if '{{title}}'.startswith('"') else '{{title}}'
230
+ content = json.loads('''{{content}}''') if '{{content}}'.startswith('"') else '{{content}}'
231
+
232
+ doc = Document()
233
+ doc.add_heading(title, 0)
234
+ doc.add_paragraph(content)
235
+
236
+ table_data_raw = '''{{tableData}}'''
237
+ if table_data_raw and table_data_raw != '{{' + 'tableData}}':
238
+ table_data = json.loads(table_data_raw)
239
+ if table_data and len(table_data) > 0:
240
+ headers = list(table_data[0].keys())
241
+ table = doc.add_table(rows=1, cols=len(headers))
242
+ table.style = 'Light Grid Accent 1'
243
+ for i, header in enumerate(headers):
244
+ table.rows[0].cells[i].text = str(header)
245
+ for row_data in table_data:
246
+ row = table.add_row()
247
+ for i, header in enumerate(headers):
248
+ row.cells[i].text = str(row_data.get(header, ''))
249
+
250
+ output_dir = os.environ.get('OUTPUT_DIR', '/output')
251
+ filepath = os.path.join(output_dir, 'report.docx')
252
+ doc.save(filepath)
253
+ print(f'Generated: report.docx')
254
+ `;
255
+
256
+ const SEED_EXCEL = `import os, json
257
+ import openpyxl
258
+
259
+ sheet_name_raw = '{{sheetName}}'
260
+ sheet_name = sheet_name_raw if sheet_name_raw != '{{' + 'sheetName}}' else 'Sheet1'
261
+ headers = json.loads('''{{headers}}''')
262
+ rows = json.loads('''{{rows}}''')
263
+
264
+ wb = openpyxl.Workbook()
265
+ ws = wb.active
266
+ ws.title = sheet_name
267
+
268
+ for col, header in enumerate(headers, 1):
269
+ ws.cell(row=1, column=col, value=header)
270
+
271
+ for row_idx, row_data in enumerate(rows, 2):
272
+ for col_idx, value in enumerate(row_data, 1):
273
+ ws.cell(row=row_idx, column=col_idx, value=value)
274
+
275
+ output_dir = os.environ.get('OUTPUT_DIR', '/output')
276
+ filepath = os.path.join(output_dir, 'data.xlsx')
277
+ wb.save(filepath)
278
+ print(f'Generated: data.xlsx')
279
+ `;
280
+
281
+ const SEED_PDF_REPORT = `import os, json
282
+ from reportlab.lib.pagesizes import A4
283
+ from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
284
+ from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle
285
+ from reportlab.lib import colors
286
+ from reportlab.lib.units import cm
287
+
288
+ title = json.loads('''{{title}}''') if '{{title}}'.startswith('"') else '{{title}}'
289
+ sections = json.loads('''{{sections}}''')
290
+
291
+ output_dir = os.environ.get('OUTPUT_DIR', '/output')
292
+ filepath = os.path.join(output_dir, 'report.pdf')
293
+
294
+ doc = SimpleDocTemplate(filepath, pagesize=A4,
295
+ topMargin=2*cm, bottomMargin=2*cm, leftMargin=2*cm, rightMargin=2*cm)
296
+ styles = getSampleStyleSheet()
297
+ title_style = ParagraphStyle('CustomTitle', parent=styles['Title'], fontSize=22, spaceAfter=20)
298
+ heading_style = ParagraphStyle('CustomHeading', parent=styles['Heading2'], fontSize=14, spaceBefore=16, spaceAfter=8)
299
+ body_style = styles['BodyText']
300
+
301
+ story = [Paragraph(title, title_style), Spacer(1, 12)]
302
+
303
+ for section in sections:
304
+ if section.get('heading'):
305
+ story.append(Paragraph(section['heading'], heading_style))
306
+ if section.get('body'):
307
+ for line in section['body'].split('\\n'):
308
+ story.append(Paragraph(line, body_style))
309
+ story.append(Spacer(1, 8))
310
+
311
+ table_data_raw = '''{{tableData}}'''
312
+ if table_data_raw and table_data_raw != '{{' + 'tableData}}':
313
+ td = json.loads(table_data_raw)
314
+ if td and len(td) > 0:
315
+ headers = list(td[0].keys())
316
+ data = [headers] + [[str(r.get(h, '')) for h in headers] for r in td]
317
+ t = Table(data, repeatRows=1)
318
+ t.setStyle(TableStyle([
319
+ ('BACKGROUND', (0, 0), (-1, 0), colors.HexColor('#4472C4')),
320
+ ('TEXTCOLOR', (0, 0), (-1, 0), colors.white),
321
+ ('FONTSIZE', (0, 0), (-1, 0), 10),
322
+ ('FONTSIZE', (0, 1), (-1, -1), 9),
323
+ ('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
324
+ ('ROWBACKGROUNDS', (0, 1), (-1, -1), [colors.white, colors.HexColor('#D9E2F3')]),
325
+ ]))
326
+ story.append(Spacer(1, 12))
327
+ story.append(t)
328
+
329
+ doc.build(story)
330
+ print('Generated: report.pdf')
331
+ `;
332
+
333
+ const SEED_PPTX = `import os, json
334
+ from pptx import Presentation
335
+ from pptx.util import Inches, Pt
336
+ from pptx.enum.text import PP_ALIGN
337
+
338
+ title = json.loads('''{{title}}''') if '{{title}}'.startswith('"') else '{{title}}'
339
+ subtitle_raw = '''{{subtitle}}'''
340
+ subtitle = json.loads(subtitle_raw) if subtitle_raw.startswith('"') else subtitle_raw if subtitle_raw != '{{' + 'subtitle}}' else ''
341
+ slides_data = json.loads('''{{slides}}''')
342
+
343
+ prs = Presentation()
344
+ prs.slide_width = Inches(13.333)
345
+ prs.slide_height = Inches(7.5)
346
+
347
+ # Title slide
348
+ slide = prs.slides.add_slide(prs.slide_layouts[0])
349
+ slide.shapes.title.text = title
350
+ if subtitle and slide.placeholders[1]:
351
+ slide.placeholders[1].text = subtitle
352
+
353
+ # Content slides
354
+ for s in slides_data:
355
+ slide = prs.slides.add_slide(prs.slide_layouts[1])
356
+ slide.shapes.title.text = s.get('title', '')
357
+ body = slide.placeholders[1].text_frame
358
+ body.clear()
359
+ for i, bullet in enumerate(s.get('bullets', [])):
360
+ if i == 0:
361
+ body.paragraphs[0].text = bullet
362
+ else:
363
+ p = body.add_paragraph()
364
+ p.text = bullet
365
+ body.paragraphs[-1].font.size = Pt(18)
366
+
367
+ output_dir = os.environ.get('OUTPUT_DIR', '/output')
368
+ filepath = os.path.join(output_dir, 'presentation.pptx')
369
+ prs.save(filepath)
370
+ print('Generated: presentation.pptx')
371
+ `;
372
+
373
+ const SEED_CHART = `import os, json
374
+ import matplotlib
375
+ matplotlib.use('Agg')
376
+ import matplotlib.pyplot as plt
377
+
378
+ chart_type = '{{chartType}}'
379
+ title = json.loads('''{{title}}''') if '{{title}}'.startswith('"') else '{{title}}'
380
+ labels = json.loads('''{{labels}}''')
381
+ values = json.loads('''{{values}}''')
382
+ xlabel_raw = '''{{xlabel}}'''
383
+ ylabel_raw = '''{{ylabel}}'''
384
+ xlabel = xlabel_raw if xlabel_raw != '{{' + 'xlabel}}' else ''
385
+ ylabel = ylabel_raw if ylabel_raw != '{{' + 'ylabel}}' else ''
386
+
387
+ fig, ax = plt.subplots(figsize=(10, 6))
388
+ colors = ['#4472C4', '#ED7D31', '#A5A5A5', '#FFC000', '#5B9BD5', '#70AD47', '#264478', '#9B59B6']
389
+
390
+ if chart_type == 'bar':
391
+ bars = ax.bar(labels, values, color=colors[:len(labels)])
392
+ for bar, val in zip(bars, values):
393
+ ax.text(bar.get_x() + bar.get_width()/2, bar.get_height() + max(values)*0.01,
394
+ f'{val:,.0f}' if isinstance(val, (int, float)) else str(val),
395
+ ha='center', va='bottom', fontsize=9)
396
+ if xlabel: ax.set_xlabel(xlabel)
397
+ if ylabel: ax.set_ylabel(ylabel)
398
+ elif chart_type == 'line':
399
+ ax.plot(labels, values, marker='o', linewidth=2, color='#4472C4', markersize=6)
400
+ for i, val in enumerate(values):
401
+ ax.annotate(f'{val:,.0f}', (labels[i], val), textcoords="offset points",
402
+ xytext=(0, 10), ha='center', fontsize=9)
403
+ if xlabel: ax.set_xlabel(xlabel)
404
+ if ylabel: ax.set_ylabel(ylabel)
405
+ elif chart_type == 'pie':
406
+ ax.pie(values, labels=labels, colors=colors[:len(labels)], autopct='%1.1f%%', startangle=90)
407
+
408
+ ax.set_title(title, fontsize=14, fontweight='bold', pad=15)
409
+ plt.tight_layout()
410
+
411
+ output_dir = os.environ.get('OUTPUT_DIR', '/output')
412
+ filepath = os.path.join(output_dir, 'chart.png')
413
+ fig.savefig(filepath, dpi=150, bbox_inches='tight')
414
+ plt.close()
415
+ print('Generated: chart.png')
416
+ `;
417
+
418
+ const SEED_INVOICE = `import os, json
419
+ from reportlab.lib.pagesizes import A4
420
+ from reportlab.pdfgen import canvas
421
+ from reportlab.lib.units import cm, mm
422
+ from reportlab.lib import colors
423
+
424
+ inv_number = json.loads('''{{invoiceNumber}}''') if '{{invoiceNumber}}'.startswith('"') else '{{invoiceNumber}}'
425
+ date = json.loads('''{{date}}''') if '{{date}}'.startswith('"') else '{{date}}'
426
+ company = json.loads('''{{companyName}}''') if '{{companyName}}'.startswith('"') else '{{companyName}}'
427
+ customer = json.loads('''{{customerName}}''') if '{{customerName}}'.startswith('"') else '{{customerName}}'
428
+ address_raw = '''{{customerAddress}}'''
429
+ address = json.loads(address_raw) if address_raw.startswith('"') else address_raw if address_raw != '{{' + 'customerAddress}}' else ''
430
+ items = json.loads('''{{items}}''')
431
+ currency_raw = '''{{currency}}'''
432
+ currency = currency_raw if currency_raw != '{{' + 'currency}}' else '$'
433
+ notes_raw = '''{{notes}}'''
434
+ notes = json.loads(notes_raw) if notes_raw.startswith('"') else notes_raw if notes_raw != '{{' + 'notes}}' else ''
435
+
436
+ output_dir = os.environ.get('OUTPUT_DIR', '/output')
437
+ filepath = os.path.join(output_dir, f'invoice_{inv_number}.pdf')
438
+ w, h = A4
439
+ c = canvas.Canvas(filepath, pagesize=A4)
440
+
441
+ # Header
442
+ c.setFont('Helvetica-Bold', 24)
443
+ c.setFillColor(colors.HexColor('#2C3E50'))
444
+ c.drawString(2*cm, h - 2.5*cm, 'INVOICE')
445
+ c.setFont('Helvetica', 10)
446
+ c.setFillColor(colors.HexColor('#7F8C8D'))
447
+ c.drawRightString(w - 2*cm, h - 2.5*cm, f'#{inv_number}')
448
+ c.drawRightString(w - 2*cm, h - 3*cm, f'Date: {date}')
449
+
450
+ # Company & Customer
451
+ y = h - 4.5*cm
452
+ c.setFillColor(colors.HexColor('#2C3E50'))
453
+ c.setFont('Helvetica-Bold', 11)
454
+ c.drawString(2*cm, y, 'From:')
455
+ c.drawString(10*cm, y, 'To:')
456
+ c.setFont('Helvetica', 10)
457
+ c.setFillColor(colors.black)
458
+ c.drawString(2*cm, y - 0.5*cm, company)
459
+ c.drawString(10*cm, y - 0.5*cm, customer)
460
+ if address:
461
+ for i, line in enumerate(address.split('\\n')):
462
+ c.drawString(10*cm, y - (1 + i*0.5)*cm, line)
463
+
464
+ # Table header
465
+ y = h - 8*cm
466
+ c.setFillColor(colors.HexColor('#4472C4'))
467
+ c.rect(2*cm, y - 0.1*cm, w - 4*cm, 0.7*cm, fill=1, stroke=0)
468
+ c.setFillColor(colors.white)
469
+ c.setFont('Helvetica-Bold', 9)
470
+ c.drawString(2.2*cm, y + 0.1*cm, 'Description')
471
+ c.drawRightString(12*cm, y + 0.1*cm, 'Qty')
472
+ c.drawRightString(15*cm, y + 0.1*cm, 'Unit Price')
473
+ c.drawRightString(w - 2.2*cm, y + 0.1*cm, 'Amount')
474
+
475
+ # Items
476
+ c.setFillColor(colors.black)
477
+ c.setFont('Helvetica', 9)
478
+ total = 0
479
+ for i, item in enumerate(items):
480
+ row_y = y - (i + 1) * 0.6*cm
481
+ qty = item.get('quantity', 0)
482
+ price = item.get('unitPrice', 0)
483
+ amount = qty * price
484
+ total += amount
485
+ if i % 2 == 1:
486
+ c.setFillColor(colors.HexColor('#F0F4F8'))
487
+ c.rect(2*cm, row_y - 0.1*cm, w - 4*cm, 0.6*cm, fill=1, stroke=0)
488
+ c.setFillColor(colors.black)
489
+ c.drawString(2.2*cm, row_y + 0.1*cm, str(item.get('description', '')))
490
+ c.drawRightString(12*cm, row_y + 0.1*cm, str(qty))
491
+ c.drawRightString(15*cm, row_y + 0.1*cm, f'{currency}{price:,.2f}')
492
+ c.drawRightString(w - 2.2*cm, row_y + 0.1*cm, f'{currency}{amount:,.2f}')
493
+
494
+ # Total
495
+ total_y = y - (len(items) + 1.5) * 0.6*cm
496
+ c.setStrokeColor(colors.HexColor('#4472C4'))
497
+ c.line(12*cm, total_y + 0.4*cm, w - 2*cm, total_y + 0.4*cm)
498
+ c.setFont('Helvetica-Bold', 11)
499
+ c.drawRightString(15*cm, total_y, 'Total:')
500
+ c.setFillColor(colors.HexColor('#2C3E50'))
501
+ c.drawRightString(w - 2.2*cm, total_y, f'{currency}{total:,.2f}')
502
+
503
+ # Notes
504
+ if notes:
505
+ notes_y = total_y - 2*cm
506
+ c.setFillColor(colors.HexColor('#7F8C8D'))
507
+ c.setFont('Helvetica-Bold', 9)
508
+ c.drawString(2*cm, notes_y, 'Notes:')
509
+ c.setFont('Helvetica', 9)
510
+ c.setFillColor(colors.black)
511
+ for i, line in enumerate(notes.split('\\n')):
512
+ c.drawString(2*cm, notes_y - (i + 1) * 0.4*cm, line)
513
+
514
+ c.save()
515
+ print(f'Generated: invoice_{inv_number}.pdf')
516
+ `;
517
+
518
+ const SEED_DATA_SUMMARY = `import os, json
519
+ import pandas as pd
520
+ from docx import Document
521
+ from docx.shared import Inches, Pt
522
+ from docx.enum.table import WD_TABLE_ALIGNMENT
523
+
524
+ title = json.loads('''{{title}}''') if '{{title}}'.startswith('"') else '{{title}}'
525
+ raw_data = json.loads('''{{data}}''')
526
+ group_by_raw = '''{{groupByField}}'''
527
+ group_by = group_by_raw if group_by_raw != '{{' + 'groupByField}}' else None
528
+ sort_by_raw = '''{{sortByField}}'''
529
+ sort_by = sort_by_raw if sort_by_raw != '{{' + 'sortByField}}' else None
530
+ top_n_raw = '''{{topN}}'''
531
+ top_n = int(top_n_raw) if top_n_raw != '{{' + 'topN}}' else 10
532
+
533
+ df = pd.DataFrame(raw_data)
534
+ doc = Document()
535
+ doc.add_heading(title, 0)
536
+
537
+ # Overview
538
+ doc.add_heading('Overview', level=1)
539
+ doc.add_paragraph(f'Total records: {len(df)}')
540
+ doc.add_paragraph(f'Fields: {", ".join(df.columns.tolist())}')
541
+
542
+ # Numeric summary
543
+ num_cols = df.select_dtypes(include='number').columns.tolist()
544
+ if num_cols:
545
+ doc.add_heading('Numeric Summary', level=1)
546
+ stats = df[num_cols].describe().round(2)
547
+ table = doc.add_table(rows=len(stats) + 1, cols=len(num_cols) + 1)
548
+ table.style = 'Light Grid Accent 1'
549
+ table.alignment = WD_TABLE_ALIGNMENT.CENTER
550
+ table.rows[0].cells[0].text = 'Metric'
551
+ for j, col in enumerate(num_cols):
552
+ table.rows[0].cells[j + 1].text = col
553
+ for i, (idx, row) in enumerate(stats.iterrows()):
554
+ table.rows[i + 1].cells[0].text = str(idx)
555
+ for j, col in enumerate(num_cols):
556
+ table.rows[i + 1].cells[j + 1].text = str(row[col])
557
+
558
+ # Group-by analysis
559
+ if group_by and group_by in df.columns:
560
+ doc.add_heading(f'Grouped by: {group_by}', level=1)
561
+ grouped = df.groupby(group_by)
562
+ summary_rows = []
563
+ for name, group in grouped:
564
+ row_info = {'Group': str(name), 'Count': len(group)}
565
+ for nc in num_cols:
566
+ row_info[f'{nc} (sum)'] = round(group[nc].sum(), 2)
567
+ row_info[f'{nc} (avg)'] = round(group[nc].mean(), 2)
568
+ summary_rows.append(row_info)
569
+ if summary_rows:
570
+ headers = list(summary_rows[0].keys())
571
+ table = doc.add_table(rows=len(summary_rows) + 1, cols=len(headers))
572
+ table.style = 'Light Grid Accent 1'
573
+ for j, h in enumerate(headers):
574
+ table.rows[0].cells[j].text = h
575
+ for i, sr in enumerate(summary_rows):
576
+ for j, h in enumerate(headers):
577
+ table.rows[i + 1].cells[j].text = str(sr[h])
578
+
579
+ # Top records
580
+ if sort_by and sort_by in df.columns:
581
+ df_sorted = df.sort_values(sort_by, ascending=False)
582
+ else:
583
+ df_sorted = df
584
+ top = df_sorted.head(top_n)
585
+ doc.add_heading(f'Top {top_n} Records', level=1)
586
+ cols = top.columns.tolist()
587
+ table = doc.add_table(rows=len(top) + 1, cols=len(cols))
588
+ table.style = 'Light Grid Accent 1'
589
+ for j, col in enumerate(cols):
590
+ table.rows[0].cells[j].text = str(col)
591
+ for i, (_, row) in enumerate(top.iterrows()):
592
+ for j, col in enumerate(cols):
593
+ table.rows[i + 1].cells[j].text = str(row[col])
594
+
595
+ output_dir = os.environ.get('OUTPUT_DIR', '/output')
596
+ filepath = os.path.join(output_dir, 'summary_report.docx')
597
+ doc.save(filepath)
598
+ print('Generated: summary_report.docx')
599
+ `;
600
+
601
+ const SEED_DATA_TRANSFORM = `const fs = require('fs');
602
+ const path = require('path');
603
+
604
+ const data = {{data}};
605
+ const format = '{{format}}';
606
+ const filename = '{{filename}}' !== '{{' + 'filename}}' ? '{{filename}}' : 'result';
607
+ const outputDir = process.env.OUTPUT_DIR || '/output';
608
+
609
+ if (format === 'csv') {
610
+ const headers = Object.keys(data[0] || {});
611
+ const csv = [
612
+ headers.join(','),
613
+ ...data.map(row => headers.map(h => JSON.stringify(row[h] ?? '')).join(','))
614
+ ].join('\\n');
615
+ const outPath = path.join(outputDir, filename + '.csv');
616
+ fs.writeFileSync(outPath, csv, 'utf-8');
617
+ console.log('Generated: ' + filename + '.csv');
618
+ } else {
619
+ const outPath = path.join(outputDir, filename + '.json');
620
+ fs.writeFileSync(outPath, JSON.stringify(data, null, 2), 'utf-8');
621
+ console.log('Generated: ' + filename + '.json');
622
+ }
623
+ `;