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.
- package/README.md +16 -291
- package/dist/client/AIEmployeesContext.d.ts +7 -0
- package/dist/client/OrchestratorSettings.d.ts +2 -1
- package/dist/client/index.js +1 -1
- package/dist/client/plugin.d.ts +1 -0
- package/dist/client/skill-hub/components/ExecutionHistory.d.ts +2 -0
- package/dist/client/skill-hub/components/ExecutionProgress.d.ts +20 -0
- package/dist/client/skill-hub/components/GitSkillImport.d.ts +7 -0
- package/dist/client/skill-hub/components/SkillEditor.d.ts +7 -0
- package/dist/client/skill-hub/components/SkillManager.d.ts +2 -0
- package/dist/client/skill-hub/components/SkillMetrics.d.ts +2 -0
- package/dist/client/skill-hub/components/SkillTestPanel.d.ts +7 -0
- package/dist/client/skill-hub/index.d.ts +10 -0
- package/dist/client/skill-hub/locale.d.ts +3 -0
- package/dist/client/skill-hub/tools/InteractionSchemasProvider.d.ts +19 -0
- package/dist/client/skill-hub/tools/SkillHubCard.d.ts +3 -0
- package/dist/client/skill-hub/utils/jsonFields.d.ts +3 -0
- package/dist/externalVersion.js +6 -6
- package/dist/node_modules/adm-zip/LICENSE +21 -0
- package/dist/node_modules/adm-zip/adm-zip.js +1 -0
- package/dist/node_modules/adm-zip/headers/entryHeader.js +377 -0
- package/dist/node_modules/adm-zip/headers/index.js +2 -0
- package/dist/node_modules/adm-zip/headers/mainHeader.js +130 -0
- package/dist/node_modules/adm-zip/methods/deflater.js +33 -0
- package/dist/node_modules/adm-zip/methods/index.js +3 -0
- package/dist/node_modules/adm-zip/methods/inflater.js +34 -0
- package/dist/node_modules/adm-zip/methods/zipcrypto.js +175 -0
- package/dist/node_modules/adm-zip/package.json +1 -0
- package/dist/node_modules/adm-zip/util/constants.js +142 -0
- package/dist/node_modules/adm-zip/util/decoder.js +5 -0
- package/dist/node_modules/adm-zip/util/errors.js +63 -0
- package/dist/node_modules/adm-zip/util/fattr.js +76 -0
- package/dist/node_modules/adm-zip/util/index.js +5 -0
- package/dist/node_modules/adm-zip/util/utils.js +339 -0
- package/dist/node_modules/adm-zip/zipEntry.js +405 -0
- package/dist/node_modules/adm-zip/zipFile.js +446 -0
- package/dist/node_modules/simple-git/dist/cjs/index.js +7399 -0
- package/dist/node_modules/simple-git/dist/esm/index.js +4745 -0
- package/dist/node_modules/simple-git/dist/esm/package.json +3 -0
- package/dist/node_modules/simple-git/dist/src/lib/api.d.ts +13 -0
- package/dist/node_modules/simple-git/dist/src/lib/args/log-format.d.ts +9 -0
- package/dist/node_modules/simple-git/dist/src/lib/errors/git-construct-error.d.ts +15 -0
- package/dist/node_modules/simple-git/dist/src/lib/errors/git-error.d.ts +30 -0
- package/dist/node_modules/simple-git/dist/src/lib/errors/git-plugin-error.d.ts +7 -0
- package/dist/node_modules/simple-git/dist/src/lib/errors/git-response-error.d.ts +32 -0
- package/dist/node_modules/simple-git/dist/src/lib/errors/task-configuration-error.d.ts +12 -0
- package/dist/node_modules/simple-git/dist/src/lib/git-factory.d.ts +15 -0
- package/dist/node_modules/simple-git/dist/src/lib/git-logger.d.ts +21 -0
- package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-branch-delete.d.ts +5 -0
- package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-branch.d.ts +2 -0
- package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-commit.d.ts +2 -0
- package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-diff-summary.d.ts +3 -0
- package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-fetch.d.ts +2 -0
- package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-list-log-summary.d.ts +6 -0
- package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-merge.d.ts +11 -0
- package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-move.d.ts +2 -0
- package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-pull.d.ts +6 -0
- package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-push.d.ts +4 -0
- package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-remote-messages.d.ts +5 -0
- package/dist/node_modules/simple-git/dist/src/lib/parsers/parse-remote-objects.d.ts +3 -0
- package/dist/node_modules/simple-git/dist/src/lib/plugins/abort-plugin.d.ts +3 -0
- package/dist/node_modules/simple-git/dist/src/lib/plugins/block-unsafe-operations-plugin.d.ts +3 -0
- package/dist/node_modules/simple-git/dist/src/lib/plugins/command-config-prefixing-plugin.d.ts +2 -0
- package/dist/node_modules/simple-git/dist/src/lib/plugins/completion-detection.plugin.d.ts +3 -0
- package/dist/node_modules/simple-git/dist/src/lib/plugins/custom-binary.plugin.d.ts +3 -0
- package/dist/node_modules/simple-git/dist/src/lib/plugins/error-detection.plugin.d.ts +7 -0
- package/dist/node_modules/simple-git/dist/src/lib/plugins/index.d.ts +11 -0
- package/dist/node_modules/simple-git/dist/src/lib/plugins/plugin-store.d.ts +11 -0
- package/dist/node_modules/simple-git/dist/src/lib/plugins/progress-monitor-plugin.d.ts +3 -0
- package/dist/node_modules/simple-git/dist/src/lib/plugins/simple-git-plugin.d.ts +48 -0
- package/dist/node_modules/simple-git/dist/src/lib/plugins/spawn-options-plugin.d.ts +3 -0
- package/dist/node_modules/simple-git/dist/src/lib/plugins/suffix-paths.plugin.d.ts +2 -0
- package/dist/node_modules/simple-git/dist/src/lib/plugins/timout-plugin.d.ts +3 -0
- package/dist/node_modules/simple-git/dist/src/lib/responses/BranchDeleteSummary.d.ts +12 -0
- package/dist/node_modules/simple-git/dist/src/lib/responses/BranchSummary.d.ts +14 -0
- package/dist/node_modules/simple-git/dist/src/lib/responses/CheckIgnore.d.ts +4 -0
- package/dist/node_modules/simple-git/dist/src/lib/responses/CleanSummary.d.ts +9 -0
- package/dist/node_modules/simple-git/dist/src/lib/responses/ConfigList.d.ts +13 -0
- package/dist/node_modules/simple-git/dist/src/lib/responses/DiffSummary.d.ts +10 -0
- package/dist/node_modules/simple-git/dist/src/lib/responses/FileStatusSummary.d.ts +9 -0
- package/dist/node_modules/simple-git/dist/src/lib/responses/GetRemoteSummary.d.ts +11 -0
- package/dist/node_modules/simple-git/dist/src/lib/responses/InitSummary.d.ts +9 -0
- package/dist/node_modules/simple-git/dist/src/lib/responses/MergeSummary.d.ts +16 -0
- package/dist/node_modules/simple-git/dist/src/lib/responses/PullSummary.d.ts +25 -0
- package/dist/node_modules/simple-git/dist/src/lib/responses/StatusSummary.d.ts +19 -0
- package/dist/node_modules/simple-git/dist/src/lib/responses/TagList.d.ts +7 -0
- package/dist/node_modules/simple-git/dist/src/lib/runners/git-executor-chain.d.ts +25 -0
- package/dist/node_modules/simple-git/dist/src/lib/runners/git-executor.d.ts +14 -0
- package/dist/node_modules/simple-git/dist/src/lib/runners/promise-wrapped.d.ts +2 -0
- package/dist/node_modules/simple-git/dist/src/lib/runners/scheduler.d.ts +11 -0
- package/dist/node_modules/simple-git/dist/src/lib/runners/tasks-pending-queue.d.ts +23 -0
- package/dist/node_modules/simple-git/dist/src/lib/simple-git-api.d.ts +20 -0
- package/dist/node_modules/simple-git/dist/src/lib/task-callback.d.ts +2 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/apply-patch.d.ts +3 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/branch.d.ts +7 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/change-working-directory.d.ts +2 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/check-ignore.d.ts +2 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/check-is-repo.d.ts +9 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/checkout.d.ts +2 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/clean.d.ts +25 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/clone.d.ts +9 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/commit.d.ts +4 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/config.d.ts +8 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/count-objects.d.ts +12 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/diff-name-status.d.ts +12 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/diff.d.ts +5 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/fetch.d.ts +4 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/first-commit.d.ts +2 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/grep.d.ts +12 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/hash-object.d.ts +5 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/init.d.ts +3 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/log.d.ts +32 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/merge.d.ts +4 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/move.d.ts +3 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/pull.d.ts +3 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/push.d.ts +9 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/remote.d.ts +8 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/reset.d.ts +11 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/show.d.ts +2 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/stash-list.d.ts +4 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/status.d.ts +3 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/sub-module.d.ts +5 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/tag.d.ts +18 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/task.d.ts +14 -0
- package/dist/node_modules/simple-git/dist/src/lib/tasks/version.d.ts +9 -0
- package/dist/node_modules/simple-git/dist/src/lib/types/handlers.d.ts +21 -0
- package/dist/node_modules/simple-git/dist/src/lib/types/index.d.ts +136 -0
- package/dist/node_modules/simple-git/dist/src/lib/types/tasks.d.ts +19 -0
- package/dist/node_modules/simple-git/dist/src/lib/utils/argument-filters.d.ts +14 -0
- package/dist/node_modules/simple-git/dist/src/lib/utils/exit-codes.d.ts +10 -0
- package/dist/node_modules/simple-git/dist/src/lib/utils/git-output-streams.d.ts +7 -0
- package/dist/node_modules/simple-git/dist/src/lib/utils/index.d.ts +8 -0
- package/dist/node_modules/simple-git/dist/src/lib/utils/line-parser.d.ts +15 -0
- package/dist/node_modules/simple-git/dist/src/lib/utils/simple-git-options.d.ts +2 -0
- package/dist/node_modules/simple-git/dist/src/lib/utils/task-options.d.ts +13 -0
- package/dist/node_modules/simple-git/dist/src/lib/utils/task-parser.d.ts +5 -0
- package/dist/node_modules/simple-git/dist/src/lib/utils/util.d.ts +47 -0
- package/dist/node_modules/simple-git/dist/typings/errors.d.ts +5 -0
- package/dist/node_modules/simple-git/dist/typings/index.d.ts +14 -0
- package/dist/node_modules/simple-git/dist/typings/response.d.ts +556 -0
- package/dist/node_modules/simple-git/dist/typings/simple-git.d.ts +1033 -0
- package/dist/node_modules/simple-git/dist/typings/types.d.ts +22 -0
- package/dist/node_modules/simple-git/node_modules/debug/package.json +64 -0
- package/dist/node_modules/simple-git/node_modules/debug/src/browser.js +272 -0
- package/dist/node_modules/simple-git/node_modules/debug/src/common.js +292 -0
- package/dist/node_modules/simple-git/node_modules/debug/src/index.js +10 -0
- package/dist/node_modules/simple-git/node_modules/debug/src/node.js +263 -0
- package/dist/node_modules/simple-git/package.json +1 -0
- package/dist/node_modules/simple-git/promise.js +17 -0
- package/dist/server/collections/agent-execution-spans.d.ts +9 -0
- package/dist/server/collections/agent-execution-spans.js +152 -0
- package/dist/server/collections/orchestrator-config.d.ts +1 -1
- package/dist/server/collections/orchestrator-config.js +6 -0
- package/dist/server/collections/orchestrator-logs.d.ts +1 -1
- package/dist/server/collections/skill-definitions.d.ts +2 -0
- package/dist/server/collections/skill-definitions.js +158 -0
- package/dist/server/collections/skill-executions.d.ts +2 -0
- package/dist/server/collections/skill-executions.js +123 -0
- package/dist/server/collections/skill-worker-configs.d.ts +2 -0
- package/dist/server/collections/skill-worker-configs.js +115 -0
- package/dist/server/migrations/20260423000000-add-progress-fields.d.ts +4 -0
- package/dist/server/migrations/20260423000000-add-progress-fields.js +69 -0
- package/dist/server/migrations/20260425000000-add-interaction-schema.d.ts +4 -0
- package/dist/server/migrations/20260425000000-add-interaction-schema.js +61 -0
- package/dist/server/migrations/20260427000000-change-packages-to-text.d.ts +4 -0
- package/dist/server/migrations/20260427000000-change-packages-to-text.js +70 -0
- package/dist/server/migrations/20260427000001-change-other-json-to-text.d.ts +4 -0
- package/dist/server/migrations/20260427000001-change-other-json-to-text.js +80 -0
- package/dist/server/migrations/20260429000000-add-llm-fields.js +8 -0
- package/dist/server/migrations/20260429000000-fix-inputargs-json-to-text.d.ts +16 -0
- package/dist/server/migrations/20260429000000-fix-inputargs-json-to-text.js +51 -0
- package/dist/server/migrations/20260503000000-add-orchestrator-trace-fields.d.ts +7 -0
- package/dist/server/migrations/20260503000000-add-orchestrator-trace-fields.js +57 -0
- package/dist/server/plugin.d.ts +3 -0
- package/dist/server/plugin.js +37 -1
- package/dist/server/resources/tracing.js +154 -11
- package/dist/server/services/CodeValidator.d.ts +32 -0
- package/dist/server/services/CodeValidator.js +206 -0
- package/dist/server/services/ExecutionSpanService.d.ts +44 -0
- package/dist/server/services/ExecutionSpanService.js +104 -0
- package/dist/server/services/FileManager.d.ts +28 -0
- package/dist/server/services/FileManager.js +151 -0
- package/dist/server/services/SandboxRunner.d.ts +41 -0
- package/dist/server/services/SandboxRunner.js +167 -0
- package/dist/server/services/SkillManager.d.ts +6 -0
- package/dist/server/services/SkillManager.js +640 -0
- package/dist/server/services/SkillRepositoryService.d.ts +22 -0
- package/dist/server/services/SkillRepositoryService.js +157 -0
- package/dist/server/services/WorkerEnvManager.d.ts +26 -0
- package/dist/server/services/WorkerEnvManager.js +120 -0
- package/dist/server/skill-hub/actions/git-import.d.ts +21 -0
- package/dist/server/skill-hub/actions/git-import.js +413 -0
- package/dist/server/skill-hub/mcp/McpController.d.ts +15 -0
- package/dist/server/skill-hub/mcp/McpController.js +111 -0
- package/dist/server/skill-hub/plugin.d.ts +58 -0
- package/dist/server/skill-hub/plugin.js +694 -0
- package/dist/server/skill-hub/sandbox-config.json +6 -0
- package/dist/server/skill-hub/tasks/SkillExecutionTask.d.ts +16 -0
- package/dist/server/skill-hub/tasks/SkillExecutionTask.js +389 -0
- package/dist/server/skill-hub/utils/json-fields.d.ts +7 -0
- package/dist/server/skill-hub/utils/json-fields.js +88 -0
- package/dist/server/tools/delegate-task.d.ts +4 -0
- package/dist/server/tools/delegate-task.js +606 -104
- package/dist/server/tools/skill-execute.d.ts +36 -0
- package/dist/server/tools/skill-execute.js +167 -0
- package/package.json +3 -1
- package/src/client/AIEmployeeSelect.tsx +1 -3
- package/src/client/AIEmployeesContext.tsx +28 -13
- package/src/client/OrchestratorSettings.tsx +43 -5
- package/src/client/RulesTab.tsx +253 -32
- package/src/client/TracingTab.tsx +277 -213
- package/src/client/index.tsx +1 -1
- package/src/client/plugin.tsx +54 -15
- package/src/client/skill-hub/components/ExecutionHistory.tsx +201 -0
- package/src/client/skill-hub/components/ExecutionProgress.tsx +55 -0
- package/src/client/skill-hub/components/GitSkillImport.tsx +555 -0
- package/src/client/skill-hub/components/SkillEditor.tsx +456 -0
- package/src/client/skill-hub/components/SkillManager.tsx +181 -0
- package/src/client/skill-hub/components/SkillMetrics.tsx +124 -0
- package/src/client/skill-hub/components/SkillTestPanel.tsx +144 -0
- package/src/client/skill-hub/index.tsx +75 -0
- package/src/client/skill-hub/locale.ts +16 -0
- package/src/client/skill-hub/tools/InteractionSchemasProvider.tsx +59 -0
- package/src/client/skill-hub/tools/SkillHubCard.tsx +78 -0
- package/src/client/skill-hub/utils/jsonFields.ts +37 -0
- package/src/server/collections/agent-execution-spans.ts +129 -0
- package/src/server/collections/orchestrator-config.ts +7 -0
- package/src/server/collections/skill-definitions.ts +128 -0
- package/src/server/collections/skill-executions.ts +94 -0
- package/src/server/collections/skill-worker-configs.ts +86 -0
- package/src/server/migrations/20260423000000-add-progress-fields.ts +50 -0
- package/src/server/migrations/20260425000000-add-interaction-schema.ts +35 -0
- package/src/server/migrations/20260427000000-add-tracing-detail-fields.ts +5 -5
- package/src/server/migrations/20260427000000-change-packages-to-text.ts +47 -0
- package/src/server/migrations/20260427000001-change-other-json-to-text.ts +57 -0
- package/src/server/migrations/20260429000000-add-llm-fields.ts +11 -2
- package/src/server/migrations/20260429000000-fix-inputargs-json-to-text.ts +38 -0
- package/src/server/migrations/20260503000000-add-orchestrator-trace-fields.ts +32 -0
- package/src/server/plugin.ts +94 -46
- package/src/server/resources/tracing.ts +182 -15
- package/src/server/services/CodeValidator.ts +159 -0
- package/src/server/services/ExecutionSpanService.ts +106 -0
- package/src/server/services/FileManager.ts +144 -0
- package/src/server/services/SandboxRunner.ts +205 -0
- package/src/server/services/SkillManager.ts +623 -0
- package/src/server/services/SkillRepositoryService.ts +142 -0
- package/src/server/services/WorkerEnvManager.ts +113 -0
- package/src/server/skill-hub/actions/git-import.ts +486 -0
- package/src/server/skill-hub/mcp/McpController.ts +86 -0
- package/src/server/skill-hub/plugin.ts +771 -0
- package/src/server/skill-hub/sandbox-config.json +6 -0
- package/src/server/skill-hub/tasks/SkillExecutionTask.ts +443 -0
- package/src/server/skill-hub/utils/json-fields.ts +57 -0
- package/src/server/tools/delegate-task.ts +803 -127
- 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 as any).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
|
+
`;
|