blockmine 1.21.0 → 1.23.0
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/.claude/agents/README.md +469 -0
- package/.claude/agents/auth-route-debugger.md +118 -0
- package/.claude/agents/auth-route-tester.md +93 -0
- package/.claude/agents/auto-error-resolver.md +97 -0
- package/.claude/agents/build-optimizer.md +236 -0
- package/.claude/agents/code-architecture-reviewer.md +83 -0
- package/.claude/agents/code-refactor-master.md +94 -0
- package/.claude/agents/cost-optimizer.md +134 -0
- package/.claude/agents/deployment-orchestrator.md +113 -0
- package/.claude/agents/documentation-architect.md +82 -0
- package/.claude/agents/frontend-error-fixer.md +77 -0
- package/.claude/agents/iac-code-generator.md +71 -0
- package/.claude/agents/incident-responder.md +346 -0
- package/.claude/agents/infrastructure-architect.md +31 -0
- package/.claude/agents/kubernetes-specialist.md +56 -0
- package/.claude/agents/migration-planner.md +181 -0
- package/.claude/agents/network-architect.md +196 -0
- package/.claude/agents/plan-reviewer.md +52 -0
- package/.claude/agents/refactor-planner.md +63 -0
- package/.claude/agents/security-scanner.md +102 -0
- package/.claude/agents/web-research-specialist.md +78 -0
- package/.claude/commands/cost-analysis.md +315 -0
- package/.claude/commands/dev-docs-update.md +55 -0
- package/.claude/commands/dev-docs.md +51 -0
- package/.claude/commands/incident-debug.md +247 -0
- package/.claude/commands/infra-plan.md +81 -0
- package/.claude/commands/migration-plan.md +478 -0
- package/.claude/commands/route-research-for-testing.md +37 -0
- package/.claude/commands/security-review.md +66 -0
- package/.claude/hooks/CONFIG.md +448 -0
- package/.claude/hooks/README.md +163 -0
- package/.claude/hooks/SKILL_ACTIVATION_COMPLETE.md +226 -0
- package/.claude/hooks/WINDOWS_HOOKS_README.md +151 -0
- package/.claude/hooks/add-skill-activation-banners.ts +132 -0
- package/.claude/hooks/comprehensive-skill-test.ts +1315 -0
- package/.claude/hooks/error-handling-reminder.sh +12 -0
- package/.claude/hooks/error-handling-reminder.ts +222 -0
- package/.claude/hooks/k8s-manifest-validator.sh +56 -0
- package/.claude/hooks/package-lock.json +556 -0
- package/.claude/hooks/package.json +16 -0
- package/.claude/hooks/post-tool-use-tracker.ps1 +174 -0
- package/.claude/hooks/post-tool-use-tracker.sh +183 -0
- package/.claude/hooks/security-policy-check.sh +247 -0
- package/.claude/hooks/skill-activation-prompt.ps1 +10 -0
- package/.claude/hooks/skill-activation-prompt.sh +10 -0
- package/.claude/hooks/skill-activation-prompt.ts +141 -0
- package/.claude/hooks/stop-build-check-enhanced.sh +130 -0
- package/.claude/hooks/terraform-validator.sh +53 -0
- package/.claude/hooks/test-input.json +7 -0
- package/.claude/hooks/test-skill-activation.ts +427 -0
- package/.claude/hooks/trigger-build-resolver.sh +79 -0
- package/.claude/hooks/tsc-check.sh +173 -0
- package/.claude/hooks/tsconfig.json +19 -0
- package/.claude/settings.json +59 -0
- package/.claude/settings.local.json +36 -14
- package/.claude/skills/README.md +507 -0
- package/.claude/skills/api-engineering/SKILL.md +63 -0
- package/.claude/skills/api-engineering/resources/api-versioning.md +88 -0
- package/.claude/skills/api-engineering/resources/graphql-patterns.md +106 -0
- package/.claude/skills/api-engineering/resources/rate-limiting.md +118 -0
- package/.claude/skills/api-engineering/resources/rest-api-design.md +105 -0
- package/.claude/skills/backend-dev-guidelines/SKILL.md +306 -0
- package/.claude/skills/backend-dev-guidelines/resources/architecture-overview.md +451 -0
- package/.claude/skills/backend-dev-guidelines/resources/async-and-errors.md +307 -0
- package/.claude/skills/backend-dev-guidelines/resources/complete-examples.md +638 -0
- package/.claude/skills/backend-dev-guidelines/resources/configuration.md +275 -0
- package/.claude/skills/backend-dev-guidelines/resources/database-patterns.md +224 -0
- package/.claude/skills/backend-dev-guidelines/resources/middleware-guide.md +213 -0
- package/.claude/skills/backend-dev-guidelines/resources/routing-and-controllers.md +756 -0
- package/.claude/skills/backend-dev-guidelines/resources/sentry-and-monitoring.md +336 -0
- package/.claude/skills/backend-dev-guidelines/resources/services-and-repositories.md +789 -0
- package/.claude/skills/backend-dev-guidelines/resources/testing-guide.md +235 -0
- package/.claude/skills/backend-dev-guidelines/resources/validation-patterns.md +754 -0
- package/.claude/skills/budget-and-cost-management/SKILL.md +850 -0
- package/.claude/skills/build-engineering/SKILL.md +431 -0
- package/.claude/skills/build-engineering/resources/artifact-repositories.md +72 -0
- package/.claude/skills/build-engineering/resources/build-caching.md +96 -0
- package/.claude/skills/build-engineering/resources/build-pipelines.md +105 -0
- package/.claude/skills/build-engineering/resources/build-security.md +95 -0
- package/.claude/skills/build-engineering/resources/build-systems.md +389 -0
- package/.claude/skills/build-engineering/resources/compilation-optimization.md +201 -0
- package/.claude/skills/build-engineering/resources/dependency-management.md +73 -0
- package/.claude/skills/build-engineering/resources/monorepo-builds.md +110 -0
- package/.claude/skills/build-engineering/resources/performance-optimization.md +113 -0
- package/.claude/skills/build-engineering/resources/reproducible-builds.md +82 -0
- package/.claude/skills/cloud-engineering/SKILL.md +675 -0
- package/.claude/skills/cloud-engineering/resources/aws-patterns.md +742 -0
- package/.claude/skills/cloud-engineering/resources/azure-patterns.md +714 -0
- package/.claude/skills/cloud-engineering/resources/cleared-cloud-environments.md +987 -0
- package/.claude/skills/cloud-engineering/resources/cloud-cost-optimization.md +757 -0
- package/.claude/skills/cloud-engineering/resources/cloud-networking.md +1058 -0
- package/.claude/skills/cloud-engineering/resources/cloud-security-tools.md +1530 -0
- package/.claude/skills/cloud-engineering/resources/cloud-security.md +990 -0
- package/.claude/skills/cloud-engineering/resources/gcp-patterns.md +758 -0
- package/.claude/skills/cloud-engineering/resources/migration-strategies.md +820 -0
- package/.claude/skills/cloud-engineering/resources/multi-cloud-strategies.md +670 -0
- package/.claude/skills/cloud-engineering/resources/oci-patterns.md +1198 -0
- package/.claude/skills/cloud-engineering/resources/serverless-patterns.md +795 -0
- package/.claude/skills/cloud-engineering/resources/well-architected-frameworks.md +966 -0
- package/.claude/skills/cybersecurity/SKILL.md +409 -0
- package/.claude/skills/cybersecurity/resources/security-architecture.md +266 -0
- package/.claude/skills/database-engineering/SKILL.md +61 -0
- package/.claude/skills/database-engineering/resources/backup-and-recovery.md +72 -0
- package/.claude/skills/database-engineering/resources/database-replication.md +63 -0
- package/.claude/skills/database-engineering/resources/postgresql-fundamentals.md +70 -0
- package/.claude/skills/database-engineering/resources/query-optimization.md +68 -0
- package/.claude/skills/devsecops/SKILL.md +374 -0
- package/.claude/skills/devsecops/resources/ci-cd-security.md +204 -0
- package/.claude/skills/devsecops/resources/compliance-automation.md +530 -0
- package/.claude/skills/devsecops/resources/compliance-frameworks.md +2322 -0
- package/.claude/skills/devsecops/resources/container-security.md +915 -0
- package/.claude/skills/devsecops/resources/cspm-integration.md +1440 -0
- package/.claude/skills/devsecops/resources/policy-enforcement.md +619 -0
- package/.claude/skills/devsecops/resources/secrets-management.md +755 -0
- package/.claude/skills/devsecops/resources/security-monitoring.md +146 -0
- package/.claude/skills/devsecops/resources/security-scanning.md +887 -0
- package/.claude/skills/devsecops/resources/security-testing.md +203 -0
- package/.claude/skills/devsecops/resources/supply-chain-security.md +518 -0
- package/.claude/skills/devsecops/resources/vulnerability-management.md +481 -0
- package/.claude/skills/devsecops/resources/zero-trust-architecture.md +177 -0
- package/.claude/skills/documentation-as-code/SKILL.md +323 -0
- package/.claude/skills/documentation-as-code/resources/api-documentation.md +90 -0
- package/.claude/skills/documentation-as-code/resources/changelog-management.md +79 -0
- package/.claude/skills/documentation-as-code/resources/diagram-generation.md +44 -0
- package/.claude/skills/documentation-as-code/resources/docs-as-code-workflow.md +99 -0
- package/.claude/skills/documentation-as-code/resources/documentation-automation.md +68 -0
- package/.claude/skills/documentation-as-code/resources/documentation-sites.md +79 -0
- package/.claude/skills/documentation-as-code/resources/markdown-best-practices.md +162 -0
- package/.claude/skills/documentation-as-code/resources/openapi-specification.md +77 -0
- package/.claude/skills/documentation-as-code/resources/readme-engineering.md +60 -0
- package/.claude/skills/documentation-as-code/resources/technical-writing-guide.md +202 -0
- package/.claude/skills/engineering-management/SKILL.md +356 -0
- package/.claude/skills/engineering-management/resources/career-ladders.md +609 -0
- package/.claude/skills/engineering-management/resources/hiring-and-assessment.md +555 -0
- package/.claude/skills/engineering-management/resources/one-on-one-guides.md +609 -0
- package/.claude/skills/engineering-management/resources/resource-planning.md +557 -0
- package/.claude/skills/engineering-management/resources/team-organization-patterns.md +491 -0
- package/.claude/skills/engineering-management/resources/technical-interviews.md +474 -0
- package/.claude/skills/engineering-operations-management/SKILL.md +817 -0
- package/.claude/skills/error-tracking/SKILL.md +379 -0
- package/.claude/skills/frontend-dev-guidelines/SKILL.md +403 -0
- package/.claude/skills/frontend-dev-guidelines/resources/common-patterns.md +331 -0
- package/.claude/skills/frontend-dev-guidelines/resources/complete-examples.md +872 -0
- package/.claude/skills/frontend-dev-guidelines/resources/component-patterns.md +502 -0
- package/.claude/skills/frontend-dev-guidelines/resources/data-fetching.md +767 -0
- package/.claude/skills/frontend-dev-guidelines/resources/file-organization.md +502 -0
- package/.claude/skills/frontend-dev-guidelines/resources/loading-and-error-states.md +501 -0
- package/.claude/skills/frontend-dev-guidelines/resources/performance.md +406 -0
- package/.claude/skills/frontend-dev-guidelines/resources/routing-guide.md +364 -0
- package/.claude/skills/frontend-dev-guidelines/resources/styling-guide.md +428 -0
- package/.claude/skills/frontend-dev-guidelines/resources/typescript-standards.md +418 -0
- package/.claude/skills/general-it-engineering/SKILL.md +393 -0
- package/.claude/skills/general-it-engineering/resources/asset-management.md +712 -0
- package/.claude/skills/general-it-engineering/resources/automation-orchestration.md +817 -0
- package/.claude/skills/general-it-engineering/resources/business-continuity.md +786 -0
- package/.claude/skills/general-it-engineering/resources/change-management.md +715 -0
- package/.claude/skills/general-it-engineering/resources/enterprise-monitoring.md +729 -0
- package/.claude/skills/general-it-engineering/resources/help-desk-operations.md +738 -0
- package/.claude/skills/general-it-engineering/resources/incident-service-management.md +834 -0
- package/.claude/skills/general-it-engineering/resources/it-governance.md +753 -0
- package/.claude/skills/general-it-engineering/resources/itil-framework.md +503 -0
- package/.claude/skills/general-it-engineering/resources/service-management.md +669 -0
- package/.claude/skills/infrastructure-architecture/SKILL.md +328 -0
- package/.claude/skills/infrastructure-architecture/resources/architecture-decision-records.md +505 -0
- package/.claude/skills/infrastructure-architecture/resources/architecture-patterns.md +528 -0
- package/.claude/skills/infrastructure-architecture/resources/capacity-planning.md +453 -0
- package/.claude/skills/infrastructure-architecture/resources/cleared-environment-architecture.md +773 -0
- package/.claude/skills/infrastructure-architecture/resources/cost-architecture.md +499 -0
- package/.claude/skills/infrastructure-architecture/resources/data-architecture.md +501 -0
- package/.claude/skills/infrastructure-architecture/resources/disaster-recovery.md +535 -0
- package/.claude/skills/infrastructure-architecture/resources/migration-architecture.md +512 -0
- package/.claude/skills/infrastructure-architecture/resources/multi-region-design.md +608 -0
- package/.claude/skills/infrastructure-architecture/resources/reference-architectures.md +562 -0
- package/.claude/skills/infrastructure-architecture/resources/security-architecture.md +538 -0
- package/.claude/skills/infrastructure-architecture/resources/system-design-principles.md +489 -0
- package/.claude/skills/infrastructure-architecture/resources/workload-classification.md +1000 -0
- package/.claude/skills/infrastructure-strategy/SKILL.md +924 -0
- package/.claude/skills/network-engineering/SKILL.md +385 -0
- package/.claude/skills/network-engineering/resources/dns-management.md +738 -0
- package/.claude/skills/network-engineering/resources/load-balancing.md +820 -0
- package/.claude/skills/network-engineering/resources/network-architecture.md +546 -0
- package/.claude/skills/network-engineering/resources/network-security.md +921 -0
- package/.claude/skills/network-engineering/resources/network-troubleshooting.md +749 -0
- package/.claude/skills/network-engineering/resources/routing-switching.md +373 -0
- package/.claude/skills/network-engineering/resources/sdn-networking.md +695 -0
- package/.claude/skills/network-engineering/resources/service-mesh-networking.md +777 -0
- package/.claude/skills/network-engineering/resources/tcp-ip-protocols.md +444 -0
- package/.claude/skills/network-engineering/resources/vpn-connectivity.md +672 -0
- package/.claude/skills/observability-engineering/SKILL.md +101 -0
- package/.claude/skills/observability-engineering/resources/apm-tools.md +97 -0
- package/.claude/skills/observability-engineering/resources/correlation-strategies.md +87 -0
- package/.claude/skills/observability-engineering/resources/distributed-tracing.md +98 -0
- package/.claude/skills/observability-engineering/resources/logs-aggregation.md +118 -0
- package/.claude/skills/observability-engineering/resources/observability-cost-optimization.md +141 -0
- package/.claude/skills/observability-engineering/resources/opentelemetry.md +110 -0
- package/.claude/skills/platform-engineering/SKILL.md +555 -0
- package/.claude/skills/platform-engineering/resources/architecture-overview.md +600 -0
- package/.claude/skills/platform-engineering/resources/container-orchestration.md +916 -0
- package/.claude/skills/platform-engineering/resources/cost-optimization.md +634 -0
- package/.claude/skills/platform-engineering/resources/developer-platforms.md +670 -0
- package/.claude/skills/platform-engineering/resources/gitops-automation.md +650 -0
- package/.claude/skills/platform-engineering/resources/infrastructure-as-code.md +778 -0
- package/.claude/skills/platform-engineering/resources/infrastructure-standards.md +708 -0
- package/.claude/skills/platform-engineering/resources/multi-tenancy.md +602 -0
- package/.claude/skills/platform-engineering/resources/platform-security.md +711 -0
- package/.claude/skills/platform-engineering/resources/resource-management.md +592 -0
- package/.claude/skills/platform-engineering/resources/service-mesh.md +628 -0
- package/.claude/skills/release-engineering/SKILL.md +393 -0
- package/.claude/skills/release-engineering/resources/artifact-management.md +108 -0
- package/.claude/skills/release-engineering/resources/build-optimization.md +84 -0
- package/.claude/skills/release-engineering/resources/ci-cd-pipelines.md +411 -0
- package/.claude/skills/release-engineering/resources/deployment-strategies.md +197 -0
- package/.claude/skills/release-engineering/resources/pipeline-security.md +62 -0
- package/.claude/skills/release-engineering/resources/progressive-delivery.md +83 -0
- package/.claude/skills/release-engineering/resources/release-automation.md +68 -0
- package/.claude/skills/release-engineering/resources/release-orchestration.md +77 -0
- package/.claude/skills/release-engineering/resources/rollback-strategies.md +66 -0
- package/.claude/skills/release-engineering/resources/versioning-strategies.md +59 -0
- package/.claude/skills/route-tester/SKILL.md +392 -0
- package/.claude/skills/skill-developer/ADVANCED.md +197 -0
- package/.claude/skills/skill-developer/HOOK_MECHANISMS.md +306 -0
- package/.claude/skills/skill-developer/PATTERNS_LIBRARY.md +152 -0
- package/.claude/skills/skill-developer/SKILL.md +430 -0
- package/.claude/skills/skill-developer/SKILL_RULES_REFERENCE.md +315 -0
- package/.claude/skills/skill-developer/TRIGGER_TYPES.md +305 -0
- package/.claude/skills/skill-developer/TROUBLESHOOTING.md +514 -0
- package/.claude/skills/skill-rules.json +2940 -0
- package/.claude/skills/sre/SKILL.md +464 -0
- package/.claude/skills/sre/resources/alerting-best-practices.md +282 -0
- package/.claude/skills/sre/resources/capacity-planning.md +226 -0
- package/.claude/skills/sre/resources/chaos-engineering.md +193 -0
- package/.claude/skills/sre/resources/disaster-recovery.md +232 -0
- package/.claude/skills/sre/resources/incident-management.md +436 -0
- package/.claude/skills/sre/resources/observability-stack.md +240 -0
- package/.claude/skills/sre/resources/on-call-runbooks.md +167 -0
- package/.claude/skills/sre/resources/performance-optimization.md +108 -0
- package/.claude/skills/sre/resources/reliability-patterns.md +183 -0
- package/.claude/skills/sre/resources/slo-sli-sla.md +464 -0
- package/.claude/skills/sre/resources/toil-reduction.md +145 -0
- package/.claude/skills/systems-engineering/SKILL.md +648 -0
- package/.claude/skills/systems-engineering/resources/automation-patterns.md +771 -0
- package/.claude/skills/systems-engineering/resources/configuration-management.md +998 -0
- package/.claude/skills/systems-engineering/resources/linux-administration.md +672 -0
- package/.claude/skills/systems-engineering/resources/networking-fundamentals.md +982 -0
- package/.claude/skills/systems-engineering/resources/performance-tuning.md +871 -0
- package/.claude/skills/systems-engineering/resources/powershell-scripting.md +482 -0
- package/.claude/skills/systems-engineering/resources/security-hardening.md +739 -0
- package/.claude/skills/systems-engineering/resources/shell-scripting.md +915 -0
- package/.claude/skills/systems-engineering/resources/storage-management.md +628 -0
- package/.claude/skills/systems-engineering/resources/system-monitoring.md +787 -0
- package/.claude/skills/systems-engineering/resources/troubleshooting-guide.md +753 -0
- package/.claude/skills/systems-engineering/resources/windows-administration.md +738 -0
- package/.claude/skills/technical-leadership/SKILL.md +728 -0
- package/CHANGELOG.md +102 -42
- package/CLAUDE.md +284 -0
- package/README.md +315 -71
- package/backend/docs/SECRETS_DOCUMENTATION.md +327 -0
- package/backend/jest.config.js +59 -0
- package/backend/package-lock.json +6801 -0
- package/backend/package.json +24 -4
- package/backend/prisma/migrations/20251026104609_add_websocket_api/migration.sql +33 -0
- package/backend/prisma/migrations/20251116111851_add_execution_trace/migration.sql +22 -0
- package/backend/prisma/migrations/20251120154914_add_panel_api_keys/migration.sql +21 -0
- package/backend/prisma/migrations/20251121110241_add_proxy_table/migration.sql +45 -0
- package/backend/prisma/migrations/migration_lock.toml +2 -2
- package/backend/prisma/schema.prisma +103 -1
- package/backend/src/__tests__/core/DependencyService.test.js +336 -0
- package/backend/src/__tests__/core/UserService.test.js +875 -0
- package/backend/src/__tests__/repositories/BaseRepository.test.js +146 -0
- package/backend/src/__tests__/repositories/BotRepository.test.js +118 -0
- package/backend/src/__tests__/repositories/CommandRepository.test.js +132 -0
- package/backend/src/__tests__/repositories/EventGraphRepository.test.js +93 -0
- package/backend/src/__tests__/repositories/GroupRepository.test.js +155 -0
- package/backend/src/__tests__/repositories/PermissionRepository.test.js +130 -0
- package/backend/src/__tests__/repositories/PluginRepository.test.js +107 -0
- package/backend/src/__tests__/repositories/ServerRepository.test.js +80 -0
- package/backend/src/__tests__/repositories/UserRepository.test.js +128 -0
- package/backend/src/__tests__/secretsFilter.test.js +425 -0
- package/backend/src/__tests__/services/BotLifecycleService.test.js +416 -0
- package/backend/src/__tests__/services/BotProcessManager.test.js +285 -0
- package/backend/src/__tests__/services/CacheManager.test.js +125 -0
- package/backend/src/__tests__/services/CommandExecutionService.test.js +460 -0
- package/backend/src/__tests__/services/ResourceMonitorService.test.js +207 -0
- package/backend/src/__tests__/services/TelemetryService.test.js +291 -0
- package/backend/src/__tests__/setup.js +25 -0
- package/backend/src/ai/plugin-assistant-system-prompt.md +788 -0
- package/backend/src/api/middleware/auth.js +27 -0
- package/backend/src/api/middleware/botAccess.js +7 -3
- package/backend/src/api/middleware/panelApiAuth.js +135 -0
- package/backend/src/api/routes/aiAssistant.js +995 -0
- package/backend/src/api/routes/apiKeys.js +181 -0
- package/backend/src/api/routes/auth.js +669 -633
- package/backend/src/api/routes/botCommands.js +107 -0
- package/backend/src/api/routes/botGroups.js +165 -0
- package/backend/src/api/routes/botHistory.js +108 -0
- package/backend/src/api/routes/botPermissions.js +99 -0
- package/backend/src/api/routes/botStatus.js +36 -0
- package/backend/src/api/routes/botUsers.js +162 -0
- package/backend/src/api/routes/bots.js +2451 -2360
- package/backend/src/api/routes/eventGraphs.js +4 -1
- package/backend/src/api/routes/logs.js +13 -3
- package/backend/src/api/routes/panel.js +66 -66
- package/backend/src/api/routes/panelApiKeys.js +179 -0
- package/backend/src/api/routes/pluginIde.js +1715 -135
- package/backend/src/api/routes/plugins.js +376 -218
- package/backend/src/api/routes/proxies.js +130 -0
- package/backend/src/api/routes/search.js +4 -0
- package/backend/src/api/routes/servers.js +20 -3
- package/backend/src/api/routes/settings.js +5 -0
- package/backend/src/api/routes/system.js +174 -0
- package/backend/src/api/routes/traces.js +131 -0
- package/backend/src/config/debug.config.js +36 -0
- package/backend/src/container.js +82 -0
- package/backend/src/core/BotHistoryStore.js +180 -0
- package/backend/src/core/BotManager.js +149 -868
- package/backend/src/core/BotManager.old.js +1093 -0
- package/backend/src/core/BotProcess.js +850 -191
- package/backend/src/core/EventGraphManager.js +194 -198
- package/backend/src/core/GraphExecutionEngine.js +709 -57
- package/backend/src/core/MessageQueue.js +39 -12
- package/backend/src/core/NodeRegistry.js +37 -1134
- package/backend/src/core/PluginLoader.js +99 -5
- package/backend/src/core/PluginManager.js +126 -15
- package/backend/src/core/PrismaService.js +32 -0
- package/backend/src/core/TaskScheduler.js +1 -1
- package/backend/src/core/UserService.js +3 -3
- package/backend/src/core/__tests__/PrismaService.test.js +24 -0
- package/backend/src/core/commands/README.md +305 -0
- package/backend/src/core/commands/dev.js +13 -7
- package/backend/src/core/commands/ping.js +10 -4
- package/backend/src/core/commands/whois.js +63 -0
- package/backend/src/core/config/validation.js +27 -0
- package/backend/src/core/constants/graphTypes.js +21 -0
- package/backend/src/core/node-registries/actions.js +202 -0
- package/backend/src/core/node-registries/arrays.js +155 -0
- package/backend/src/core/node-registries/bot.js +23 -0
- package/backend/src/core/node-registries/data.js +290 -0
- package/backend/src/core/node-registries/debug.js +26 -0
- package/backend/src/core/node-registries/events.js +201 -0
- package/backend/src/core/node-registries/flow.js +139 -0
- package/backend/src/core/node-registries/logic.js +62 -0
- package/backend/src/core/node-registries/math.js +42 -0
- package/backend/src/core/node-registries/objects.js +98 -0
- package/backend/src/core/node-registries/strings.js +187 -0
- package/backend/src/core/node-registries/time.js +113 -0
- package/backend/src/core/node-registries/type.js +25 -0
- package/backend/src/core/node-registries/users.js +79 -0
- package/backend/src/core/nodes/{action_bot_look_at.js → actions/bot_look_at.js} +36 -36
- package/backend/src/core/nodes/{action_bot_set_variable.js → actions/bot_set_variable.js} +32 -32
- package/backend/src/core/nodes/actions/create_command.js +189 -0
- package/backend/src/core/nodes/actions/delete_command.js +92 -0
- package/backend/src/core/nodes/{action_send_log.js → actions/send_log.js} +28 -23
- package/backend/src/core/nodes/{action_send_message.js → actions/send_message.js} +32 -32
- package/backend/src/core/nodes/actions/send_websocket_response.js +33 -0
- package/backend/src/core/nodes/actions/update_command.js +133 -0
- package/backend/src/core/nodes/arrays/get_next.js +35 -0
- package/backend/src/core/nodes/arrays/join.js +28 -0
- package/backend/src/core/nodes/{data_cast.js → data/cast.js} +10 -1
- package/backend/src/core/nodes/data/datetime_literal.js +27 -0
- package/backend/src/core/nodes/data/entity_info.js +69 -0
- package/backend/src/core/nodes/data/get_nearby_entities.js +32 -0
- package/backend/src/core/nodes/data/get_nearby_players.js +64 -0
- package/backend/src/core/nodes/{data_get_user_field.js → data/get_user_field.js} +1 -1
- package/backend/src/core/nodes/data/type_check.js +53 -0
- package/backend/src/core/nodes/{debug_log.js → debug/log.js} +16 -16
- package/backend/src/core/nodes/{flow_branch.js → flow/branch.js} +15 -15
- package/backend/src/core/nodes/{flow_break.js → flow/break.js} +14 -14
- package/backend/src/core/nodes/flow/delay.js +43 -0
- package/backend/src/core/nodes/{flow_for_each.js → flow/for_each.js} +39 -39
- package/backend/src/core/nodes/{flow_sequence.js → flow/sequence.js} +16 -16
- package/backend/src/core/nodes/{flow_switch.js → flow/switch.js} +47 -47
- package/backend/src/core/nodes/{flow_while.js → flow/while.js} +1 -1
- package/backend/src/core/nodes/logic/__tests__/compare.test.js +83 -0
- package/backend/src/core/nodes/logic/not.js +22 -0
- package/backend/src/core/nodes/math/__tests__/operation.test.js +65 -0
- package/backend/src/core/nodes/strings/__tests__/concat.test.js +89 -0
- package/backend/src/core/nodes/{string_starts_with.js → strings/starts_with.js} +1 -1
- package/backend/src/core/nodes/strings/to_lower.js +22 -0
- package/backend/src/core/nodes/strings/to_upper.js +22 -0
- package/backend/src/core/nodes/time/__tests__/now.test.js +24 -0
- package/backend/src/core/nodes/time/add.js +33 -0
- package/backend/src/core/nodes/time/compare.js +35 -0
- package/backend/src/core/nodes/time/diff.js +29 -0
- package/backend/src/core/nodes/time/format.js +32 -0
- package/backend/src/core/nodes/time/now.js +18 -0
- package/backend/src/core/nodes/type/to_string.js +32 -0
- package/backend/src/core/nodes/{user_check_blacklist.js → users/check_blacklist.js} +37 -37
- package/backend/src/core/nodes/{user_get_groups.js → users/get_groups.js} +36 -36
- package/backend/src/core/nodes/{user_get_permissions.js → users/get_permissions.js} +36 -36
- package/backend/src/core/nodes/{user_set_blacklist.js → users/set_blacklist.js} +37 -37
- package/backend/src/core/services/BotLifecycleService.js +835 -0
- package/backend/src/core/services/BotProcessManager.js +163 -0
- package/backend/src/core/services/CacheManager.js +111 -0
- package/backend/src/core/services/CommandExecutionService.js +430 -0
- package/backend/src/core/services/DebugSessionManager.js +347 -0
- package/backend/src/core/services/GraphCollaborationManager.js +501 -0
- package/backend/src/core/services/MinecraftBotManager.js +259 -0
- package/backend/src/core/services/MinecraftViewerService.js +216 -0
- package/backend/src/core/services/ResourceMonitorService.js +90 -0
- package/backend/src/core/services/TelemetryService.js +124 -0
- package/backend/src/core/services/TraceCollectorService.js +545 -0
- package/backend/src/core/services/ValidationService.js +132 -0
- package/backend/src/core/services/__tests__/ValidationService.test.js +148 -0
- package/backend/src/core/services.js +20 -5
- package/backend/src/core/system/CommandContext.js +84 -0
- package/backend/src/core/system/RuntimeCommandRegistry.js +116 -0
- package/backend/src/core/system/Transport.js +74 -0
- package/backend/src/core/utils/__tests__/jsonParser.test.js +44 -0
- package/backend/src/core/utils/jsonParser.js +18 -0
- package/backend/src/core/utils/secretsFilter.js +262 -0
- package/backend/src/core/utils/variableParser.js +89 -0
- package/backend/src/core/validation/__tests__/nodeSchemas.test.js +175 -0
- package/backend/src/core/validation/nodeSchemas.js +112 -0
- package/backend/src/lib/prisma.js +2 -4
- package/backend/src/real-time/botApi/handlers/commandHandlers.js +28 -0
- package/backend/src/real-time/botApi/handlers/graphHandlers.js +99 -0
- package/backend/src/real-time/botApi/handlers/graphWebSocketHandlers.js +147 -0
- package/backend/src/real-time/botApi/handlers/index.js +43 -0
- package/backend/src/real-time/botApi/handlers/messageHandlers.js +66 -0
- package/backend/src/real-time/botApi/handlers/statusHandlers.js +17 -0
- package/backend/src/real-time/botApi/handlers/userHandlers.js +141 -0
- package/backend/src/real-time/botApi/index.js +40 -0
- package/backend/src/real-time/botApi/middleware.js +79 -0
- package/backend/src/real-time/botApi/utils.js +65 -0
- package/backend/src/real-time/panelNamespace.js +387 -0
- package/backend/src/real-time/presence.js +7 -2
- package/backend/src/real-time/socketHandler.js +400 -5
- package/backend/src/repositories/BaseRepository.js +43 -0
- package/backend/src/repositories/BotRepository.js +42 -0
- package/backend/src/repositories/CommandRepository.js +53 -0
- package/backend/src/repositories/EventGraphRepository.js +40 -0
- package/backend/src/repositories/GroupRepository.js +69 -0
- package/backend/src/repositories/PermissionRepository.js +48 -0
- package/backend/src/repositories/PluginRepository.js +42 -0
- package/backend/src/repositories/ServerRepository.js +27 -0
- package/backend/src/repositories/UserRepository.js +48 -0
- package/backend/src/server.js +21 -0
- package/backend/src/test-refactor.js +85 -0
- package/frontend/dist/assets/index-B1serztM.js +11210 -0
- package/frontend/dist/assets/index-t6K1u4OV.css +32 -0
- package/frontend/dist/index.html +2 -2
- package/frontend/package-lock.json +9437 -0
- package/frontend/package.json +8 -5
- package/package.json +3 -2
- package/screen/console.png +0 -0
- package/screen/dashboard.png +0 -0
- package/screen/graph_collabe.png +0 -0
- package/screen/graph_live_debug.png +0 -0
- package/screen/management_command.png +0 -0
- package/screen/node_debug_trace.png +0 -0
- package/screen/plugin_/320/276/320/261/320/267/320/276/321/200.png +0 -0
- package/screen/websocket.png +0 -0
- package/screen//320/275/320/260/321/201/321/202/321/200/320/276/320/271/320/272/320/270_/320/276/321/202/320/264/320/265/320/273/321/214/320/275/321/213/321/205_/320/272/320/276/320/274/320/260/320/275/320/264_/320/272/320/260/320/266/320/264/321/203_/320/272/320/276/320/274/320/260/320/275/320/273/320/264/321/203_/320/274/320/276/320/266/320/275/320/276_/320/275/320/260/321/201/321/202/321/200/320/260/320/270/320/262/320/260/321/202/321/214.png +0 -0
- package/screen//320/277/320/273/320/260/320/275/320/270/321/200/320/276/320/262/321/211/320/270/320/272_/320/274/320/276/320/266/320/275/320/276_/320/267/320/260/320/264/320/260/320/262/320/260/321/202/321/214_/320/264/320/265/320/271/321/201/321/202/320/262/320/270/321/217_/320/277/320/276_/320/262/321/200/320/265/320/274/320/265/320/275/320/270.png +0 -0
- package/frontend/dist/assets/index-B9GedHEa.js +0 -8352
- package/frontend/dist/assets/index-zLiy9MDx.css +0 -1
- package/nul +0 -0
- /package/backend/src/core/nodes/{action_http_request.js → actions/http_request.js} +0 -0
- /package/backend/src/core/nodes/{array_add_element.js → arrays/add_element.js} +0 -0
- /package/backend/src/core/nodes/{array_contains.js → arrays/contains.js} +0 -0
- /package/backend/src/core/nodes/{array_find_index.js → arrays/find_index.js} +0 -0
- /package/backend/src/core/nodes/{array_get_by_index.js → arrays/get_by_index.js} +0 -0
- /package/backend/src/core/nodes/{array_get_random_element.js → arrays/get_random_element.js} +0 -0
- /package/backend/src/core/nodes/{array_remove_by_index.js → arrays/remove_by_index.js} +0 -0
- /package/backend/src/core/nodes/{bot_get_position.js → bot/get_position.js} +0 -0
- /package/backend/src/core/nodes/{data_array_literal.js → data/array_literal.js} +0 -0
- /package/backend/src/core/nodes/{data_boolean_literal.js → data/boolean_literal.js} +0 -0
- /package/backend/src/core/nodes/{data_get_argument.js → data/get_argument.js} +0 -0
- /package/backend/src/core/nodes/{data_get_bot_look.js → data/get_bot_look.js} +0 -0
- /package/backend/src/core/nodes/{data_get_entity_field.js → data/get_entity_field.js} +0 -0
- /package/backend/src/core/nodes/{data_get_server_players.js → data/get_server_players.js} +0 -0
- /package/backend/src/core/nodes/{data_get_variable.js → data/get_variable.js} +0 -0
- /package/backend/src/core/nodes/{data_length.js → data/length.js} +0 -0
- /package/backend/src/core/nodes/{data_make_object.js → data/make_object.js} +0 -0
- /package/backend/src/core/nodes/{data_number_literal.js → data/number_literal.js} +0 -0
- /package/backend/src/core/nodes/{data_string_literal.js → data/string_literal.js} +0 -0
- /package/backend/src/core/nodes/{logic_compare.js → logic/compare.js} +0 -0
- /package/backend/src/core/nodes/{logic_operation.js → logic/operation.js} +0 -0
- /package/backend/src/core/nodes/{math_operation.js → math/operation.js} +0 -0
- /package/backend/src/core/nodes/{math_random_number.js → math/random_number.js} +0 -0
- /package/backend/src/core/nodes/{object_create.js → objects/create.js} +0 -0
- /package/backend/src/core/nodes/{object_delete.js → objects/delete.js} +0 -0
- /package/backend/src/core/nodes/{object_get.js → objects/get.js} +0 -0
- /package/backend/src/core/nodes/{object_has_key.js → objects/has_key.js} +0 -0
- /package/backend/src/core/nodes/{object_set.js → objects/set.js} +0 -0
- /package/backend/src/core/nodes/{string_concat.js → strings/concat.js} +0 -0
- /package/backend/src/core/nodes/{string_contains.js → strings/contains.js} +0 -0
- /package/backend/src/core/nodes/{string_ends_with.js → strings/ends_with.js} +0 -0
- /package/backend/src/core/nodes/{string_equals.js → strings/equals.js} +0 -0
- /package/backend/src/core/nodes/{string_length.js → strings/length.js} +0 -0
- /package/backend/src/core/nodes/{string_matches.js → strings/matches.js} +0 -0
- /package/backend/src/core/nodes/{string_split.js → strings/split.js} +0 -0
|
@@ -1,9 +1,20 @@
|
|
|
1
|
-
const
|
|
2
|
-
const
|
|
1
|
+
const prismaService = require('./PrismaService');
|
|
2
|
+
const { parseVariables } = require('./utils/variableParser');
|
|
3
|
+
const validationService = require('./services/ValidationService');
|
|
4
|
+
const { MAX_RECURSION_DEPTH } = require('./config/validation');
|
|
5
|
+
const debugConfig = require('../config/debug.config');
|
|
6
|
+
const prisma = prismaService.getClient();
|
|
3
7
|
|
|
4
8
|
const BreakLoopSignal = require('./BreakLoopSignal');
|
|
9
|
+
const { getTraceCollector } = require('./services/TraceCollectorService');
|
|
10
|
+
const { getGlobalDebugManager } = require('./services/DebugSessionManager');
|
|
5
11
|
|
|
6
12
|
class GraphExecutionEngine {
|
|
13
|
+
// Static флаг для предотвращения дублирования IPC handler
|
|
14
|
+
static _ipcHandlerAttached = false;
|
|
15
|
+
// Static Map для хранения всех pending requests из всех instances
|
|
16
|
+
static _allPendingRequests = new Map();
|
|
17
|
+
|
|
7
18
|
constructor(nodeRegistry, botManagerOrApi = null) {
|
|
8
19
|
if (!nodeRegistry || typeof nodeRegistry.getNodeConfig !== 'function') {
|
|
9
20
|
throw new Error('GraphExecutionEngine requires a valid NodeRegistry instance.');
|
|
@@ -13,55 +24,56 @@ class GraphExecutionEngine {
|
|
|
13
24
|
this.activeGraph = null;
|
|
14
25
|
this.context = null;
|
|
15
26
|
this.memo = new Map();
|
|
27
|
+
this.traceCollector = getTraceCollector();
|
|
28
|
+
this.currentTraceId = null;
|
|
29
|
+
|
|
30
|
+
// Используем статическую Map для всех instance
|
|
31
|
+
this.pendingDebugRequests = GraphExecutionEngine._allPendingRequests;
|
|
32
|
+
|
|
33
|
+
if (process.on && !GraphExecutionEngine._ipcHandlerAttached) {
|
|
34
|
+
process.on('message', (message) => {
|
|
35
|
+
if (message.type === 'debug:breakpoint_response' || message.type === 'debug:step_response') {
|
|
36
|
+
GraphExecutionEngine._handleGlobalDebugResponse(message);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
GraphExecutionEngine._ipcHandlerAttached = true;
|
|
40
|
+
}
|
|
16
41
|
}
|
|
17
42
|
|
|
18
43
|
async execute(graph, context, eventType) {
|
|
19
44
|
if (!graph || graph === 'null') return context;
|
|
20
45
|
|
|
21
|
-
|
|
22
|
-
if (
|
|
23
|
-
|
|
24
|
-
parsedGraph = JSON.parse(graph);
|
|
25
|
-
} catch (e) {
|
|
26
|
-
console.error('[GraphExecutionEngine] Ошибка парсинга JSON графа:', e);
|
|
27
|
-
return context;
|
|
28
|
-
}
|
|
29
|
-
} else {
|
|
30
|
-
parsedGraph = graph;
|
|
46
|
+
const parsedGraph = validationService.parseGraph(graph, 'GraphExecutionEngine.execute');
|
|
47
|
+
if (!parsedGraph) {
|
|
48
|
+
return context;
|
|
31
49
|
}
|
|
32
50
|
|
|
33
|
-
|
|
34
|
-
|
|
51
|
+
const validation = validationService.validateGraphStructure(parsedGraph, 'GraphExecutionEngine');
|
|
52
|
+
if (validation.shouldSkip) {
|
|
35
53
|
return context;
|
|
36
54
|
}
|
|
37
55
|
|
|
56
|
+
const graphId = context.graphId || null;
|
|
57
|
+
const botId = context.botId || null;
|
|
58
|
+
|
|
59
|
+
if (graphId && botId) {
|
|
60
|
+
this.currentTraceId = await this.traceCollector.startTrace(
|
|
61
|
+
botId,
|
|
62
|
+
graphId,
|
|
63
|
+
eventType || 'command',
|
|
64
|
+
context.eventArgs || {}
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
38
68
|
try {
|
|
39
69
|
this.activeGraph = parsedGraph;
|
|
40
70
|
this.context = context;
|
|
41
|
-
|
|
71
|
+
|
|
42
72
|
if (!this.context.variables) {
|
|
43
|
-
this.context.variables =
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
try {
|
|
48
|
-
switch(variable.type) {
|
|
49
|
-
case 'number':
|
|
50
|
-
value = Number(value);
|
|
51
|
-
break;
|
|
52
|
-
case 'boolean':
|
|
53
|
-
value = value === 'true';
|
|
54
|
-
break;
|
|
55
|
-
case 'array':
|
|
56
|
-
value = JSON.parse(value);
|
|
57
|
-
break;
|
|
58
|
-
}
|
|
59
|
-
} catch (e) {
|
|
60
|
-
console.error(`Error parsing variable default value for ${variable.name}:`, e);
|
|
61
|
-
}
|
|
62
|
-
this.context.variables[variable.name] = value;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
73
|
+
this.context.variables = parseVariables(
|
|
74
|
+
this.activeGraph.variables,
|
|
75
|
+
'GraphExecutionEngine'
|
|
76
|
+
);
|
|
65
77
|
}
|
|
66
78
|
|
|
67
79
|
if (!this.context.persistenceIntent) this.context.persistenceIntent = new Map();
|
|
@@ -71,12 +83,86 @@ class GraphExecutionEngine {
|
|
|
71
83
|
const startNode = this.activeGraph.nodes.find(n => n.type === `event:${eventName}`);
|
|
72
84
|
|
|
73
85
|
if (startNode) {
|
|
86
|
+
if (this.currentTraceId) {
|
|
87
|
+
this.traceCollector.recordStep(this.currentTraceId, {
|
|
88
|
+
nodeId: startNode.id,
|
|
89
|
+
nodeType: startNode.type,
|
|
90
|
+
status: 'executed',
|
|
91
|
+
duration: 0,
|
|
92
|
+
inputs: {},
|
|
93
|
+
outputs: await this._captureNodeOutputs(startNode),
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
74
97
|
await this.traverse(startNode, 'exec');
|
|
75
98
|
} else if (!eventType) {
|
|
76
99
|
throw new Error(`Не найдена стартовая нода события (event:command) в графе.`);
|
|
77
100
|
}
|
|
78
101
|
|
|
102
|
+
if (this.currentTraceId) {
|
|
103
|
+
// Перед завершением trace, захватываем outputs для всех data-нод
|
|
104
|
+
await this._captureAllDataNodeOutputs();
|
|
105
|
+
|
|
106
|
+
const trace = await this.traceCollector.completeTrace(this.currentTraceId);
|
|
107
|
+
|
|
108
|
+
// Если работаем в дочернем процессе (BotProcess), отправляем трассировку в главный процесс
|
|
109
|
+
if (trace && process.send) {
|
|
110
|
+
process.send({
|
|
111
|
+
type: 'trace:completed',
|
|
112
|
+
trace: {
|
|
113
|
+
...trace,
|
|
114
|
+
steps: trace.steps,
|
|
115
|
+
eventArgs: typeof trace.eventArgs === 'string' ? trace.eventArgs : JSON.stringify(trace.eventArgs)
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Отправляем debug событие только если DebugSessionManager инициализирован
|
|
121
|
+
// (он может быть не инициализирован в дочерних процессах BotProcess)
|
|
122
|
+
if (graphId) {
|
|
123
|
+
try {
|
|
124
|
+
const debugManager = getGlobalDebugManager();
|
|
125
|
+
const debugState = debugManager.get(graphId);
|
|
126
|
+
if (debugState && debugState.activeExecution) {
|
|
127
|
+
debugState.broadcast('debug:completed', {
|
|
128
|
+
trace: await this.traceCollector.getTrace(this.currentTraceId)
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
} catch (error) {
|
|
132
|
+
// DebugSessionManager не инициализирован - это нормально для дочерних процессов
|
|
133
|
+
// Просто игнорируем
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
this.currentTraceId = null;
|
|
138
|
+
}
|
|
139
|
+
|
|
79
140
|
} catch (error) {
|
|
141
|
+
if (this.currentTraceId) {
|
|
142
|
+
// Даже при ошибке захватываем outputs для data-нод
|
|
143
|
+
try {
|
|
144
|
+
await this._captureAllDataNodeOutputs();
|
|
145
|
+
} catch (captureError) {
|
|
146
|
+
console.error(`[GraphExecutor] Error capturing outputs on failure:`, captureError);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const trace = await this.traceCollector.failTrace(this.currentTraceId, error);
|
|
150
|
+
|
|
151
|
+
// Если работаем в дочернем процессе (BotProcess), отправляем трассировку с ошибкой в главный процесс
|
|
152
|
+
if (trace && process.send) {
|
|
153
|
+
process.send({
|
|
154
|
+
type: 'trace:completed',
|
|
155
|
+
trace: {
|
|
156
|
+
...trace,
|
|
157
|
+
steps: trace.steps,
|
|
158
|
+
eventArgs: typeof trace.eventArgs === 'string' ? trace.eventArgs : JSON.stringify(trace.eventArgs)
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
this.currentTraceId = null;
|
|
164
|
+
}
|
|
165
|
+
|
|
80
166
|
if (!(error instanceof BreakLoopSignal)) {
|
|
81
167
|
console.error(`[GraphExecutionEngine] Критическая ошибка выполнения графа: ${error.stack}`);
|
|
82
168
|
}
|
|
@@ -92,10 +178,39 @@ class GraphExecutionEngine {
|
|
|
92
178
|
const nextNode = this.activeGraph.nodes.find(n => n.id === connection.targetNodeId);
|
|
93
179
|
if (!nextNode) return;
|
|
94
180
|
|
|
181
|
+
if (this.currentTraceId) {
|
|
182
|
+
this.traceCollector.recordTraversal(
|
|
183
|
+
this.currentTraceId,
|
|
184
|
+
node.id,
|
|
185
|
+
fromPinId,
|
|
186
|
+
nextNode.id
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
|
|
95
190
|
await this.executeNode(nextNode);
|
|
96
191
|
}
|
|
97
192
|
|
|
98
193
|
async executeNode(node) {
|
|
194
|
+
const startTime = Date.now();
|
|
195
|
+
|
|
196
|
+
// Записываем шаг ДО проверки брейкпоинта, чтобы в trace были данные о предыдущих нодах
|
|
197
|
+
if (this.currentTraceId) {
|
|
198
|
+
this.traceCollector.recordStep(this.currentTraceId, {
|
|
199
|
+
nodeId: node.id,
|
|
200
|
+
nodeType: node.type,
|
|
201
|
+
status: 'executed',
|
|
202
|
+
duration: null,
|
|
203
|
+
inputs: await this._captureNodeInputs(node),
|
|
204
|
+
outputs: {},
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Проверка брейкпоинта ПЕРЕД выполнением (но ПОСЛЕ записи в trace)
|
|
209
|
+
await this.checkBreakpoint(node);
|
|
210
|
+
|
|
211
|
+
// Проверка step mode ПЕРЕД выполнением (важно делать ДО executor, чтобы поймать ноду до traverse)
|
|
212
|
+
await this._checkStepMode(node);
|
|
213
|
+
|
|
99
214
|
const nodeConfig = this.nodeRegistry.getNodeConfig(node.type);
|
|
100
215
|
if (nodeConfig && typeof nodeConfig.executor === 'function') {
|
|
101
216
|
const helpers = {
|
|
@@ -104,7 +219,28 @@ class GraphExecutionEngine {
|
|
|
104
219
|
memo: this.memo,
|
|
105
220
|
clearLoopBodyMemo: this.clearLoopBodyMemo.bind(this),
|
|
106
221
|
};
|
|
107
|
-
|
|
222
|
+
|
|
223
|
+
try {
|
|
224
|
+
await nodeConfig.executor.call(this, node, this.context, helpers);
|
|
225
|
+
|
|
226
|
+
const executionTime = Date.now() - startTime;
|
|
227
|
+
|
|
228
|
+
if (this.currentTraceId) {
|
|
229
|
+
this.traceCollector.updateStepOutputs(this.currentTraceId, node.id, await this._captureNodeOutputs(node));
|
|
230
|
+
this.traceCollector.updateStepDuration(this.currentTraceId, node.id, executionTime);
|
|
231
|
+
}
|
|
232
|
+
} catch (error) {
|
|
233
|
+
if (this.currentTraceId) {
|
|
234
|
+
this.traceCollector.updateStepError(
|
|
235
|
+
this.currentTraceId,
|
|
236
|
+
node.id,
|
|
237
|
+
error.message,
|
|
238
|
+
Date.now() - startTime
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
throw error;
|
|
242
|
+
}
|
|
243
|
+
|
|
108
244
|
return;
|
|
109
245
|
}
|
|
110
246
|
|
|
@@ -114,6 +250,120 @@ class GraphExecutionEngine {
|
|
|
114
250
|
}
|
|
115
251
|
this.memo.set(execCacheKey, true);
|
|
116
252
|
|
|
253
|
+
try {
|
|
254
|
+
await this._executeLegacyNode(node);
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
const executionTime = Date.now() - startTime;
|
|
258
|
+
|
|
259
|
+
if (this.currentTraceId) {
|
|
260
|
+
this.traceCollector.updateStepOutputs(this.currentTraceId, node.id, await this._captureNodeOutputs(node));
|
|
261
|
+
this.traceCollector.updateStepDuration(this.currentTraceId, node.id, executionTime);
|
|
262
|
+
}
|
|
263
|
+
} catch (error) {
|
|
264
|
+
if (this.currentTraceId) {
|
|
265
|
+
this.traceCollector.updateStepError(
|
|
266
|
+
this.currentTraceId,
|
|
267
|
+
node.id,
|
|
268
|
+
error.message,
|
|
269
|
+
Date.now() - startTime
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
throw error;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
async _checkStepMode(node) {
|
|
277
|
+
try {
|
|
278
|
+
// Если работаем в дочернем процессе, используем IPC
|
|
279
|
+
if (process.send) {
|
|
280
|
+
return await this._checkStepModeViaIpc(node);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Иначе используем прямой доступ к DebugManager
|
|
284
|
+
const { getGlobalDebugManager } = require('./services/DebugSessionManager');
|
|
285
|
+
const debugManager = getGlobalDebugManager();
|
|
286
|
+
const graphId = this.activeGraph?.id;
|
|
287
|
+
|
|
288
|
+
if (graphId) {
|
|
289
|
+
const debugState = debugManager.get(graphId);
|
|
290
|
+
if (debugState && debugState.shouldStepPause(node.id)) {
|
|
291
|
+
console.log(`[Debug] Step mode: pausing after executing node ${node.id}`);
|
|
292
|
+
|
|
293
|
+
// Получаем inputs для отправки в debug session
|
|
294
|
+
const inputs = await this._captureNodeInputs(node);
|
|
295
|
+
|
|
296
|
+
// Получаем текущую трассировку для отображения выполненных шагов
|
|
297
|
+
const executedSteps = this.currentTraceId
|
|
298
|
+
? await this.traceCollector.getTrace(this.currentTraceId)
|
|
299
|
+
: null;
|
|
300
|
+
|
|
301
|
+
// Паузим выполнение
|
|
302
|
+
await debugState.pause({
|
|
303
|
+
nodeId: node.id,
|
|
304
|
+
nodeType: node.type,
|
|
305
|
+
inputs,
|
|
306
|
+
executedSteps,
|
|
307
|
+
context: {
|
|
308
|
+
user: this.context.user,
|
|
309
|
+
variables: this.context.variables,
|
|
310
|
+
commandArguments: this.context.commandArguments,
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
} catch (error) {
|
|
316
|
+
if (error.message !== 'DebugSessionManager not initialized! Call initializeDebugManager(io) first.') {
|
|
317
|
+
throw error;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
async _checkStepModeViaIpc(node) {
|
|
323
|
+
// Step mode работает аналогично breakpoint, просто отправляем тип 'step'
|
|
324
|
+
const { randomUUID } = require('crypto');
|
|
325
|
+
const requestId = randomUUID();
|
|
326
|
+
|
|
327
|
+
const inputs = await this._captureNodeInputs(node);
|
|
328
|
+
const executedSteps = this.currentTraceId
|
|
329
|
+
? await this.traceCollector.getTrace(this.currentTraceId)
|
|
330
|
+
: null;
|
|
331
|
+
|
|
332
|
+
process.send({
|
|
333
|
+
type: 'debug:check_step_mode',
|
|
334
|
+
requestId,
|
|
335
|
+
payload: {
|
|
336
|
+
graphId: this.context.graphId,
|
|
337
|
+
nodeId: node.id,
|
|
338
|
+
nodeType: node.type,
|
|
339
|
+
inputs,
|
|
340
|
+
executedSteps,
|
|
341
|
+
context: {
|
|
342
|
+
user: this.context.user,
|
|
343
|
+
variables: this.context.variables,
|
|
344
|
+
commandArguments: this.context.commandArguments,
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
// Ждём ответа (если step mode не активен, ответ придёт сразу)
|
|
350
|
+
await new Promise((resolve) => {
|
|
351
|
+
this.pendingDebugRequests.set(requestId, resolve);
|
|
352
|
+
|
|
353
|
+
// Таймаут на случай, если ответ не придёт
|
|
354
|
+
const timeoutId = setTimeout(() => {
|
|
355
|
+
if (this.pendingDebugRequests.has(requestId)) {
|
|
356
|
+
this.pendingDebugRequests.delete(requestId);
|
|
357
|
+
resolve(null);
|
|
358
|
+
}
|
|
359
|
+
}, debugConfig.STEP_MODE_TIMEOUT);
|
|
360
|
+
|
|
361
|
+
// Сохраняем timeoutId для возможной отмены
|
|
362
|
+
this.pendingDebugRequests.set(`${requestId}_timeout`, timeoutId);
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
async _executeLegacyNode(node) {
|
|
117
367
|
switch (node.type) {
|
|
118
368
|
|
|
119
369
|
|
|
@@ -217,7 +467,7 @@ class GraphExecutionEngine {
|
|
|
217
467
|
|
|
218
468
|
async evaluateOutputPin(node, pinId, defaultValue = null) {
|
|
219
469
|
if (!node) return defaultValue;
|
|
220
|
-
|
|
470
|
+
|
|
221
471
|
const cacheKey = `${node.id}:${pinId}`;
|
|
222
472
|
if (this.memo.has(cacheKey)) {
|
|
223
473
|
return this.memo.get(cacheKey);
|
|
@@ -229,12 +479,52 @@ class GraphExecutionEngine {
|
|
|
229
479
|
resolvePinValue: this.resolvePinValue.bind(this),
|
|
230
480
|
memo: this.memo,
|
|
231
481
|
};
|
|
482
|
+
|
|
483
|
+
// Записываем data ноду в трассировку перед вычислением (только один раз)
|
|
484
|
+
const traceKey = `trace_recorded:${node.id}`;
|
|
485
|
+
const isDataNode = !nodeConfig.pins.inputs.some(p => p.type === 'Exec');
|
|
486
|
+
|
|
487
|
+
if (this.currentTraceId && isDataNode && !this.memo.has(traceKey)) {
|
|
488
|
+
// Это data нода (нет exec пинов) и она ещё не записана - записываем её inputs
|
|
489
|
+
const inputs = await this._captureNodeInputs(node);
|
|
490
|
+
|
|
491
|
+
this.traceCollector.recordStep(this.currentTraceId, {
|
|
492
|
+
nodeId: node.id,
|
|
493
|
+
nodeType: node.type,
|
|
494
|
+
status: 'executed',
|
|
495
|
+
duration: 0,
|
|
496
|
+
inputs,
|
|
497
|
+
outputs: {},
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
// Помечаем, что нода уже записана в трассировку
|
|
501
|
+
this.memo.set(traceKey, true);
|
|
502
|
+
}
|
|
503
|
+
|
|
232
504
|
const result = await nodeConfig.evaluator.call(this, node, pinId, this.context, helpers);
|
|
233
|
-
|
|
505
|
+
|
|
234
506
|
const isVolatile = this.isNodeVolatile(node);
|
|
235
507
|
if (!isVolatile) {
|
|
236
508
|
this.memo.set(cacheKey, result);
|
|
237
509
|
}
|
|
510
|
+
|
|
511
|
+
// Обновляем outputs для data ноды после вычисления И после записи в memo
|
|
512
|
+
// Обновляем только один раз для всей ноды (не для каждого пина отдельно)
|
|
513
|
+
const traceOutputsKey = `trace_outputs_recorded:${node.id}`;
|
|
514
|
+
if (this.currentTraceId && isDataNode && this.memo.has(traceKey) && !this.memo.has(traceOutputsKey)) {
|
|
515
|
+
const outputs = {};
|
|
516
|
+
for (const outputPin of nodeConfig.pins.outputs) {
|
|
517
|
+
if (outputPin.type !== 'Exec') {
|
|
518
|
+
const outKey = `${node.id}:${outputPin.id}`;
|
|
519
|
+
if (this.memo.has(outKey)) {
|
|
520
|
+
outputs[outputPin.id] = this.memo.get(outKey);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
this.traceCollector.updateStepOutputs(this.currentTraceId, node.id, outputs);
|
|
525
|
+
this.memo.set(traceOutputsKey, true); // Помечаем, что outputs уже записаны
|
|
526
|
+
}
|
|
527
|
+
|
|
238
528
|
return result;
|
|
239
529
|
}
|
|
240
530
|
|
|
@@ -245,33 +535,45 @@ class GraphExecutionEngine {
|
|
|
245
535
|
result = this.memo.get(`${node.id}:updated_user`);
|
|
246
536
|
break;
|
|
247
537
|
case 'event:command':
|
|
248
|
-
if (pinId === 'args') result = this.context.args || {};
|
|
249
|
-
else if (pinId === 'user') result = this.context.user || {};
|
|
250
|
-
else if (pinId === 'chat_type') result = this.context.typeChat || 'chat';
|
|
251
|
-
else result = this.context
|
|
538
|
+
if (pinId === 'args') result = this.context.eventArgs?.args || {};
|
|
539
|
+
else if (pinId === 'user') result = this.context.eventArgs?.user || {};
|
|
540
|
+
else if (pinId === 'chat_type') result = this.context.eventArgs?.typeChat || 'chat';
|
|
541
|
+
else if (pinId === 'command_name') result = this.context.eventArgs?.commandName;
|
|
542
|
+
else if (pinId === 'success') result = this.context.success !== undefined ? this.context.success : true;
|
|
543
|
+
else result = this.context.eventArgs?.[pinId];
|
|
252
544
|
break;
|
|
253
545
|
case 'event:chat':
|
|
254
|
-
if (pinId === 'username') result = this.context.username;
|
|
255
|
-
else if (pinId === 'message') result = this.context.message;
|
|
256
|
-
else if (pinId === 'chatType') result = this.context.chat_type;
|
|
257
|
-
else result = this.context[pinId];
|
|
546
|
+
if (pinId === 'username') result = this.context.eventArgs?.username || this.context.username;
|
|
547
|
+
else if (pinId === 'message') result = this.context.eventArgs?.message || this.context.message;
|
|
548
|
+
else if (pinId === 'chatType') result = this.context.eventArgs?.chatType || this.context.chat_type;
|
|
549
|
+
else result = this.context.eventArgs?.[pinId] || this.context[pinId];
|
|
258
550
|
break;
|
|
259
551
|
case 'event:raw_message':
|
|
260
|
-
if (pinId === 'rawText') result = this.context.rawText;
|
|
261
|
-
else result = this.context[pinId];
|
|
552
|
+
if (pinId === 'rawText') result = this.context.eventArgs?.rawText || this.context.rawText;
|
|
553
|
+
else result = this.context.eventArgs?.[pinId] || this.context[pinId];
|
|
262
554
|
break;
|
|
263
555
|
case 'event:playerJoined':
|
|
264
556
|
case 'event:playerLeft':
|
|
265
|
-
result = this.context
|
|
557
|
+
if (pinId === 'user') result = this.context.eventArgs?.user || this.context.user;
|
|
558
|
+
else result = this.context.eventArgs?.[pinId] || this.context[pinId];
|
|
266
559
|
break;
|
|
267
560
|
case 'event:entitySpawn':
|
|
268
561
|
case 'event:entityMoved':
|
|
269
562
|
case 'event:entityGone':
|
|
270
|
-
result = this.context
|
|
563
|
+
if (pinId === 'entity') result = this.context.eventArgs?.entity || this.context.entity;
|
|
564
|
+
else result = this.context.eventArgs?.[pinId] || this.context[pinId];
|
|
271
565
|
break;
|
|
272
566
|
case 'event:health':
|
|
273
567
|
case 'event:botDied':
|
|
274
|
-
|
|
568
|
+
case 'event:botStartup':
|
|
569
|
+
result = this.context.eventArgs?.[pinId] || this.context[pinId];
|
|
570
|
+
break;
|
|
571
|
+
case 'event:websocket_call':
|
|
572
|
+
if (pinId === 'graphName') result = this.context.eventArgs?.graphName || this.context.graphName;
|
|
573
|
+
else if (pinId === 'data') result = this.context.eventArgs?.data || this.context.data;
|
|
574
|
+
else if (pinId === 'socketId') result = this.context.eventArgs?.socketId || this.context.socketId;
|
|
575
|
+
else if (pinId === 'keyPrefix') result = this.context.eventArgs?.keyPrefix || this.context.keyPrefix;
|
|
576
|
+
else result = this.context.eventArgs?.[pinId] || this.context[pinId];
|
|
275
577
|
break;
|
|
276
578
|
|
|
277
579
|
case 'flow:for_each': {
|
|
@@ -297,9 +599,19 @@ class GraphExecutionEngine {
|
|
|
297
599
|
return result;
|
|
298
600
|
}
|
|
299
601
|
|
|
300
|
-
isNodeVolatile(node) {
|
|
602
|
+
isNodeVolatile(node, visited = new Set(), depth = 0) {
|
|
301
603
|
if (!node) return false;
|
|
302
|
-
|
|
604
|
+
|
|
605
|
+
if (depth > MAX_RECURSION_DEPTH) {
|
|
606
|
+
console.warn(`[GraphExecutionEngine] isNodeVolatile достиг максимальной глубины рекурсии (${MAX_RECURSION_DEPTH})`);
|
|
607
|
+
return false;
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
if (visited.has(node.id)) {
|
|
611
|
+
return false;
|
|
612
|
+
}
|
|
613
|
+
visited.add(node.id);
|
|
614
|
+
|
|
303
615
|
if (node.type === 'data:get_variable') {
|
|
304
616
|
return true;
|
|
305
617
|
}
|
|
@@ -307,7 +619,7 @@ class GraphExecutionEngine {
|
|
|
307
619
|
const connections = this.activeGraph.connections.filter(c => c.targetNodeId === node.id);
|
|
308
620
|
for (const conn of connections) {
|
|
309
621
|
const sourceNode = this.activeGraph.nodes.find(n => n.id === conn.sourceNodeId);
|
|
310
|
-
if (this.isNodeVolatile(sourceNode)) {
|
|
622
|
+
if (this.isNodeVolatile(sourceNode, visited, depth + 1)) {
|
|
311
623
|
return true;
|
|
312
624
|
}
|
|
313
625
|
}
|
|
@@ -317,10 +629,350 @@ class GraphExecutionEngine {
|
|
|
317
629
|
|
|
318
630
|
hasConnection(node, pinId) {
|
|
319
631
|
if (!this.activeGraph || !this.activeGraph.connections) return false;
|
|
320
|
-
return this.activeGraph.connections.some(conn =>
|
|
632
|
+
return this.activeGraph.connections.some(conn =>
|
|
321
633
|
conn.targetNodeId === node.id && conn.targetPinId === pinId
|
|
322
634
|
);
|
|
323
635
|
}
|
|
636
|
+
|
|
637
|
+
/**
|
|
638
|
+
* Захватить outputs для всех data-нод в trace
|
|
639
|
+
* Вызывается перед завершением trace, чтобы гарантировать,
|
|
640
|
+
* что для всех data-нод записаны outputs (даже если их выходы не подключены)
|
|
641
|
+
*/
|
|
642
|
+
async _captureAllDataNodeOutputs() {
|
|
643
|
+
if (!this.currentTraceId) return;
|
|
644
|
+
|
|
645
|
+
const trace = await this.traceCollector.getTrace(this.currentTraceId);
|
|
646
|
+
if (!trace || !trace.steps) return;
|
|
647
|
+
|
|
648
|
+
// Проходим по всем шагам и находим data-ноды
|
|
649
|
+
for (const step of trace.steps) {
|
|
650
|
+
if (step.type === 'traversal') continue;
|
|
651
|
+
|
|
652
|
+
// Проверяем, есть ли уже outputs
|
|
653
|
+
if (step.outputs && Object.keys(step.outputs).length > 0) continue;
|
|
654
|
+
|
|
655
|
+
// Находим ноду в графе
|
|
656
|
+
const node = this.activeGraph.nodes.find(n => n.id === step.nodeId);
|
|
657
|
+
if (!node) continue;
|
|
658
|
+
|
|
659
|
+
// Получаем конфигурацию ноды
|
|
660
|
+
const nodeConfig = this.nodeRegistry.getNodeConfig(node.type);
|
|
661
|
+
if (!nodeConfig) continue;
|
|
662
|
+
|
|
663
|
+
// Проверяем, является ли это data-нодой (нет exec входов)
|
|
664
|
+
const isDataNode = !nodeConfig.pins.inputs.some(p => p.type === 'Exec');
|
|
665
|
+
if (!isDataNode) continue;
|
|
666
|
+
|
|
667
|
+
// Захватываем outputs
|
|
668
|
+
try {
|
|
669
|
+
const outputs = await this._captureNodeOutputs(node);
|
|
670
|
+
if (outputs && Object.keys(outputs).length > 0) {
|
|
671
|
+
this.traceCollector.updateStepOutputs(this.currentTraceId, node.id, outputs);
|
|
672
|
+
}
|
|
673
|
+
} catch (error) {
|
|
674
|
+
console.error(`[GraphExecutor] Error capturing outputs for data node ${node.id}:`, error);
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
/**
|
|
680
|
+
* Захватить значения входов ноды для трассировки
|
|
681
|
+
*/
|
|
682
|
+
async _captureNodeInputs(node) {
|
|
683
|
+
const inputs = {};
|
|
684
|
+
|
|
685
|
+
// Получаем конфигурацию ноды
|
|
686
|
+
const nodeConfig = this.nodeRegistry.getNodeConfig(node.type);
|
|
687
|
+
if (!nodeConfig || !nodeConfig.pins || !nodeConfig.pins.inputs) {
|
|
688
|
+
return inputs;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
// Захватываем значения всех входов
|
|
692
|
+
for (const inputPin of nodeConfig.pins.inputs) {
|
|
693
|
+
if (inputPin.type === 'Exec') continue; // Пропускаем exec пины
|
|
694
|
+
|
|
695
|
+
try {
|
|
696
|
+
// Используем resolvePinValue для получения актуального значения
|
|
697
|
+
const value = await this.resolvePinValue(node, inputPin.id);
|
|
698
|
+
// Записываем все значения, включая undefined и null
|
|
699
|
+
inputs[inputPin.id] = value;
|
|
700
|
+
} catch (error) {
|
|
701
|
+
inputs[inputPin.id] = '<error capturing>';
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
return inputs;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
/**
|
|
708
|
+
* Захватить значения выходов ноды для трассировки
|
|
709
|
+
*/
|
|
710
|
+
async _captureNodeOutputs(node) {
|
|
711
|
+
const outputs = {};
|
|
712
|
+
|
|
713
|
+
// Получаем конфигурацию ноды
|
|
714
|
+
const nodeConfig = this.nodeRegistry.getNodeConfig(node.type);
|
|
715
|
+
if (!nodeConfig || !nodeConfig.pins || !nodeConfig.pins.outputs) {
|
|
716
|
+
return outputs;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
// Захватываем значения всех выходов
|
|
720
|
+
for (const outputPin of nodeConfig.pins.outputs) {
|
|
721
|
+
if (outputPin.type === 'Exec') continue; // Пропускаем exec пины
|
|
722
|
+
|
|
723
|
+
try {
|
|
724
|
+
// Активно вызываем evaluateOutputPin вместо чтения из memo
|
|
725
|
+
// Это необходимо для event нод, которые используют switch-case и не пишут в memo
|
|
726
|
+
const value = await this.evaluateOutputPin(node, outputPin.id);
|
|
727
|
+
// Записываем все значения, включая undefined и null
|
|
728
|
+
outputs[outputPin.id] = value;
|
|
729
|
+
} catch (error) {
|
|
730
|
+
outputs[outputPin.id] = '<error capturing>';
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
return outputs;
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
/**
|
|
737
|
+
* Проверить брейкпоинт перед выполнением ноды
|
|
738
|
+
*/
|
|
739
|
+
async checkBreakpoint(node) {
|
|
740
|
+
try {
|
|
741
|
+
// Если работаем в дочернем процессе, используем IPC
|
|
742
|
+
if (process.send) {
|
|
743
|
+
return await this._checkBreakpointViaIpc(node);
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
// Иначе используем прямой доступ к DebugManager
|
|
747
|
+
const debugManager = getGlobalDebugManager();
|
|
748
|
+
const graphId = this.context.graphId;
|
|
749
|
+
|
|
750
|
+
if (!graphId) return;
|
|
751
|
+
|
|
752
|
+
const debugState = debugManager.get(graphId);
|
|
753
|
+
if (!debugState) return;
|
|
754
|
+
|
|
755
|
+
const breakpoint = debugState.breakpoints.get(node.id);
|
|
756
|
+
if (!breakpoint || !breakpoint.enabled) return;
|
|
757
|
+
|
|
758
|
+
const shouldPause = await this.evaluateBreakpointCondition(breakpoint);
|
|
759
|
+
|
|
760
|
+
if (shouldPause) {
|
|
761
|
+
console.log(`[Debug] Hit breakpoint at node ${node.id}, pausing execution`);
|
|
762
|
+
|
|
763
|
+
breakpoint.hitCount++;
|
|
764
|
+
|
|
765
|
+
const inputs = await this._captureNodeInputs(node);
|
|
766
|
+
|
|
767
|
+
const executedSteps = this.currentTraceId
|
|
768
|
+
? await this.traceCollector.getTrace(this.currentTraceId)
|
|
769
|
+
: null;
|
|
770
|
+
|
|
771
|
+
const overrides = await debugState.pause({
|
|
772
|
+
nodeId: node.id,
|
|
773
|
+
nodeType: node.type,
|
|
774
|
+
inputs,
|
|
775
|
+
executedSteps, // Добавляем выполненные шаги
|
|
776
|
+
context: {
|
|
777
|
+
user: this.context.user,
|
|
778
|
+
variables: this.context.variables,
|
|
779
|
+
commandArguments: this.context.commandArguments,
|
|
780
|
+
},
|
|
781
|
+
breakpoint: {
|
|
782
|
+
condition: breakpoint.condition,
|
|
783
|
+
hitCount: breakpoint.hitCount
|
|
784
|
+
}
|
|
785
|
+
});
|
|
786
|
+
|
|
787
|
+
if (overrides && overrides.__stopped) {
|
|
788
|
+
throw new Error('Execution stopped by debugger');
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
if (overrides) {
|
|
792
|
+
this.applyWhatIfOverrides(node, overrides);
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
} catch (error) {
|
|
796
|
+
console.error(`[checkBreakpoint] ERROR:`, error.message, error.stack);
|
|
797
|
+
if (error.message === 'DebugSessionManager not initialized! Call initializeDebugManager(io) first.') {
|
|
798
|
+
return;
|
|
799
|
+
}
|
|
800
|
+
// НЕ пробрасываем ошибку дальше, чтобы не сломать выполнение
|
|
801
|
+
console.error(`[checkBreakpoint] Ignoring error to continue execution`);
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
/**
|
|
806
|
+
* Оценить условие брейкпоинта
|
|
807
|
+
*/
|
|
808
|
+
async evaluateBreakpointCondition(breakpoint) {
|
|
809
|
+
// Если нет условия, всегда срабатывает
|
|
810
|
+
if (!breakpoint.condition || breakpoint.condition.trim() === '') {
|
|
811
|
+
return true;
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
try {
|
|
815
|
+
// Создаем sandbox для безопасного выполнения условия
|
|
816
|
+
const sandbox = {
|
|
817
|
+
user: this.context.user || {},
|
|
818
|
+
args: this.context.commandArguments || {},
|
|
819
|
+
variables: this.context.variables || {},
|
|
820
|
+
context: this.context
|
|
821
|
+
};
|
|
822
|
+
|
|
823
|
+
// Используем Function constructor для безопасного выполнения
|
|
824
|
+
const fn = new Function(
|
|
825
|
+
...Object.keys(sandbox),
|
|
826
|
+
`return (${breakpoint.condition})`
|
|
827
|
+
);
|
|
828
|
+
|
|
829
|
+
const result = fn(...Object.values(sandbox));
|
|
830
|
+
|
|
831
|
+
return Boolean(result);
|
|
832
|
+
} catch (error) {
|
|
833
|
+
console.error(`[Debug] Error evaluating breakpoint condition: ${error.message}`);
|
|
834
|
+
console.error(`[Debug] Condition was: ${breakpoint.condition}`);
|
|
835
|
+
return false;
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
/**
|
|
840
|
+
* Применить what-if overrides к ноде
|
|
841
|
+
*/
|
|
842
|
+
/**
|
|
843
|
+
* Проверить брейкпоинт через IPC (для дочерних процессов)
|
|
844
|
+
*/
|
|
845
|
+
async _checkBreakpointViaIpc(node) {
|
|
846
|
+
try {
|
|
847
|
+
const { randomUUID } = require('crypto');
|
|
848
|
+
const requestId = randomUUID();
|
|
849
|
+
|
|
850
|
+
const inputs = await this._captureNodeInputs(node);
|
|
851
|
+
const executedSteps = this.currentTraceId
|
|
852
|
+
? await this.traceCollector.getTrace(this.currentTraceId)
|
|
853
|
+
: null;
|
|
854
|
+
|
|
855
|
+
// Отправляем запрос в главный процесс
|
|
856
|
+
process.send({
|
|
857
|
+
type: 'debug:check_breakpoint',
|
|
858
|
+
requestId,
|
|
859
|
+
payload: {
|
|
860
|
+
graphId: this.context.graphId,
|
|
861
|
+
nodeId: node.id,
|
|
862
|
+
nodeType: node.type,
|
|
863
|
+
inputs,
|
|
864
|
+
executedSteps,
|
|
865
|
+
context: {
|
|
866
|
+
user: this.context.user,
|
|
867
|
+
variables: this.context.variables,
|
|
868
|
+
commandArguments: this.context.commandArguments,
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
});
|
|
872
|
+
|
|
873
|
+
// Ждём ответа
|
|
874
|
+
const overrides = await new Promise((resolve) => {
|
|
875
|
+
this.pendingDebugRequests.set(requestId, resolve);
|
|
876
|
+
|
|
877
|
+
// Таймаут на случай, если ответ не придёт
|
|
878
|
+
const timeoutId = setTimeout(() => {
|
|
879
|
+
if (this.pendingDebugRequests.has(requestId)) {
|
|
880
|
+
this.pendingDebugRequests.delete(requestId);
|
|
881
|
+
resolve(null);
|
|
882
|
+
}
|
|
883
|
+
}, debugConfig.BREAKPOINT_TIMEOUT);
|
|
884
|
+
|
|
885
|
+
// Сохраняем timeoutId для возможной отмены
|
|
886
|
+
this.pendingDebugRequests.set(`${requestId}_timeout`, timeoutId);
|
|
887
|
+
});
|
|
888
|
+
|
|
889
|
+
if (overrides && overrides.__stopped) {
|
|
890
|
+
throw new Error('Execution stopped by debugger');
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
if (overrides) {
|
|
894
|
+
this.applyWhatIfOverrides(node, overrides);
|
|
895
|
+
}
|
|
896
|
+
} catch (error) {
|
|
897
|
+
if (error.message === 'Execution stopped by debugger') {
|
|
898
|
+
throw error;
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
/**
|
|
904
|
+
* Статический обработчик IPC ответов (глобальный для всех instances)
|
|
905
|
+
*/
|
|
906
|
+
static _handleGlobalDebugResponse(message) {
|
|
907
|
+
const { requestId, overrides } = message;
|
|
908
|
+
const resolve = GraphExecutionEngine._allPendingRequests.get(requestId);
|
|
909
|
+
|
|
910
|
+
if (resolve) {
|
|
911
|
+
// Отменяем таймаут
|
|
912
|
+
const timeoutId = GraphExecutionEngine._allPendingRequests.get(`${requestId}_timeout`);
|
|
913
|
+
if (timeoutId) {
|
|
914
|
+
clearTimeout(timeoutId);
|
|
915
|
+
GraphExecutionEngine._allPendingRequests.delete(`${requestId}_timeout`);
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
GraphExecutionEngine._allPendingRequests.delete(requestId);
|
|
919
|
+
resolve(overrides);
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
/**
|
|
924
|
+
* Обработать IPC ответ от главного процесса (legacy wrapper)
|
|
925
|
+
*/
|
|
926
|
+
_handleDebugResponse(message) {
|
|
927
|
+
GraphExecutionEngine._handleGlobalDebugResponse(message);
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
applyWhatIfOverrides(node, overrides) {
|
|
931
|
+
if (!overrides || typeof overrides !== 'object') return;
|
|
932
|
+
|
|
933
|
+
console.log(`[Debug] Applying what-if overrides to node ${node.id}:`, overrides);
|
|
934
|
+
|
|
935
|
+
for (const [key, value] of Object.entries(overrides)) {
|
|
936
|
+
if (key === '__stopped') continue;
|
|
937
|
+
|
|
938
|
+
// Парсим ключ для определения типа изменения
|
|
939
|
+
// Форматы:
|
|
940
|
+
// - "var.varName" - переменная графа
|
|
941
|
+
// - "nodeId.out.pinName" - выходной пин ноды
|
|
942
|
+
// - "nodeId.in.pinName" - входной пин ноды
|
|
943
|
+
// - "pinName" - входной пин текущей ноды
|
|
944
|
+
|
|
945
|
+
if (key.startsWith('var.')) {
|
|
946
|
+
// Изменение переменной графа
|
|
947
|
+
const varName = key.substring(4);
|
|
948
|
+
if (!this.context.variables) {
|
|
949
|
+
this.context.variables = {};
|
|
950
|
+
}
|
|
951
|
+
this.context.variables[varName] = value;
|
|
952
|
+
console.log(`[Debug] Variable override: ${varName} = ${JSON.stringify(value)}`);
|
|
953
|
+
}
|
|
954
|
+
else if (key.includes('.out.')) {
|
|
955
|
+
// Изменение выходного пина ноды
|
|
956
|
+
const [nodeId, , pinName] = key.split('.');
|
|
957
|
+
const memoKey = `${nodeId}:${pinName}`;
|
|
958
|
+
this.memo.set(memoKey, value);
|
|
959
|
+
console.log(`[Debug] Output override: ${memoKey} = ${JSON.stringify(value)}`);
|
|
960
|
+
}
|
|
961
|
+
else if (key.includes('.in.')) {
|
|
962
|
+
// Изменение входного пина ноды (пока не применяется, но можно расширить)
|
|
963
|
+
const [nodeId, , pinName] = key.split('.');
|
|
964
|
+
console.log(`[Debug] Input override (informational): ${nodeId}.${pinName} = ${JSON.stringify(value)}`);
|
|
965
|
+
// Входы можно изменить через изменение outputs предыдущих нод или переменных
|
|
966
|
+
}
|
|
967
|
+
else {
|
|
968
|
+
// Изменение входного пина текущей ноды
|
|
969
|
+
if (!node.data) {
|
|
970
|
+
node.data = {};
|
|
971
|
+
}
|
|
972
|
+
node.data[key] = value;
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
}
|
|
324
976
|
}
|
|
325
977
|
|
|
326
978
|
module.exports = GraphExecutionEngine;
|