sinapse-ai 1.19.2 → 1.20.1
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/CLAUDE.md +2 -2
- package/.claude/hooks/enforce-delegation.cjs +32 -36
- package/.claude/rules/agent-handoff.md +10 -21
- package/.claude/rules/mandatory-delegation.md +1 -1
- package/.claude/rules/token-economy.md +12 -5
- package/.sinapse-ai/constitution.md +2 -0
- package/.sinapse-ai/core/atlas/flows-pt.js +6 -0
- package/.sinapse-ai/core/atlas/flows.js +7 -0
- package/.sinapse-ai/core/atlas/render-html.js +10 -8
- package/.sinapse-ai/core/atlas/render-markdown.js +8 -0
- package/.sinapse-ai/core/doctor/checks/constitution-consistency.js +7 -0
- package/.sinapse-ai/core/execution/autonomous-build-loop.js +10 -4
- package/.sinapse-ai/core/execution/build-orchestrator.js +73 -2
- package/.sinapse-ai/core/execution/rate-limit-manager.js +2 -0
- package/.sinapse-ai/core/execution/result-aggregator.js +2 -0
- package/.sinapse-ai/core/health-check/checks/project/constitution-consistency.js +12 -1
- package/.sinapse-ai/core/orchestration/cli-commands.js +121 -4
- package/.sinapse-ai/core/orchestration/executors/epic-4-executor.js +10 -2
- package/.sinapse-ai/core/orchestration/executors/epic-6-executor.js +53 -2
- package/.sinapse-ai/core/orchestration/index.js +3 -0
- package/.sinapse-ai/core/orchestration/master-orchestrator.js +116 -18
- package/.sinapse-ai/core/registry/service-registry.json +2 -32
- package/.sinapse-ai/core/synapse/context/context-tracker.js +118 -11
- package/.sinapse-ai/core/synapse/engine.js +18 -3
- package/.sinapse-ai/core/synapse/layers/l0-constitution.js +189 -8
- package/.sinapse-ai/core/synapse/output/formatter.js +65 -25
- package/.sinapse-ai/core-config.yaml +8 -1
- package/.sinapse-ai/data/entity-registry.yaml +492 -246
- package/.sinapse-ai/development/agents/analyst.md +18 -34
- package/.sinapse-ai/development/agents/architect.md +18 -34
- package/.sinapse-ai/development/agents/data-engineer.md +15 -28
- package/.sinapse-ai/development/agents/developer.md +18 -40
- package/.sinapse-ai/development/agents/devops.md +15 -28
- package/.sinapse-ai/development/agents/product-lead.md +18 -34
- package/.sinapse-ai/development/agents/project-lead.md +18 -34
- package/.sinapse-ai/development/agents/quality-gate.md +18 -34
- package/.sinapse-ai/development/agents/snps-orqx.md +5 -5
- package/.sinapse-ai/development/agents/sprint-lead.md +20 -36
- package/.sinapse-ai/development/agents/squad-creator.md +15 -27
- package/.sinapse-ai/development/agents/ux-design-expert.md +15 -27
- package/.sinapse-ai/development/scripts/agent-exit-hooks.js +13 -4
- package/.sinapse-ai/development/scripts/populate-entity-registry.js +3 -0
- package/.sinapse-ai/development/tasks/execute-epic-plan.md +0 -4
- package/.sinapse-ai/development/workflows/epic-orchestration.yaml +0 -1
- package/.sinapse-ai/git-hooks/lib/staged-secret-scan.js +3 -1
- package/.sinapse-ai/infrastructure/integrations/ai-providers/README.md +2 -2
- package/.sinapse-ai/install-manifest.yaml +94 -126
- package/.sinapse-ai/product/templates/activation-instructions-template.md +72 -185
- package/.sinapse-ai/product/templates/ide-rules/claude-rules.md +45 -274
- package/.sinapse-ai/product/templates/personalized-agent-template.md +3 -5
- package/.sinapse-ai/product/templates/statusline/agent-badges.json +2 -2
- package/.sinapse-ai/product/templates/statusline/statusline-script.js +5 -3
- package/.sinapse-ai/workflow-intelligence/index.js +3 -21
- package/AGENTS.md +2 -2
- package/CHANGELOG.md +50 -2
- package/README.md +10 -0
- package/bin/cli.js +29 -0
- package/bin/commands/help.js +5 -0
- package/bin/commands/install.js +5 -4
- package/bin/commands/uninstall.js +5 -0
- package/bin/lib/command-generator.js +4 -4
- package/bin/lib/fs-utils.js +18 -0
- package/bin/lib/setup-statusline.js +3 -1
- package/bin/modules/chrome-brain-installer.js +5 -3
- package/bin/modules/mcp-installer.js +3 -6
- package/bin/postinstall.js +9 -1
- package/bin/sinapse-init.js +8 -9
- package/bin/sinapse.js +152 -2
- package/bin/utils/staged-secret-scan.js +3 -1
- package/docs/framework/atlas/OPERATING-ATLAS.md +3 -3
- package/docs/framework/atlas/atlas-data.json +27 -27
- package/docs/framework/atlas/atlas.html +12 -10
- package/docs/framework/source-tree.md +2 -3
- package/docs/framework/workflow-engine-status.md +70 -0
- package/docs/guides/ade-guide.md +4 -2
- package/docs/guides/api-reference.md +2 -0
- package/docs/guides/permission-modes.md +2 -0
- package/docs/guides/user-guide.md +21 -7
- package/docs/guides/workflows/AUTO-WORKTREE-WORKFLOW.md +2 -2
- package/docs/pt/architecture/ade-architecture.md +2 -0
- package/docs/pt/architecture/high-level-architecture.md +1 -1
- package/docs/pt/guides/ade-guide.md +4 -2
- package/docs/pt/guides/api-reference.md +2 -0
- package/docs/pt/guides/permission-modes.md +2 -0
- package/docs/pt/guides/user-guide.md +21 -7
- package/docs/pt/platforms/claude-code.md +2 -2
- package/docs/sinapse-workflows/auto-worktree-workflow.md +2 -2
- package/package.json +1 -1
- package/packages/installer/src/config/configure-environment.js +14 -6
- package/packages/installer/src/config/templates/core-config-template.js +43 -1
- package/packages/installer/src/installer/brownfield-upgrader.js +5 -3
- package/packages/installer/src/installer/file-hasher.js +29 -21
- package/packages/installer/src/installer/manifest-signature.js +61 -49
- package/packages/installer/src/installer/post-install-validator.js +24 -17
- package/packages/installer/src/installer/synapse-runtime-installer.js +148 -0
- package/packages/installer/src/merger/parsers/markdown-section-parser.js +3 -2
- package/packages/installer/src/updater/index.js +7 -1
- package/packages/installer/src/utils/atomic-write.js +35 -0
- package/packages/installer/src/wizard/i18n.js +294 -0
- package/packages/installer/src/wizard/index.js +31 -3
- package/packages/installer/src/wizard/validation/troubleshooting-system.js +60 -131
- package/packages/sinapse-install/src/capabilities/chrome-brain.js +5 -3
- package/packages/sinapse-install/src/installer.js +3 -1
- package/packages/sinapse-install/src/utils/atomic-write.js +67 -0
- package/scripts/apply-persona-disclaimer.js +2 -1
- package/scripts/bracket-report.js +103 -0
- package/scripts/sinapse-patch.js +2 -1
- package/scripts/sync-squad-yaml-components.js +2 -1
- package/scripts/validate-agent-codenames.js +168 -37
- package/scripts/validate-agents-md.js +2 -1
- package/scripts/validate-article-xi.js +10 -8
- package/scripts/validate-install-docs.js +23 -2
- package/scripts/validate-no-external-refs.js +14 -8
- package/sinapse/agents/sinapse-orqx.md +3 -3
- package/sinapse/agents/snps-orqx.md +3 -3
- package/sinapse/knowledge-base/routing-catalog.md +1 -1
- package/sinapse/tasks/diagnose-and-route.md +1 -1
- package/squads/claude-code-mastery/CHANGELOG.md +1 -1
- package/squads/claude-code-mastery/README.md +6 -6
- package/squads/claude-code-mastery/agents/claude-mastery-chief.md +10 -15
- package/squads/claude-code-mastery/agents/config-engineer.md +5 -12
- package/squads/claude-code-mastery/agents/hooks-architect.md +5 -11
- package/squads/claude-code-mastery/agents/mcp-integrator.md +5 -12
- package/squads/claude-code-mastery/agents/project-integrator.md +5 -12
- package/squads/claude-code-mastery/agents/roadmap-sentinel.md +14 -21
- package/squads/claude-code-mastery/agents/skill-craftsman.md +5 -11
- package/squads/claude-code-mastery/agents/swarm-orqx.md +20 -33
- package/squads/claude-code-mastery/data/claude-code-quick-ref.yaml +1 -1
- package/squads/claude-code-mastery/knowledge-base/claude-code-internals-deep.md +4 -4
- package/squads/claude-code-mastery/knowledge-base/claude-code-internals-reference.md +4 -4
- package/squads/claude-code-mastery/tasks/create-agent-definition.md +6 -6
- package/squads/claude-code-mastery/tasks/create-team-topology.md +3 -3
- package/squads/claude-code-mastery/tasks/diagnose.md +1 -1
- package/squads/claude-code-mastery/tasks/parallel-decomposition.md +1 -1
- package/squads/claude-code-mastery/tasks/worktree-strategy.md +1 -1
- package/squads/squad-animations/README.md +1 -1
- package/squads/squad-animations/agents/animation-interpreter.md +5 -5
- package/squads/squad-animations/agents/animations-orqx.md +6 -6
- package/squads/squad-animations/squad.yaml +1 -1
- package/squads/squad-animations/tasks/analyze-reference-animation.md +1 -1
- package/squads/squad-animations/tasks/build-animation-brief.md +1 -1
- package/squads/squad-animations/tasks/create-animation-storyboard.md +1 -1
- package/squads/squad-animations/tasks/cross-reference-brand-system.md +1 -1
- package/squads/squad-animations/tasks/extract-animation-intent.md +1 -1
- package/squads/squad-animations/tasks/generate-motion-vocabulary.md +1 -1
- package/squads/squad-animations/tasks/identify-website-animation.md +1 -1
- package/squads/squad-animations/tasks/interpret-animation-prompt.md +1 -1
- package/squads/squad-animations/tasks/refine-animation-specification.md +1 -1
- package/squads/squad-animations/tasks/translate-feeling-to-parameters.md +1 -1
- package/squads/squad-animations/tasks/validate-animation-feasibility.md +1 -1
- package/squads/squad-animations/workflows/prompt-to-animation-cycle.yaml +2 -2
- package/squads/squad-brand/agents/brand-auditor.md +1 -1
- package/squads/squad-brand/agents/brand-compiler.md +1 -1
- package/squads/squad-brand/agents/brand-motion-vfx.md +5 -5
- package/squads/squad-brand/agents/brand-orqx.md +2 -2
- package/squads/squad-brand/agents/brand-sonic-designer.md +1 -1
- package/squads/squad-brand/squad.yaml +1 -1
- package/squads/squad-brand/tasks/create-animation-library.md +1 -1
- package/squads/squad-brand/tasks/create-brand-characters.md +2 -2
- package/squads/squad-brand/tasks/create-event-branding.md +2 -2
- package/squads/squad-brand/tasks/create-micro-interactions.md +1 -1
- package/squads/squad-brand/tasks/create-page-transitions.md +1 -1
- package/squads/squad-brand/tasks/create-video-templates.md +1 -1
- package/squads/squad-brand/tasks/create-web-templates.md +1 -1
- package/squads/squad-brand/tasks/define-motion-language.md +1 -1
- package/squads/squad-brand/tasks/design-dynamic-identity-system.md +2 -2
- package/squads/squad-brand/tasks/design-illustration-system.md +1 -1
- package/squads/squad-commercial/README.md +3 -3
- package/squads/squad-commercial/agents/commercial-orqx.md +8 -8
- package/squads/squad-commercial/agents/cs-crm-specialist.md +3 -3
- package/squads/squad-commercial/agents/cs-revops-analyst.md +3 -3
- package/squads/squad-commercial/agents/cs-sales-closer.md +1 -1
- package/squads/squad-commercial/knowledge-base/commercial-analytics-reporting.md +7 -7
- package/squads/squad-commercial/knowledge-base/sales-revenue-master-reference.md +1 -1
- package/squads/squad-commercial/squad.yaml +3 -3
- package/squads/squad-commercial/tasks/analyze-revenue-leaks.md +2 -2
- package/squads/squad-commercial/tasks/audit-commercial-tech-stack.md +1 -1
- package/squads/squad-commercial/tasks/audit-crm-data.md +1 -1
- package/squads/squad-commercial/tasks/build-deal-scoring-model.md +1 -1
- package/squads/squad-commercial/tasks/build-forecasting-model.md +1 -1
- package/squads/squad-commercial/tasks/build-pipeline-dashboard.md +2 -2
- package/squads/squad-commercial/tasks/build-unit-economics-model.md +1 -1
- package/squads/squad-commercial/tasks/conduct-commercial-retrospective.md +2 -2
- package/squads/squad-commercial/tasks/conduct-deal-review.md +1 -1
- package/squads/squad-commercial/tasks/conduct-win-loss-analysis.md +1 -1
- package/squads/squad-commercial/tasks/configure-activity-tracking.md +1 -1
- package/squads/squad-commercial/tasks/configure-crm-integrations.md +1 -1
- package/squads/squad-commercial/tasks/configure-pipeline-stages.md +1 -1
- package/squads/squad-commercial/tasks/coordinate-revenue-cycle.md +1 -1
- package/squads/squad-commercial/tasks/create-commercial-brief.md +2 -2
- package/squads/squad-commercial/tasks/create-revenue-dashboard.md +1 -1
- package/squads/squad-commercial/tasks/design-lead-routing.md +1 -1
- package/squads/squad-commercial/tasks/design-quota-model.md +1 -1
- package/squads/squad-commercial/tasks/execute-save-play.md +1 -1
- package/squads/squad-commercial/tasks/manage-commercial-handoffs.md +1 -1
- package/squads/squad-commercial/tasks/manage-pipeline-forecast.md +3 -3
- package/squads/squad-commercial/tasks/monitor-pipeline-health.md +1 -1
- package/squads/squad-commercial/tasks/monitor-saas-metrics.md +1 -1
- package/squads/squad-commercial/tasks/plan-sales-capacity.md +1 -1
- package/squads/squad-commercial/tasks/plan-territory-mapping.md +1 -1
- package/squads/squad-commercial/tasks/review-revenue-architecture.md +2 -2
- package/squads/squad-commercial/tasks/run-quarterly-commercial-review.md +3 -3
- package/squads/squad-commercial/tasks/select-commercial-workflow.md +1 -1
- package/squads/squad-commercial/tasks/setup-outreach-sequences.md +1 -1
- package/squads/squad-commercial/templates/offer-brief-template.md +2 -2
- package/squads/squad-commercial/workflows/new-offer-launch.yaml +2 -2
- package/squads/squad-commercial/workflows/quarterly-commercial-review.yaml +1 -1
- package/squads/squad-commercial/workflows/revenue-forecasting-cycle.yaml +2 -2
- package/squads/squad-content/README.md +1 -1
- package/squads/squad-content/agents/content-analyst.md +4 -4
- package/squads/squad-content/agents/content-engineer.md +2 -2
- package/squads/squad-content/agents/content-governor.md +1 -1
- package/squads/squad-content/agents/content-orqx.md +6 -6
- package/squads/squad-content/agents/editorial-strategist.md +5 -5
- package/squads/squad-content/agents/platform-specialist.md +1 -1
- package/squads/squad-content/agents/signal-intelligence.md +4 -4
- package/squads/squad-content/checklists/editorial-planning-checklist.md +1 -1
- package/squads/squad-content/checklists/onboarding-setup-checklist.md +2 -2
- package/squads/squad-content/knowledge-base/ai-native-content-loop.md +2 -2
- package/squads/squad-content/knowledge-base/content-governance-principles.md +2 -2
- package/squads/squad-content/knowledge-base/cross-squad-integration-protocol.md +1 -1
- package/squads/squad-content/knowledge-base/signal-intelligence-v2.md +1 -1
- package/squads/squad-content/knowledge-base/task-ownership-map.md +5 -5
- package/squads/squad-content/squad.yaml +2 -2
- package/squads/squad-content/tasks/alert-opportunity-windows.md +6 -6
- package/squads/squad-content/tasks/analyze-content-performance.md +2 -2
- package/squads/squad-content/tasks/batch-content-production.md +1 -1
- package/squads/squad-content/tasks/benchmark-against-competitors.md +1 -1
- package/squads/squad-content/tasks/coordinate-cross-squad.md +1 -1
- package/squads/squad-content/tasks/create-content-governance.md +1 -1
- package/squads/squad-content/tasks/create-editorial-calendar.md +1 -1
- package/squads/squad-content/tasks/curate-ugc-signals.md +2 -2
- package/squads/squad-content/tasks/define-big-idea.md +1 -1
- package/squads/squad-content/tasks/define-content-kpis.md +1 -1
- package/squads/squad-content/tasks/flag-content-for-amplification.md +2 -2
- package/squads/squad-content/tasks/generate-content-report.md +3 -3
- package/squads/squad-content/tasks/manage-content-sprint.md +1 -1
- package/squads/squad-content/tasks/measure-content-roi.md +3 -3
- package/squads/squad-content/tasks/orchestrate-content-pipeline.md +2 -2
- package/squads/squad-content/tasks/plan-content-sprint.md +3 -3
- package/squads/squad-content/tasks/predict-content-performance.md +2 -2
- package/squads/squad-content/tasks/scan-daily-signals.md +2 -2
- package/squads/squad-content/tasks/triage-content-requests.md +1 -1
- package/squads/squad-content/tasks/triage-urgent-signal.md +1 -1
- package/squads/squad-content/templates/signal-alert-template.md +2 -2
- package/squads/squad-content/templates/weekly-briefing-template.md +1 -1
- package/squads/squad-content/workflows/content-audit-cycle.yaml +1 -1
- package/squads/squad-content/workflows/content-creation-cycle.yaml +3 -3
- package/squads/squad-content/workflows/editorial-planning-cycle.yaml +3 -3
- package/squads/squad-content/workflows/onboarding-content-cycle.yaml +3 -3
- package/squads/squad-content/workflows/performance-feedback-loop.yaml +3 -3
- package/squads/squad-content/workflows/signal-to-content-cycle.yaml +5 -5
- package/squads/squad-copy/README.md +4 -4
- package/squads/squad-copy/agents/ad-copywriter.md +4 -4
- package/squads/squad-copy/agents/copy-orqx.md +3 -3
- package/squads/squad-copy/agents/copy-strategist.md +5 -5
- package/squads/squad-copy/agents/direct-response-writer.md +3 -3
- package/squads/squad-copy/agents/email-sequence-strategist.md +1 -1
- package/squads/squad-copy/agents/funnel-copywriter.md +3 -3
- package/squads/squad-copy/agents/headline-specialist.md +1 -1
- package/squads/squad-copy/agents/proof-architect.md +3 -3
- package/squads/squad-copy/squad.yaml +3 -3
- package/squads/squad-copy/tasks/build-proof-stack.md +3 -3
- package/squads/squad-copy/tasks/craft-cta-variations.md +2 -2
- package/squads/squad-copy/tasks/craft-email-nurture-sequence.md +2 -2
- package/squads/squad-copy/tasks/craft-objection-handlers.md +1 -1
- package/squads/squad-copy/tasks/craft-social-media-hooks.md +1 -1
- package/squads/squad-copy/tasks/create-cart-abandonment-sequence.md +2 -2
- package/squads/squad-copy/tasks/create-customer-story.md +2 -2
- package/squads/squad-copy/tasks/create-email-campaign.md +2 -2
- package/squads/squad-copy/tasks/create-mechanism-copy.md +4 -4
- package/squads/squad-copy/tasks/create-opening-hooks.md +1 -1
- package/squads/squad-copy/tasks/create-ugc-script.md +2 -2
- package/squads/squad-copy/tasks/create-urgency-scarcity-framework.md +1 -1
- package/squads/squad-copy/tasks/create-welcome-sequence.md +2 -2
- package/squads/squad-copy/tasks/design-headline-ab-tests.md +1 -1
- package/squads/squad-copy/tasks/design-trigger-sequence.md +1 -1
- package/squads/squad-copy/tasks/design-welcome-series.md +2 -2
- package/squads/squad-copy/tasks/optimize-existing-copy.md +2 -2
- package/squads/squad-copy/tasks/optimize-funnel-conversion-copy.md +2 -2
- package/squads/squad-copy/tasks/optimize-pricing-framing.md +2 -2
- package/squads/squad-copy/tasks/write-ad-copy-google.md +2 -2
- package/squads/squad-copy/tasks/write-ad-copy-social.md +2 -2
- package/squads/squad-copy/tasks/write-ad-copy-variations.md +4 -4
- package/squads/squad-copy/tasks/write-case-study.md +2 -2
- package/squads/squad-copy/tasks/write-comparison-piece.md +2 -2
- package/squads/squad-copy/tasks/write-email-sequence.md +1 -1
- package/squads/squad-copy/tasks/write-email-subject-lines.md +1 -1
- package/squads/squad-copy/tasks/write-funnel-copy-sequence.md +4 -4
- package/squads/squad-copy/tasks/write-landing-page-copy.md +2 -2
- package/squads/squad-copy/tasks/write-launch-sequence.md +2 -2
- package/squads/squad-copy/tasks/write-opt-in-page.md +2 -2
- package/squads/squad-copy/tasks/write-product-narrative.md +2 -2
- package/squads/squad-copy/tasks/write-retargeting-copy.md +2 -2
- package/squads/squad-copy/tasks/write-sales-letter.md +1 -1
- package/squads/squad-copy/tasks/write-social-proof-section.md +1 -1
- package/squads/squad-copy/tasks/write-subheadlines-and-deck-copy.md +1 -1
- package/squads/squad-copy/tasks/write-upsell-copy.md +2 -2
- package/squads/squad-copy/tasks/write-vsl-script.md +3 -3
- package/squads/squad-copy/tasks/write-whitepaper-persuasive.md +2 -2
- package/squads/squad-copy/workflows/campaign-copy-cycle.yaml +4 -4
- package/squads/squad-copy/workflows/conversion-copy-sprint.yaml +6 -6
- package/squads/squad-copy/workflows/sales-copy-pipeline.yaml +4 -4
- package/squads/squad-design/README.md +6 -6
- package/squads/squad-design/agents/cro-persuasion.md +3 -3
- package/squads/squad-design/agents/design-orqx.md +17 -17
- package/squads/squad-design/agents/dx-accessibility-specialist.md +5 -5
- package/squads/squad-design/agents/dx-design-system-architect.md +8 -8
- package/squads/squad-design/agents/dx-frontend-engineer.md +7 -7
- package/squads/squad-design/agents/dx-interaction-designer.md +6 -6
- package/squads/squad-design/agents/dx-performance-engineer.md +3 -3
- package/squads/squad-design/agents/dx-ui-designer.md +7 -7
- package/squads/squad-design/agents/dx-ux-strategist.md +7 -7
- package/squads/squad-design/agents/platform-aesthetic-director.md +11 -11
- package/squads/squad-design/agents/premium-packaging-strategist.md +2 -2
- package/squads/squad-design/agents/product-surface-director.md +1 -1
- package/squads/squad-design/squad.yaml +6 -6
- package/squads/squad-design/tasks/analyze-javascript-bundles.md +1 -1
- package/squads/squad-design/tasks/audit-core-web-vitals.md +1 -1
- package/squads/squad-design/tasks/audit-design-system-health.md +1 -1
- package/squads/squad-design/tasks/audit-motion-performance.md +1 -1
- package/squads/squad-design/tasks/certify-accessibility-compliance.md +2 -2
- package/squads/squad-design/tasks/compose-screen-layouts.md +3 -3
- package/squads/squad-design/tasks/conduct-competitive-ux-analysis.md +1 -1
- package/squads/squad-design/tasks/conduct-dx-quality-gate.md +3 -3
- package/squads/squad-design/tasks/conduct-usability-heuristic-review.md +1 -1
- package/squads/squad-design/tasks/conduct-visual-qa.md +1 -1
- package/squads/squad-design/tasks/conduct-wcag-audit.md +1 -1
- package/squads/squad-design/tasks/configure-cdn-strategy.md +1 -1
- package/squads/squad-design/tasks/configure-token-export-pipeline.md +1 -1
- package/squads/squad-design/tasks/create-a11y-remediation-plan.md +4 -4
- package/squads/squad-design/tasks/create-color-system.md +2 -2
- package/squads/squad-design/tasks/create-component-governance.md +1 -1
- package/squads/squad-design/tasks/create-component-tokens.md +2 -2
- package/squads/squad-design/tasks/create-dark-light-themes.md +3 -3
- package/squads/squad-design/tasks/create-easing-curve-library.md +1 -1
- package/squads/squad-design/tasks/create-empty-error-states.md +1 -1
- package/squads/squad-design/tasks/create-error-boundary-patterns.md +1 -1
- package/squads/squad-design/tasks/create-illustration-style.md +1 -1
- package/squads/squad-design/tasks/create-mobile-first-designs.md +2 -2
- package/squads/squad-design/tasks/create-motion-documentation.md +1 -1
- package/squads/squad-design/tasks/create-motion-tokens.md +2 -2
- package/squads/squad-design/tasks/create-primitive-tokens.md +1 -1
- package/squads/squad-design/tasks/create-responsive-grid-system.md +1 -1
- package/squads/squad-design/tasks/create-screen-reader-specs.md +1 -1
- package/squads/squad-design/tasks/create-scroll-animation-patterns.md +1 -1
- package/squads/squad-design/tasks/create-semantic-tokens.md +1 -1
- package/squads/squad-design/tasks/create-storybook-documentation-standards.md +1 -1
- package/squads/squad-design/tasks/create-user-personas.md +1 -1
- package/squads/squad-design/tasks/create-ux-principles.md +1 -1
- package/squads/squad-design/tasks/create-wireframe-brief.md +2 -2
- package/squads/squad-design/tasks/define-atomic-hierarchy.md +2 -2
- package/squads/squad-design/tasks/define-content-hierarchy.md +2 -2
- package/squads/squad-design/tasks/define-motion-principles.md +4 -4
- package/squads/squad-design/tasks/define-performance-budgets.md +1 -1
- package/squads/squad-design/tasks/define-token-taxonomy.md +2 -2
- package/squads/squad-design/tasks/design-accessible-form-patterns.md +2 -2
- package/squads/squad-design/tasks/design-component-api-contracts.md +3 -3
- package/squads/squad-design/tasks/design-component-visual-states.md +4 -4
- package/squads/squad-design/tasks/design-dashboard-layouts.md +1 -1
- package/squads/squad-design/tasks/design-duration-scale.md +1 -1
- package/squads/squad-design/tasks/design-feedback-animations.md +2 -2
- package/squads/squad-design/tasks/design-focus-management.md +1 -1
- package/squads/squad-design/tasks/design-form-patterns.md +2 -2
- package/squads/squad-design/tasks/design-icon-system.md +1 -1
- package/squads/squad-design/tasks/design-information-architecture.md +2 -2
- package/squads/squad-design/tasks/design-landing-page-ui.md +3 -3
- package/squads/squad-design/tasks/design-loading-choreography.md +1 -1
- package/squads/squad-design/tasks/design-multi-brand-theming.md +1 -1
- package/squads/squad-design/tasks/design-page-transitions.md +1 -1
- package/squads/squad-design/tasks/design-spacing-scale.md +3 -3
- package/squads/squad-design/tasks/design-typography-scale.md +3 -3
- package/squads/squad-design/tasks/design-user-flows.md +2 -2
- package/squads/squad-design/tasks/design-visual-hierarchy.md +2 -2
- package/squads/squad-design/tasks/eliminate-render-blocking.md +1 -1
- package/squads/squad-design/tasks/extract-critical-css.md +1 -1
- package/squads/squad-design/tasks/govern-third-party-scripts.md +1 -1
- package/squads/squad-design/tasks/implement-authentication-ui.md +1 -1
- package/squads/squad-design/tasks/implement-component-library.md +4 -4
- package/squads/squad-design/tasks/implement-form-system.md +2 -2
- package/squads/squad-design/tasks/implement-reduced-motion.md +3 -3
- package/squads/squad-design/tasks/implement-responsive-layouts.md +1 -1
- package/squads/squad-design/tasks/implement-routing-strategy.md +1 -1
- package/squads/squad-design/tasks/map-dark-mode-tokens.md +3 -3
- package/squads/squad-design/tasks/map-user-journeys.md +2 -2
- package/squads/squad-design/tasks/migrate-legacy-design-system.md +1 -1
- package/squads/squad-design/tasks/monitor-performance-regression.md +1 -1
- package/squads/squad-design/tasks/optimize-font-loading.md +1 -1
- package/squads/squad-design/tasks/optimize-image-pipeline.md +1 -1
- package/squads/squad-design/tasks/orchestrate-dx-pipeline.md +2 -2
- package/squads/squad-design/tasks/plan-ux-research-sprint.md +1 -1
- package/squads/squad-design/tasks/produce-design-handoff-specs.md +4 -4
- package/squads/squad-design/tasks/review-aria-patterns.md +1 -1
- package/squads/squad-design/tasks/setup-performance-ci-gates.md +1 -1
- package/squads/squad-design/tasks/setup-storybook-integration.md +1 -1
- package/squads/squad-design/tasks/spec-gesture-interactions.md +1 -1
- package/squads/squad-design/tasks/spec-micro-interactions.md +2 -2
- package/squads/squad-design/tasks/synthesize-user-research.md +2 -2
- package/squads/squad-design/tasks/test-keyboard-navigation.md +1 -1
- package/squads/squad-design/tasks/validate-ux-with-testing.md +1 -1
- package/squads/squad-design/tasks/verify-color-contrast.md +2 -2
- package/squads/squad-design/templates/a11y-audit-report-template.md +1 -1
- package/squads/squad-design/templates/design-handoff-template.md +1 -1
- package/squads/squad-design/templates/performance-budget-template.md +1 -1
- package/squads/squad-design/templates/ux-research-plan-template.md +1 -1
- package/squads/squad-design/workflows/a11y-compliance-cycle.yaml +8 -8
- package/squads/squad-design/workflows/design-system-build-cycle.yaml +12 -12
- package/squads/squad-design/workflows/landing-page-sprint.yaml +10 -10
- package/squads/squad-design/workflows/performance-remediation-cycle.yaml +6 -6
- package/squads/squad-design/workflows/ux-research-sprint.yaml +8 -8
- package/squads/squad-design/workflows/zero-to-digital-product-cycle.yaml +16 -16
- package/squads/squad-finance/README.md +1 -1
- package/squads/squad-finance/agents/budget-controller.md +1 -1
- package/squads/squad-finance/agents/cost-optimizer.md +2 -2
- package/squads/squad-finance/agents/finance-orqx.md +4 -4
- package/squads/squad-finance/agents/fiscal-compliance-br.md +4 -4
- package/squads/squad-finance/agents/forecast-strategist.md +6 -6
- package/squads/squad-finance/agents/pricing-strategist.md +3 -3
- package/squads/squad-finance/agents/profitability-analyst.md +1 -1
- package/squads/squad-finance/agents/revenue-analyst.md +1 -1
- package/squads/squad-finance/checklists/monthly-close-checklist.md +1 -1
- package/squads/squad-finance/checklists/quarterly-review-checklist.md +1 -1
- package/squads/squad-finance/squad.yaml +2 -2
- package/squads/squad-finance/tasks/analyze-price-sensitivity.md +1 -1
- package/squads/squad-finance/tasks/benchmark-competitor-pricing.md +1 -1
- package/squads/squad-finance/tasks/calculate-rate-card.md +1 -1
- package/squads/squad-finance/tasks/coordinate-quarterly-review.md +2 -2
- package/squads/squad-finance/tasks/create-proposal-pricing.md +1 -1
- package/squads/squad-finance/tasks/design-service-tiers.md +1 -1
- package/squads/squad-finance/tasks/design-value-based-pricing.md +1 -1
- package/squads/squad-finance/tasks/manage-financial-calendar.md +1 -1
- package/squads/squad-finance/tasks/model-pricing-scenario.md +1 -1
- package/squads/squad-finance/tasks/optimize-rate-realization.md +1 -1
- package/squads/squad-finance/tasks/simulate-pricing-impact.md +1 -1
- package/squads/squad-finance/tasks/track-pricing-performance.md +1 -1
- package/squads/squad-paidmedia/README.md +4 -4
- package/squads/squad-paidmedia/agents/campaign-analyst.md +6 -6
- package/squads/squad-paidmedia/agents/creative-strategist.md +2 -2
- package/squads/squad-paidmedia/agents/cro-specialist.md +5 -5
- package/squads/squad-paidmedia/agents/google-ads-specialist.md +2 -2
- package/squads/squad-paidmedia/agents/meta-ads-specialist.md +6 -6
- package/squads/squad-paidmedia/agents/paidmedia-orqx.md +6 -6
- package/squads/squad-paidmedia/agents/performance-engineer.md +2 -2
- package/squads/squad-paidmedia/agents/pm-creative-performance-analyst.md +2 -2
- package/squads/squad-paidmedia/knowledge-base/routing-catalog.md +21 -21
- package/squads/squad-paidmedia/squad.yaml +4 -4
- package/squads/squad-paidmedia/tasks/allocate-cross-channel-budget.md +1 -1
- package/squads/squad-paidmedia/tasks/allocate-meta-budget.md +2 -2
- package/squads/squad-paidmedia/tasks/analyze-audience-performance.md +1 -1
- package/squads/squad-paidmedia/tasks/analyze-content-performance.md +1 -1
- package/squads/squad-paidmedia/tasks/analyze-conversion-funnel.md +2 -2
- package/squads/squad-paidmedia/tasks/analyze-creative-effectiveness.md +1 -1
- package/squads/squad-paidmedia/tasks/analyze-keyword-rankings.md +1 -1
- package/squads/squad-paidmedia/tasks/analyze-landing-page.md +1 -1
- package/squads/squad-paidmedia/tasks/analyze-local-keywords.md +1 -1
- package/squads/squad-paidmedia/tasks/analyze-local-market.md +1 -1
- package/squads/squad-paidmedia/tasks/analyze-reviews-strategy.md +1 -1
- package/squads/squad-paidmedia/tasks/analyze-top-pages.md +1 -1
- package/squads/squad-paidmedia/tasks/analyze-traffic-sources.md +1 -1
- package/squads/squad-paidmedia/tasks/analyze-user-behavior.md +1 -1
- package/squads/squad-paidmedia/tasks/audit-conversion-tracking.md +1 -1
- package/squads/squad-paidmedia/tasks/audit-gmb-location.md +1 -1
- package/squads/squad-paidmedia/tasks/audit-meta-ads-account.md +1 -1
- package/squads/squad-paidmedia/tasks/audit-sitemap-health.md +1 -1
- package/squads/squad-paidmedia/tasks/build-audience-architecture.md +2 -2
- package/squads/squad-paidmedia/tasks/build-creative-scorecard.md +1 -1
- package/squads/squad-paidmedia/tasks/calculate-sample-size.md +1 -1
- package/squads/squad-paidmedia/tasks/check-indexing-status.md +1 -1
- package/squads/squad-paidmedia/tasks/create-scaling-roadmap.md +1 -1
- package/squads/squad-paidmedia/tasks/design-campaign-structure.md +2 -2
- package/squads/squad-paidmedia/tasks/design-progressive-profiling.md +1 -1
- package/squads/squad-paidmedia/tasks/detect-creative-fatigue.md +1 -1
- package/squads/squad-paidmedia/tasks/execute-launch-checklist.md +1 -1
- package/squads/squad-paidmedia/tasks/generate-monthly-report.md +1 -1
- package/squads/squad-paidmedia/tasks/generate-search-performance-overview.md +1 -1
- package/squads/squad-paidmedia/tasks/generate-weekly-summary.md +1 -1
- package/squads/squad-paidmedia/tasks/manage-pixel-capi-health.md +1 -1
- package/squads/squad-paidmedia/tasks/manage-scaling-roadmap.md +1 -1
- package/squads/squad-paidmedia/tasks/measure-activation-rate.md +1 -1
- package/squads/squad-paidmedia/tasks/optimize-ad-set-targeting.md +2 -2
- package/squads/squad-paidmedia/tasks/optimize-form-conversion.md +1 -1
- package/squads/squad-paidmedia/tasks/optimize-onboarding-activation.md +1 -1
- package/squads/squad-paidmedia/tasks/optimize-page-conversion.md +1 -1
- package/squads/squad-paidmedia/tasks/optimize-signup-flow.md +1 -1
- package/squads/squad-paidmedia/tasks/plan-customer-engagement.md +1 -1
- package/squads/squad-paidmedia/tasks/run-ab-test.md +1 -1
- package/squads/squad-paidmedia/tasks/run-creative-test.md +1 -1
- package/squads/squad-paidmedia/tasks/track-gmb-performance-trends.md +1 -1
- package/squads/squad-paidmedia/tasks/triage-campaign-issues.md +1 -1
- package/squads/squad-product/README.md +2 -2
- package/squads/squad-product/agents/product-orqx.md +4 -4
- package/squads/squad-product/agents/ps-delivery-manager.md +2 -2
- package/squads/squad-product/agents/ps-product-ops-specialist.md +2 -2
- package/squads/squad-product/squad.yaml +2 -2
- package/squads/squad-product/tasks/audit-product-tool-stack.md +1 -1
- package/squads/squad-product/tasks/build-product-knowledge-base.md +1 -1
- package/squads/squad-product/tasks/calculate-sprint-velocity.md +1 -1
- package/squads/squad-product/tasks/configure-feature-flag-rollout.md +1 -1
- package/squads/squad-product/tasks/create-product-artifact-template.md +1 -1
- package/squads/squad-product/tasks/create-product-onboarding-runbook.md +3 -3
- package/squads/squad-product/tasks/create-product-playbook.md +2 -2
- package/squads/squad-product/tasks/document-product-process.md +1 -1
- package/squads/squad-product/tasks/execute-feature-launch-checklist.md +1 -1
- package/squads/squad-product/tasks/facilitate-sprint-retrospective.md +1 -1
- package/squads/squad-product/tasks/generate-product-health-report.md +2 -2
- package/squads/squad-product/tasks/maintain-decision-log-system.md +1 -1
- package/squads/squad-product/tasks/manage-sprint-capacity-planning.md +1 -1
- package/squads/squad-product/tasks/map-cross-functional-dependencies.md +1 -1
- package/squads/squad-product/tasks/prepare-product-handoff-package.md +4 -4
- package/squads/squad-product/tasks/run-product-operations-audit.md +1 -1
- package/squads/squad-product/tasks/run-shape-up-betting-table.md +1 -1
- package/squads/squad-product/tasks/run-sprint-planning-session.md +1 -1
- package/squads/squad-product/tasks/scope-agency-mvp.md +1 -1
- package/squads/squad-product/tasks/setup-new-client-product-operations.md +1 -1
- package/squads/squad-product/tasks/standardize-cross-client-metrics.md +1 -1
- package/squads/squad-product/tasks/triage-technical-debt-backlog.md +1 -1
- package/squads/squad-product/tasks/write-release-notes.md +1 -1
- package/squads/squad-research/README.md +3 -3
- package/squads/squad-research/agents/audience-intelligence.md +9 -9
- package/squads/squad-research/agents/competitive-intelligence.md +1 -1
- package/squads/squad-research/agents/data-synthesizer.md +11 -11
- package/squads/squad-research/agents/deep-researcher.md +2 -2
- package/squads/squad-research/agents/market-analyst.md +9 -9
- package/squads/squad-research/agents/research-orqx.md +4 -4
- package/squads/squad-research/agents/trend-forecaster.md +2 -2
- package/squads/squad-research/knowledge-base/agentic-second-brain-reference.md +1 -1
- package/squads/squad-research/knowledge-base/community-platforms-reference.md +1 -1
- package/squads/squad-research/knowledge-base/cross-squad-integration-protocol.md +1 -1
- package/squads/squad-research/knowledge-base/multi-agent-research-methodology.md +3 -3
- package/squads/squad-research/squad.yaml +3 -3
- package/squads/squad-research/tasks/analyze-audience-behavior.md +2 -2
- package/squads/squad-research/tasks/analyze-audience-psychographics.md +2 -2
- package/squads/squad-research/tasks/analyze-competitor-pricing.md +1 -1
- package/squads/squad-research/tasks/analyze-industry-trends.md +2 -2
- package/squads/squad-research/tasks/analyze-macro-forces.md +1 -1
- package/squads/squad-research/tasks/analyze-pricing-landscape.md +2 -2
- package/squads/squad-research/tasks/analyze-social-listening.md +2 -2
- package/squads/squad-research/tasks/analyze-value-chain.md +2 -2
- package/squads/squad-research/tasks/answer-strategic-question.md +1 -1
- package/squads/squad-research/tasks/assess-market-maturity.md +2 -2
- package/squads/squad-research/tasks/build-audience-persona.md +2 -2
- package/squads/squad-research/tasks/build-data-narrative.md +2 -2
- package/squads/squad-research/tasks/compile-competitive-dossier.md +2 -2
- package/squads/squad-research/tasks/conduct-deep-research.md +1 -1
- package/squads/squad-research/tasks/conduct-jobs-to-be-done.md +2 -2
- package/squads/squad-research/tasks/create-empathy-map.md +2 -2
- package/squads/squad-research/tasks/create-executive-briefing.md +2 -2
- package/squads/squad-research/tasks/create-insight-deck.md +2 -2
- package/squads/squad-research/tasks/create-research-dossier.md +1 -1
- package/squads/squad-research/tasks/create-research-repository.md +2 -2
- package/squads/squad-research/tasks/create-swot-analysis.md +4 -4
- package/squads/squad-research/tasks/design-survey.md +2 -2
- package/squads/squad-research/tasks/evaluate-market-entry.md +2 -2
- package/squads/squad-research/tasks/evaluate-regulatory-landscape.md +2 -2
- package/squads/squad-research/tasks/forecast-industry-trends.md +2 -2
- package/squads/squad-research/tasks/forecast-market-growth.md +2 -2
- package/squads/squad-research/tasks/generate-actionable-recommendations.md +2 -2
- package/squads/squad-research/tasks/identify-market-segments.md +3 -3
- package/squads/squad-research/tasks/map-audience-ecosystem.md +2 -2
- package/squads/squad-research/tasks/map-audience-journey.md +2 -2
- package/squads/squad-research/tasks/map-industry-ecosystem.md +2 -2
- package/squads/squad-research/tasks/map-market-opportunity.md +2 -2
- package/squads/squad-research/tasks/map-pain-gain-matrix.md +2 -2
- package/squads/squad-research/tasks/map-strategic-implications.md +2 -2
- package/squads/squad-research/tasks/orchestrate-research-pipeline.md +4 -4
- package/squads/squad-research/tasks/predict-market-shifts.md +1 -1
- package/squads/squad-research/tasks/profile-ideal-customer.md +2 -2
- package/squads/squad-research/tasks/run-porter-five-forces.md +1 -1
- package/squads/squad-research/tasks/run-scenario-planning.md +1 -1
- package/squads/squad-research/tasks/segment-audience.md +2 -2
- package/squads/squad-research/tasks/size-market-tam-sam-som.md +2 -2
- package/squads/squad-research/tasks/synthesize-multi-source.md +1 -1
- package/squads/squad-research/tasks/synthesize-research-report.md +2 -2
- package/squads/squad-research/tasks/validate-persona-with-data.md +2 -2
- package/squads/squad-research/tasks/visualize-research-data.md +2 -2
- package/squads/squad-research/templates/audience-persona-template.md +1 -1
- package/squads/squad-research/templates/competitive-dossier-template.md +1 -1
- package/squads/squad-research/templates/market-analysis-template.md +1 -1
- package/squads/squad-research/workflows/audience-intelligence-cycle.yaml +12 -12
- package/squads/squad-research/workflows/competitive-intelligence-cycle.yaml +2 -2
- package/squads/squad-research/workflows/deep-research-cycle.yaml +2 -2
- package/squads/squad-research/workflows/full-research-sprint.yaml +8 -8
- package/squads/squad-research/workflows/market-analysis-cycle.yaml +12 -12
- package/squads/squad-research/workflows/trend-forecasting-cycle.yaml +2 -2
- package/.sinapse-ai/core/execution/context-injector.js +0 -537
- package/.sinapse-ai/core/execution/parallel-executor.js +0 -299
- package/.sinapse-ai/core/execution/parallel-monitor.js +0 -430
- package/.sinapse-ai/core/execution/semantic-merge-engine.js +0 -1748
- package/.sinapse-ai/core/execution/wave-executor.js +0 -401
- package/.sinapse-ai/development/tasks/waves.md +0 -205
- package/.sinapse-ai/lib/build.json +0 -1
- package/.sinapse-ai/workflow-intelligence/engine/wave-analyzer.js +0 -684
|
@@ -1,1748 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Semantic Merge Engine
|
|
3
|
-
* Story 8.3 - Enhanced Implementation
|
|
4
|
-
*
|
|
5
|
-
* AI-powered semantic merge system for resolving conflicts between
|
|
6
|
-
* parallel agent work. Analyzes code at semantic level (functions, imports,
|
|
7
|
-
* classes) rather than line-by-line to enable intelligent merge resolution.
|
|
8
|
-
*
|
|
9
|
-
* Architecture:
|
|
10
|
-
* 1. SemanticAnalyzer - Extracts semantic elements from code
|
|
11
|
-
* 2. ConflictDetector - Detects conflicts using compatibility rules
|
|
12
|
-
* 3. AutoMerger - Resolves simple conflicts deterministically
|
|
13
|
-
* 4. AIResolver - Uses Claude for complex conflict resolution
|
|
14
|
-
* 5. MergeOrchestrator - Coordinates the complete pipeline
|
|
15
|
-
*
|
|
16
|
-
* Based on Auto-Claude's merge system architecture.
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
const { execSync, execFileSync } = require('child_process');
|
|
20
|
-
const fs = require('fs');
|
|
21
|
-
const path = require('path');
|
|
22
|
-
const EventEmitter = require('events');
|
|
23
|
-
const yaml = require('js-yaml');
|
|
24
|
-
|
|
25
|
-
// ============================================================================
|
|
26
|
-
// TYPES & ENUMS
|
|
27
|
-
// ============================================================================
|
|
28
|
-
|
|
29
|
-
const ChangeType = {
|
|
30
|
-
IMPORT_ADDED: 'import_added',
|
|
31
|
-
IMPORT_REMOVED: 'import_removed',
|
|
32
|
-
IMPORT_MODIFIED: 'import_modified',
|
|
33
|
-
FUNCTION_ADDED: 'function_added',
|
|
34
|
-
FUNCTION_REMOVED: 'function_removed',
|
|
35
|
-
FUNCTION_MODIFIED: 'function_modified',
|
|
36
|
-
CLASS_ADDED: 'class_added',
|
|
37
|
-
CLASS_REMOVED: 'class_removed',
|
|
38
|
-
CLASS_MODIFIED: 'class_modified',
|
|
39
|
-
VARIABLE_ADDED: 'variable_added',
|
|
40
|
-
VARIABLE_REMOVED: 'variable_removed',
|
|
41
|
-
VARIABLE_MODIFIED: 'variable_modified',
|
|
42
|
-
JSX_ADDED: 'jsx_added',
|
|
43
|
-
JSX_MODIFIED: 'jsx_modified',
|
|
44
|
-
COMMENT_ADDED: 'comment_added',
|
|
45
|
-
COMMENT_MODIFIED: 'comment_modified',
|
|
46
|
-
STYLE_ADDED: 'style_added',
|
|
47
|
-
STYLE_MODIFIED: 'style_modified',
|
|
48
|
-
CONFIG_MODIFIED: 'config_modified',
|
|
49
|
-
UNKNOWN: 'unknown',
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
const MergeStrategy = {
|
|
53
|
-
COMBINE: 'combine', // Both changes can coexist
|
|
54
|
-
TAKE_NEWER: 'take_newer', // Take the more recent change
|
|
55
|
-
TAKE_LARGER: 'take_larger', // Take the more comprehensive change
|
|
56
|
-
AI_REQUIRED: 'ai_required', // Needs AI to resolve
|
|
57
|
-
HUMAN_REQUIRED: 'human_required', // Too complex, needs human
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
const ConflictSeverity = {
|
|
61
|
-
LOW: 'low', // Auto-mergeable
|
|
62
|
-
MEDIUM: 'medium', // AI can likely resolve
|
|
63
|
-
HIGH: 'high', // AI required with review
|
|
64
|
-
CRITICAL: 'critical', // Human intervention required
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
const MergeDecision = {
|
|
68
|
-
AUTO_MERGED: 'auto_merged',
|
|
69
|
-
AI_MERGED: 'ai_merged',
|
|
70
|
-
NEEDS_HUMAN_REVIEW: 'needs_human_review',
|
|
71
|
-
FAILED: 'failed',
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
// ============================================================================
|
|
75
|
-
// SEMANTIC ANALYZER
|
|
76
|
-
// ============================================================================
|
|
77
|
-
|
|
78
|
-
class SemanticAnalyzer {
|
|
79
|
-
constructor() {
|
|
80
|
-
this.patterns = {
|
|
81
|
-
// JavaScript/TypeScript patterns
|
|
82
|
-
jsImport:
|
|
83
|
-
/^(?:import\s+(?:(?:\{[^}]*\}|\*\s+as\s+\w+|\w+)(?:\s*,\s*)?)+\s+from\s+['"][^'"]+['"]|import\s+['"][^'"]+['"])/gm,
|
|
84
|
-
jsFunction:
|
|
85
|
-
/(?:(?:export\s+)?(?:async\s+)?function\s+(\w+)|(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s+)?(?:\([^)]*\)|[^=])\s*=>|(\w+)\s*:\s*(?:async\s+)?(?:function|\([^)]*\)\s*=>))/gm,
|
|
86
|
-
jsClass: /(?:export\s+)?class\s+(\w+)(?:\s+extends\s+\w+)?/gm,
|
|
87
|
-
jsVariable: /(?:export\s+)?(?:const|let|var)\s+(\w+)\s*=/gm,
|
|
88
|
-
|
|
89
|
-
// JSX patterns
|
|
90
|
-
jsxComponent: /<(\w+)(?:\s[^>]*)?\/?>/gm,
|
|
91
|
-
|
|
92
|
-
// Python patterns
|
|
93
|
-
pyImport: /^(?:from\s+\S+\s+import\s+.+|import\s+.+)$/gm,
|
|
94
|
-
pyFunction: /^(?:async\s+)?def\s+(\w+)\s*\(/gm,
|
|
95
|
-
pyClass: /^class\s+(\w+)(?:\([^)]*\))?:/gm,
|
|
96
|
-
|
|
97
|
-
// CSS patterns
|
|
98
|
-
cssSelector: /^([.#]?\w[\w-]*(?:\s*[,>+~]\s*[.#]?\w[\w-]*)*)\s*\{/gm,
|
|
99
|
-
cssProperty: /^\s*([\w-]+)\s*:/gm,
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Analyze semantic differences between two versions of a file
|
|
105
|
-
* @param {string} filePath - Path to file
|
|
106
|
-
* @param {string} before - Content before changes
|
|
107
|
-
* @param {string} after - Content after changes
|
|
108
|
-
* @param {string} taskId - Task identifier
|
|
109
|
-
* @returns {Object} FileAnalysis with semantic changes
|
|
110
|
-
*/
|
|
111
|
-
analyzeDiff(filePath, before, after, taskId = null) {
|
|
112
|
-
const ext = path.extname(filePath).toLowerCase();
|
|
113
|
-
const language = this.detectLanguage(ext);
|
|
114
|
-
|
|
115
|
-
const beforeElements = this.extractElements(before, language);
|
|
116
|
-
const afterElements = this.extractElements(after, language);
|
|
117
|
-
|
|
118
|
-
const changes = this.computeChanges(beforeElements, afterElements, language);
|
|
119
|
-
|
|
120
|
-
return {
|
|
121
|
-
filePath,
|
|
122
|
-
taskId,
|
|
123
|
-
language,
|
|
124
|
-
changes,
|
|
125
|
-
functionsModified: changes
|
|
126
|
-
.filter((c) => c.changeType.includes('function'))
|
|
127
|
-
.map((c) => c.target),
|
|
128
|
-
functionsAdded: changes
|
|
129
|
-
.filter((c) => c.changeType === ChangeType.FUNCTION_ADDED)
|
|
130
|
-
.map((c) => c.target),
|
|
131
|
-
importsAdded: changes
|
|
132
|
-
.filter((c) => c.changeType === ChangeType.IMPORT_ADDED)
|
|
133
|
-
.map((c) => c.target),
|
|
134
|
-
totalLinesChanged: this.countChangedLines(before, after),
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* Detect programming language from file extension
|
|
140
|
-
*/
|
|
141
|
-
detectLanguage(ext) {
|
|
142
|
-
const languageMap = {
|
|
143
|
-
'.js': 'javascript',
|
|
144
|
-
'.jsx': 'javascript',
|
|
145
|
-
'.ts': 'typescript',
|
|
146
|
-
'.tsx': 'typescript',
|
|
147
|
-
'.py': 'python',
|
|
148
|
-
'.css': 'css',
|
|
149
|
-
'.scss': 'scss',
|
|
150
|
-
'.json': 'json',
|
|
151
|
-
'.md': 'markdown',
|
|
152
|
-
'.yaml': 'yaml',
|
|
153
|
-
'.yml': 'yaml',
|
|
154
|
-
};
|
|
155
|
-
return languageMap[ext] || 'text';
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
* Extract semantic elements from code
|
|
160
|
-
*/
|
|
161
|
-
extractElements(content, language) {
|
|
162
|
-
const elements = {
|
|
163
|
-
imports: [],
|
|
164
|
-
functions: [],
|
|
165
|
-
classes: [],
|
|
166
|
-
variables: [],
|
|
167
|
-
jsx: [],
|
|
168
|
-
other: [],
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
if (!content) return elements;
|
|
172
|
-
|
|
173
|
-
if (language === 'javascript' || language === 'typescript') {
|
|
174
|
-
// Extract imports
|
|
175
|
-
const importMatches = content.match(this.patterns.jsImport) || [];
|
|
176
|
-
elements.imports = importMatches.map((m) => ({
|
|
177
|
-
type: 'import',
|
|
178
|
-
content: m.trim(),
|
|
179
|
-
source: this.extractImportSource(m),
|
|
180
|
-
}));
|
|
181
|
-
|
|
182
|
-
// Extract functions
|
|
183
|
-
// DATA-003: the jsFunction regex can degrade to quadratic on pathological
|
|
184
|
-
// inputs (very large files with lots of whitespace). Cap the analyzed size
|
|
185
|
-
// and the iteration count so a single oversized file can't stall the engine.
|
|
186
|
-
// Normal files (well under the limits) are unaffected.
|
|
187
|
-
const MAX_FUNC_SCAN_BYTES = 200_000;
|
|
188
|
-
const MAX_FUNC_MATCHES = 10_000;
|
|
189
|
-
let match;
|
|
190
|
-
if (content.length <= MAX_FUNC_SCAN_BYTES) {
|
|
191
|
-
const funcRegex = new RegExp(this.patterns.jsFunction.source, 'gm');
|
|
192
|
-
let matchCount = 0;
|
|
193
|
-
while ((match = funcRegex.exec(content)) !== null) {
|
|
194
|
-
if (++matchCount > MAX_FUNC_MATCHES) break;
|
|
195
|
-
const name = match[1] || match[2] || match[3];
|
|
196
|
-
if (name) {
|
|
197
|
-
elements.functions.push({
|
|
198
|
-
type: 'function',
|
|
199
|
-
name,
|
|
200
|
-
content: this.extractFunctionBody(content, match.index),
|
|
201
|
-
location: this.getLocation(content, match.index),
|
|
202
|
-
});
|
|
203
|
-
}
|
|
204
|
-
// Guard against zero-width matches causing an infinite loop.
|
|
205
|
-
if (match.index === funcRegex.lastIndex) funcRegex.lastIndex++;
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
// Extract classes
|
|
210
|
-
const classRegex = new RegExp(this.patterns.jsClass.source, 'gm');
|
|
211
|
-
while ((match = classRegex.exec(content)) !== null) {
|
|
212
|
-
elements.classes.push({
|
|
213
|
-
type: 'class',
|
|
214
|
-
name: match[1],
|
|
215
|
-
content: this.extractClassBody(content, match.index),
|
|
216
|
-
location: this.getLocation(content, match.index),
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
|
-
} else if (language === 'python') {
|
|
220
|
-
// Extract Python imports
|
|
221
|
-
const pyImportMatches = content.match(this.patterns.pyImport) || [];
|
|
222
|
-
elements.imports = pyImportMatches.map((m) => ({
|
|
223
|
-
type: 'import',
|
|
224
|
-
content: m.trim(),
|
|
225
|
-
}));
|
|
226
|
-
|
|
227
|
-
// Extract Python functions
|
|
228
|
-
let match;
|
|
229
|
-
const pyFuncRegex = new RegExp(this.patterns.pyFunction.source, 'gm');
|
|
230
|
-
while ((match = pyFuncRegex.exec(content)) !== null) {
|
|
231
|
-
elements.functions.push({
|
|
232
|
-
type: 'function',
|
|
233
|
-
name: match[1],
|
|
234
|
-
location: this.getLocation(content, match.index),
|
|
235
|
-
});
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
// Extract Python classes
|
|
239
|
-
const pyClassRegex = new RegExp(this.patterns.pyClass.source, 'gm');
|
|
240
|
-
while ((match = pyClassRegex.exec(content)) !== null) {
|
|
241
|
-
elements.classes.push({
|
|
242
|
-
type: 'class',
|
|
243
|
-
name: match[1],
|
|
244
|
-
location: this.getLocation(content, match.index),
|
|
245
|
-
});
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
return elements;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
/**
|
|
253
|
-
* Compute semantic changes between two element sets
|
|
254
|
-
*/
|
|
255
|
-
computeChanges(before, after, _language) {
|
|
256
|
-
const changes = [];
|
|
257
|
-
|
|
258
|
-
// Compare imports
|
|
259
|
-
const beforeImports = new Set(before.imports.map((i) => i.content));
|
|
260
|
-
const afterImports = new Set(after.imports.map((i) => i.content));
|
|
261
|
-
|
|
262
|
-
for (const imp of after.imports) {
|
|
263
|
-
if (!beforeImports.has(imp.content)) {
|
|
264
|
-
changes.push({
|
|
265
|
-
changeType: ChangeType.IMPORT_ADDED,
|
|
266
|
-
target: imp.content,
|
|
267
|
-
location: 'imports',
|
|
268
|
-
});
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
for (const imp of before.imports) {
|
|
273
|
-
if (!afterImports.has(imp.content)) {
|
|
274
|
-
changes.push({
|
|
275
|
-
changeType: ChangeType.IMPORT_REMOVED,
|
|
276
|
-
target: imp.content,
|
|
277
|
-
location: 'imports',
|
|
278
|
-
});
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
// Compare functions
|
|
283
|
-
const beforeFuncs = new Map(before.functions.map((f) => [f.name, f]));
|
|
284
|
-
const afterFuncs = new Map(after.functions.map((f) => [f.name, f]));
|
|
285
|
-
|
|
286
|
-
for (const [name, func] of afterFuncs) {
|
|
287
|
-
if (!beforeFuncs.has(name)) {
|
|
288
|
-
changes.push({
|
|
289
|
-
changeType: ChangeType.FUNCTION_ADDED,
|
|
290
|
-
target: name,
|
|
291
|
-
location: func.location,
|
|
292
|
-
});
|
|
293
|
-
} else if (beforeFuncs.get(name).content !== func.content) {
|
|
294
|
-
changes.push({
|
|
295
|
-
changeType: ChangeType.FUNCTION_MODIFIED,
|
|
296
|
-
target: name,
|
|
297
|
-
location: func.location,
|
|
298
|
-
});
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
for (const [name, func] of beforeFuncs) {
|
|
303
|
-
if (!afterFuncs.has(name)) {
|
|
304
|
-
changes.push({
|
|
305
|
-
changeType: ChangeType.FUNCTION_REMOVED,
|
|
306
|
-
target: name,
|
|
307
|
-
location: func.location,
|
|
308
|
-
});
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
// Compare classes
|
|
313
|
-
const beforeClasses = new Map(before.classes.map((c) => [c.name, c]));
|
|
314
|
-
const afterClasses = new Map(after.classes.map((c) => [c.name, c]));
|
|
315
|
-
|
|
316
|
-
for (const [name, cls] of afterClasses) {
|
|
317
|
-
if (!beforeClasses.has(name)) {
|
|
318
|
-
changes.push({
|
|
319
|
-
changeType: ChangeType.CLASS_ADDED,
|
|
320
|
-
target: name,
|
|
321
|
-
location: cls.location,
|
|
322
|
-
});
|
|
323
|
-
} else if (beforeClasses.get(name).content !== cls.content) {
|
|
324
|
-
changes.push({
|
|
325
|
-
changeType: ChangeType.CLASS_MODIFIED,
|
|
326
|
-
target: name,
|
|
327
|
-
location: cls.location,
|
|
328
|
-
});
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
for (const [name] of beforeClasses) {
|
|
333
|
-
if (!afterClasses.has(name)) {
|
|
334
|
-
changes.push({
|
|
335
|
-
changeType: ChangeType.CLASS_REMOVED,
|
|
336
|
-
target: name,
|
|
337
|
-
location: 'class',
|
|
338
|
-
});
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
return changes;
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
// Helper methods
|
|
346
|
-
extractImportSource(importStr) {
|
|
347
|
-
const match = importStr.match(/from\s+['"]([^'"]+)['"]/);
|
|
348
|
-
return match ? match[1] : importStr;
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
extractFunctionBody(content, startIndex) {
|
|
352
|
-
// Simplified extraction - gets first 500 chars
|
|
353
|
-
return content.substring(startIndex, startIndex + 500);
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
extractClassBody(content, startIndex) {
|
|
357
|
-
return content.substring(startIndex, startIndex + 1000);
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
getLocation(content, index) {
|
|
361
|
-
const lines = content.substring(0, index).split('\n');
|
|
362
|
-
return `line ${lines.length}`;
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
countChangedLines(before, after) {
|
|
366
|
-
const beforeLines = (before || '').split('\n').length;
|
|
367
|
-
const afterLines = (after || '').split('\n').length;
|
|
368
|
-
return Math.abs(afterLines - beforeLines);
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
// ============================================================================
|
|
373
|
-
// CONFLICT DETECTOR
|
|
374
|
-
// ============================================================================
|
|
375
|
-
|
|
376
|
-
class ConflictDetector {
|
|
377
|
-
constructor(rulesLoader = null) {
|
|
378
|
-
this.rulesLoader = rulesLoader;
|
|
379
|
-
this.rules = this.buildCompatibilityRules();
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
/**
|
|
383
|
-
* Build compatibility rules for different change type combinations
|
|
384
|
-
* Merges default rules with custom rules from project configuration
|
|
385
|
-
*/
|
|
386
|
-
buildCompatibilityRules() {
|
|
387
|
-
return new Map([
|
|
388
|
-
// Compatible combinations (can auto-merge)
|
|
389
|
-
[
|
|
390
|
-
`${ChangeType.IMPORT_ADDED}:${ChangeType.IMPORT_ADDED}`,
|
|
391
|
-
{
|
|
392
|
-
compatible: true,
|
|
393
|
-
strategy: MergeStrategy.COMBINE,
|
|
394
|
-
reason: 'Different imports can coexist',
|
|
395
|
-
},
|
|
396
|
-
],
|
|
397
|
-
[
|
|
398
|
-
`${ChangeType.FUNCTION_ADDED}:${ChangeType.FUNCTION_ADDED}`,
|
|
399
|
-
{
|
|
400
|
-
compatible: true,
|
|
401
|
-
strategy: MergeStrategy.COMBINE,
|
|
402
|
-
reason: 'Different functions can coexist',
|
|
403
|
-
},
|
|
404
|
-
],
|
|
405
|
-
[
|
|
406
|
-
`${ChangeType.FUNCTION_ADDED}:${ChangeType.IMPORT_ADDED}`,
|
|
407
|
-
{
|
|
408
|
-
compatible: true,
|
|
409
|
-
strategy: MergeStrategy.COMBINE,
|
|
410
|
-
reason: 'Function and import additions are independent',
|
|
411
|
-
},
|
|
412
|
-
],
|
|
413
|
-
[
|
|
414
|
-
`${ChangeType.CLASS_ADDED}:${ChangeType.FUNCTION_ADDED}`,
|
|
415
|
-
{
|
|
416
|
-
compatible: true,
|
|
417
|
-
strategy: MergeStrategy.COMBINE,
|
|
418
|
-
reason: 'Class and function additions are independent',
|
|
419
|
-
},
|
|
420
|
-
],
|
|
421
|
-
|
|
422
|
-
// Incompatible combinations (need resolution)
|
|
423
|
-
[
|
|
424
|
-
`${ChangeType.FUNCTION_MODIFIED}:${ChangeType.FUNCTION_MODIFIED}`,
|
|
425
|
-
{
|
|
426
|
-
compatible: false,
|
|
427
|
-
strategy: MergeStrategy.AI_REQUIRED,
|
|
428
|
-
severity: ConflictSeverity.MEDIUM,
|
|
429
|
-
reason: 'Same function modified by multiple tasks',
|
|
430
|
-
},
|
|
431
|
-
],
|
|
432
|
-
[
|
|
433
|
-
`${ChangeType.CLASS_MODIFIED}:${ChangeType.CLASS_MODIFIED}`,
|
|
434
|
-
{
|
|
435
|
-
compatible: false,
|
|
436
|
-
strategy: MergeStrategy.AI_REQUIRED,
|
|
437
|
-
severity: ConflictSeverity.HIGH,
|
|
438
|
-
reason: 'Same class modified by multiple tasks',
|
|
439
|
-
},
|
|
440
|
-
],
|
|
441
|
-
[
|
|
442
|
-
`${ChangeType.FUNCTION_REMOVED}:${ChangeType.FUNCTION_MODIFIED}`,
|
|
443
|
-
{
|
|
444
|
-
compatible: false,
|
|
445
|
-
strategy: MergeStrategy.HUMAN_REQUIRED,
|
|
446
|
-
severity: ConflictSeverity.CRITICAL,
|
|
447
|
-
reason: 'Function removed by one task, modified by another',
|
|
448
|
-
},
|
|
449
|
-
],
|
|
450
|
-
[
|
|
451
|
-
`${ChangeType.IMPORT_REMOVED}:${ChangeType.IMPORT_MODIFIED}`,
|
|
452
|
-
{
|
|
453
|
-
compatible: false,
|
|
454
|
-
strategy: MergeStrategy.AI_REQUIRED,
|
|
455
|
-
severity: ConflictSeverity.MEDIUM,
|
|
456
|
-
reason: 'Import removed by one task, modified by another',
|
|
457
|
-
},
|
|
458
|
-
],
|
|
459
|
-
]);
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
/**
|
|
463
|
-
* Detect conflicts between multiple task analyses
|
|
464
|
-
* @param {Object} taskAnalyses - Map of taskId -> FileAnalysis
|
|
465
|
-
* @returns {Array} List of conflict regions
|
|
466
|
-
*/
|
|
467
|
-
detectConflicts(taskAnalyses) {
|
|
468
|
-
const conflicts = [];
|
|
469
|
-
const taskIds = Object.keys(taskAnalyses);
|
|
470
|
-
|
|
471
|
-
if (taskIds.length < 2) {
|
|
472
|
-
return conflicts;
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
// Compare each pair of tasks
|
|
476
|
-
for (let i = 0; i < taskIds.length; i++) {
|
|
477
|
-
for (let j = i + 1; j < taskIds.length; j++) {
|
|
478
|
-
const taskA = taskIds[i];
|
|
479
|
-
const taskB = taskIds[j];
|
|
480
|
-
const analysisA = taskAnalyses[taskA];
|
|
481
|
-
const analysisB = taskAnalyses[taskB];
|
|
482
|
-
|
|
483
|
-
// Find overlapping changes
|
|
484
|
-
const taskConflicts = this.findOverlappingChanges(
|
|
485
|
-
taskA,
|
|
486
|
-
analysisA.changes,
|
|
487
|
-
taskB,
|
|
488
|
-
analysisB.changes,
|
|
489
|
-
analysisA.filePath,
|
|
490
|
-
);
|
|
491
|
-
|
|
492
|
-
conflicts.push(...taskConflicts);
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
return conflicts;
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
/**
|
|
500
|
-
* Find overlapping changes between two tasks
|
|
501
|
-
*/
|
|
502
|
-
findOverlappingChanges(taskA, changesA, taskB, changesB, filePath) {
|
|
503
|
-
const conflicts = [];
|
|
504
|
-
|
|
505
|
-
for (const changeA of changesA) {
|
|
506
|
-
for (const changeB of changesB) {
|
|
507
|
-
// Check if changes affect the same target
|
|
508
|
-
if (changeA.target === changeB.target || changeA.location === changeB.location) {
|
|
509
|
-
const ruleKey = `${changeA.changeType}:${changeB.changeType}`;
|
|
510
|
-
const reverseKey = `${changeB.changeType}:${changeA.changeType}`;
|
|
511
|
-
|
|
512
|
-
const rule = this.rules.get(ruleKey) || this.rules.get(reverseKey);
|
|
513
|
-
|
|
514
|
-
if (rule && !rule.compatible) {
|
|
515
|
-
conflicts.push({
|
|
516
|
-
filePath,
|
|
517
|
-
location: changeA.location || changeB.location,
|
|
518
|
-
tasksInvolved: [taskA, taskB],
|
|
519
|
-
changeTypes: [changeA.changeType, changeB.changeType],
|
|
520
|
-
targets: [changeA.target, changeB.target],
|
|
521
|
-
severity: rule.severity || ConflictSeverity.MEDIUM,
|
|
522
|
-
mergeStrategy: rule.strategy,
|
|
523
|
-
reason: rule.reason,
|
|
524
|
-
canAutoMerge: rule.strategy === MergeStrategy.COMBINE,
|
|
525
|
-
});
|
|
526
|
-
}
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
return conflicts;
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
/**
|
|
535
|
-
* Get compatibility information for two change types
|
|
536
|
-
* Checks custom rules first, then falls back to defaults
|
|
537
|
-
*/
|
|
538
|
-
getCompatibility(changeTypeA, changeTypeB) {
|
|
539
|
-
// Check custom rules first if loader is available
|
|
540
|
-
if (this.rulesLoader) {
|
|
541
|
-
const customRule = this.rulesLoader.getCompatibilityRule(changeTypeA, changeTypeB);
|
|
542
|
-
if (customRule) {
|
|
543
|
-
return {
|
|
544
|
-
compatible: customRule.compatible ?? false,
|
|
545
|
-
strategy: this.mapStrategy(customRule.strategy),
|
|
546
|
-
severity: this.mapSeverity(customRule.severity),
|
|
547
|
-
reason: customRule.reason || 'Custom rule',
|
|
548
|
-
};
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
// Fall back to default rules
|
|
553
|
-
const key = `${changeTypeA}:${changeTypeB}`;
|
|
554
|
-
const reverseKey = `${changeTypeB}:${changeTypeA}`;
|
|
555
|
-
return (
|
|
556
|
-
this.rules.get(key) ||
|
|
557
|
-
this.rules.get(reverseKey) || {
|
|
558
|
-
compatible: false,
|
|
559
|
-
strategy: MergeStrategy.AI_REQUIRED,
|
|
560
|
-
severity: ConflictSeverity.MEDIUM,
|
|
561
|
-
reason: 'Unknown change type combination',
|
|
562
|
-
}
|
|
563
|
-
);
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
/**
|
|
567
|
-
* Map string strategy to MergeStrategy enum
|
|
568
|
-
*/
|
|
569
|
-
mapStrategy(strategy) {
|
|
570
|
-
if (!strategy) return MergeStrategy.AI_REQUIRED;
|
|
571
|
-
const strategyMap = {
|
|
572
|
-
combine: MergeStrategy.COMBINE,
|
|
573
|
-
take_newer: MergeStrategy.TAKE_NEWER,
|
|
574
|
-
take_larger: MergeStrategy.TAKE_LARGER,
|
|
575
|
-
ai_required: MergeStrategy.AI_REQUIRED,
|
|
576
|
-
human_required: MergeStrategy.HUMAN_REQUIRED,
|
|
577
|
-
};
|
|
578
|
-
return strategyMap[strategy.toLowerCase()] || MergeStrategy.AI_REQUIRED;
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
/**
|
|
582
|
-
* Map string severity to ConflictSeverity enum
|
|
583
|
-
*/
|
|
584
|
-
mapSeverity(severity) {
|
|
585
|
-
if (!severity) return ConflictSeverity.MEDIUM;
|
|
586
|
-
const severityMap = {
|
|
587
|
-
low: ConflictSeverity.LOW,
|
|
588
|
-
medium: ConflictSeverity.MEDIUM,
|
|
589
|
-
high: ConflictSeverity.HIGH,
|
|
590
|
-
critical: ConflictSeverity.CRITICAL,
|
|
591
|
-
};
|
|
592
|
-
return severityMap[severity.toLowerCase()] || ConflictSeverity.MEDIUM;
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
// ============================================================================
|
|
597
|
-
// AUTO MERGER
|
|
598
|
-
// ============================================================================
|
|
599
|
-
|
|
600
|
-
class AutoMerger {
|
|
601
|
-
/**
|
|
602
|
-
* Attempt to automatically merge changes without AI
|
|
603
|
-
* @param {Object} conflict - Conflict region
|
|
604
|
-
* @param {string} baseContent - Original file content
|
|
605
|
-
* @param {Object} taskContents - Map of taskId -> modified content
|
|
606
|
-
* @returns {Object} MergeResult
|
|
607
|
-
*/
|
|
608
|
-
tryAutoMerge(conflict, baseContent, taskContents) {
|
|
609
|
-
const { mergeStrategy, changeTypes, targets } = conflict;
|
|
610
|
-
|
|
611
|
-
// Only handle COMBINE strategy automatically
|
|
612
|
-
if (mergeStrategy !== MergeStrategy.COMBINE) {
|
|
613
|
-
return {
|
|
614
|
-
success: false,
|
|
615
|
-
reason: 'Strategy requires AI resolution',
|
|
616
|
-
};
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
// Handle import combinations
|
|
620
|
-
if (changeTypes.every((ct) => ct.includes('import_added'))) {
|
|
621
|
-
return this.combineImports(baseContent, taskContents);
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
// Handle function additions
|
|
625
|
-
if (changeTypes.every((ct) => ct === ChangeType.FUNCTION_ADDED)) {
|
|
626
|
-
return this.combineFunctions(baseContent, taskContents, targets);
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
return {
|
|
630
|
-
success: false,
|
|
631
|
-
reason: 'No auto-merge strategy available for this change combination',
|
|
632
|
-
};
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
/**
|
|
636
|
-
* Combine import statements from multiple tasks
|
|
637
|
-
*/
|
|
638
|
-
combineImports(baseContent, taskContents) {
|
|
639
|
-
const allImports = new Set();
|
|
640
|
-
const importRegex = /^(?:import\s+.+|from\s+.+import\s+.+)$/gm;
|
|
641
|
-
|
|
642
|
-
// Collect all imports from all versions
|
|
643
|
-
for (const content of Object.values(taskContents)) {
|
|
644
|
-
const matches = content.match(importRegex) || [];
|
|
645
|
-
matches.forEach((imp) => allImports.add(imp.trim()));
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
// Sort imports
|
|
649
|
-
const sortedImports = Array.from(allImports).sort();
|
|
650
|
-
|
|
651
|
-
// Replace imports in base content
|
|
652
|
-
const result = baseContent.replace(importRegex, '');
|
|
653
|
-
|
|
654
|
-
// Find first non-empty, non-comment line to insert imports
|
|
655
|
-
const lines = result.split('\n');
|
|
656
|
-
let insertIndex = 0;
|
|
657
|
-
for (let i = 0; i < lines.length; i++) {
|
|
658
|
-
if (
|
|
659
|
-
lines[i].trim() &&
|
|
660
|
-
!lines[i].trim().startsWith('//') &&
|
|
661
|
-
!lines[i].trim().startsWith('#')
|
|
662
|
-
) {
|
|
663
|
-
insertIndex = i;
|
|
664
|
-
break;
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
lines.splice(insertIndex, 0, ...sortedImports, '');
|
|
669
|
-
|
|
670
|
-
return {
|
|
671
|
-
success: true,
|
|
672
|
-
mergedContent: lines.join('\n'),
|
|
673
|
-
decision: MergeDecision.AUTO_MERGED,
|
|
674
|
-
explanation: `Combined ${allImports.size} imports from ${Object.keys(taskContents).length} tasks`,
|
|
675
|
-
};
|
|
676
|
-
}
|
|
677
|
-
|
|
678
|
-
/**
|
|
679
|
-
* Combine function additions from multiple tasks
|
|
680
|
-
*/
|
|
681
|
-
combineFunctions(baseContent, taskContents, functionNames) {
|
|
682
|
-
// This is a simplified version - real implementation would parse AST
|
|
683
|
-
let mergedContent = baseContent;
|
|
684
|
-
|
|
685
|
-
for (const [_taskId, content] of Object.entries(taskContents)) {
|
|
686
|
-
for (const funcName of functionNames) {
|
|
687
|
-
// Check if function exists in this task's content but not in merged
|
|
688
|
-
const funcRegex = new RegExp(
|
|
689
|
-
`(?:export\\s+)?(?:async\\s+)?function\\s+${funcName}\\s*\\([^)]*\\)\\s*\\{[^}]*\\}`,
|
|
690
|
-
'g',
|
|
691
|
-
);
|
|
692
|
-
|
|
693
|
-
const match = content.match(funcRegex);
|
|
694
|
-
if (match && !mergedContent.includes(`function ${funcName}`)) {
|
|
695
|
-
// Append function to merged content
|
|
696
|
-
mergedContent += '\n\n' + match[0];
|
|
697
|
-
}
|
|
698
|
-
}
|
|
699
|
-
}
|
|
700
|
-
|
|
701
|
-
return {
|
|
702
|
-
success: true,
|
|
703
|
-
mergedContent,
|
|
704
|
-
decision: MergeDecision.AUTO_MERGED,
|
|
705
|
-
explanation: `Combined ${functionNames.length} function additions`,
|
|
706
|
-
};
|
|
707
|
-
}
|
|
708
|
-
}
|
|
709
|
-
|
|
710
|
-
// ============================================================================
|
|
711
|
-
// AI RESOLVER
|
|
712
|
-
// ============================================================================
|
|
713
|
-
|
|
714
|
-
class AIResolver {
|
|
715
|
-
constructor(config = {}) {
|
|
716
|
-
this.maxContextTokens = config.maxContextTokens || 4000;
|
|
717
|
-
this.confidenceThreshold = config.confidenceThreshold || 0.7;
|
|
718
|
-
this.callCount = 0;
|
|
719
|
-
this.totalTokens = 0;
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
/**
|
|
723
|
-
* Resolve a conflict using AI (Claude CLI)
|
|
724
|
-
* @param {Object} conflict - Conflict region
|
|
725
|
-
* @param {string} baseContent - Original content
|
|
726
|
-
* @param {Object} taskSnapshots - Task changes and intents
|
|
727
|
-
* @returns {Promise<Object>} MergeResult
|
|
728
|
-
*/
|
|
729
|
-
async resolveConflict(conflict, baseContent, taskSnapshots) {
|
|
730
|
-
const context = this.buildContext(conflict, baseContent, taskSnapshots);
|
|
731
|
-
|
|
732
|
-
// Check token limit
|
|
733
|
-
const estimatedTokens = Math.ceil(context.length / 4);
|
|
734
|
-
if (estimatedTokens > this.maxContextTokens) {
|
|
735
|
-
return {
|
|
736
|
-
decision: MergeDecision.NEEDS_HUMAN_REVIEW,
|
|
737
|
-
reason: `Context too large (${estimatedTokens} tokens)`,
|
|
738
|
-
conflict,
|
|
739
|
-
};
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
const prompt = this.buildMergePrompt(conflict, context);
|
|
743
|
-
|
|
744
|
-
try {
|
|
745
|
-
const response = await this.callClaude(prompt);
|
|
746
|
-
this.callCount++;
|
|
747
|
-
this.totalTokens += estimatedTokens;
|
|
748
|
-
|
|
749
|
-
const mergedCode = this.extractCodeBlock(response);
|
|
750
|
-
|
|
751
|
-
if (mergedCode) {
|
|
752
|
-
return {
|
|
753
|
-
decision: MergeDecision.AI_MERGED,
|
|
754
|
-
mergedContent: mergedCode,
|
|
755
|
-
explanation: `AI resolved conflict at ${conflict.location}`,
|
|
756
|
-
confidence: this.assessConfidence(response),
|
|
757
|
-
aiCallsMade: 1,
|
|
758
|
-
tokensUsed: estimatedTokens,
|
|
759
|
-
};
|
|
760
|
-
} else {
|
|
761
|
-
return {
|
|
762
|
-
decision: MergeDecision.NEEDS_HUMAN_REVIEW,
|
|
763
|
-
reason: 'Could not parse AI response',
|
|
764
|
-
rawResponse: response,
|
|
765
|
-
conflict,
|
|
766
|
-
};
|
|
767
|
-
}
|
|
768
|
-
} catch (error) {
|
|
769
|
-
return {
|
|
770
|
-
decision: MergeDecision.FAILED,
|
|
771
|
-
error: error.message,
|
|
772
|
-
conflict,
|
|
773
|
-
};
|
|
774
|
-
}
|
|
775
|
-
}
|
|
776
|
-
|
|
777
|
-
/**
|
|
778
|
-
* Build context for AI resolution
|
|
779
|
-
*/
|
|
780
|
-
buildContext(conflict, baseContent, taskSnapshots) {
|
|
781
|
-
let context = '## Conflict Location\n';
|
|
782
|
-
context += `File: ${conflict.filePath}\n`;
|
|
783
|
-
context += `Location: ${conflict.location}\n`;
|
|
784
|
-
context += `Severity: ${conflict.severity}\n\n`;
|
|
785
|
-
|
|
786
|
-
context += `## Original Code (baseline)\n\`\`\`\n${baseContent}\n\`\`\`\n\n`;
|
|
787
|
-
|
|
788
|
-
context += '## Task Changes\n';
|
|
789
|
-
for (const [taskId, snapshot] of Object.entries(taskSnapshots)) {
|
|
790
|
-
if (conflict.tasksInvolved.includes(taskId)) {
|
|
791
|
-
context += `### ${taskId}\n`;
|
|
792
|
-
context += `Intent: ${snapshot.intent || 'Not specified'}\n`;
|
|
793
|
-
context += `Changes: ${snapshot.changes?.map((c) => c.changeType).join(', ')}\n`;
|
|
794
|
-
context += `\`\`\`\n${snapshot.content || ''}\n\`\`\`\n\n`;
|
|
795
|
-
}
|
|
796
|
-
}
|
|
797
|
-
|
|
798
|
-
return context;
|
|
799
|
-
}
|
|
800
|
-
|
|
801
|
-
/**
|
|
802
|
-
* Build the merge prompt for Claude
|
|
803
|
-
*/
|
|
804
|
-
buildMergePrompt(conflict, context) {
|
|
805
|
-
return `You are a code merge specialist. Your task is to merge conflicting changes from multiple development tasks into a single coherent result.
|
|
806
|
-
|
|
807
|
-
${context}
|
|
808
|
-
|
|
809
|
-
## Instructions
|
|
810
|
-
1. Analyze the intent of each task's changes
|
|
811
|
-
2. Preserve the functionality from ALL tasks where possible
|
|
812
|
-
3. Resolve any syntactic conflicts
|
|
813
|
-
4. Ensure the merged code is valid and follows best practices
|
|
814
|
-
5. If changes are incompatible, prioritize based on the apparent importance
|
|
815
|
-
|
|
816
|
-
## Output
|
|
817
|
-
Provide ONLY the merged code in a code block. No explanations outside the code block.
|
|
818
|
-
|
|
819
|
-
\`\`\`
|
|
820
|
-
// Your merged code here
|
|
821
|
-
\`\`\``;
|
|
822
|
-
}
|
|
823
|
-
|
|
824
|
-
/**
|
|
825
|
-
* Call Claude CLI for merge resolution
|
|
826
|
-
*/
|
|
827
|
-
async callClaude(prompt) {
|
|
828
|
-
return new Promise((resolve, reject) => {
|
|
829
|
-
try {
|
|
830
|
-
// Use Claude CLI in print mode
|
|
831
|
-
const result = execSync(
|
|
832
|
-
`claude --print --dangerously-skip-permissions -p "${prompt.replace(/"/g, '\\"').replace(/\n/g, '\\n')}"`,
|
|
833
|
-
{
|
|
834
|
-
encoding: 'utf8',
|
|
835
|
-
maxBuffer: 10 * 1024 * 1024,
|
|
836
|
-
timeout: 120000,
|
|
837
|
-
},
|
|
838
|
-
);
|
|
839
|
-
resolve(result);
|
|
840
|
-
} catch (error) {
|
|
841
|
-
reject(new Error(`Claude CLI error: ${error.message}`));
|
|
842
|
-
}
|
|
843
|
-
});
|
|
844
|
-
}
|
|
845
|
-
|
|
846
|
-
/**
|
|
847
|
-
* Extract code block from AI response
|
|
848
|
-
*/
|
|
849
|
-
extractCodeBlock(response) {
|
|
850
|
-
const codeBlockRegex = /```(?:\w+)?\n([\s\S]*?)```/;
|
|
851
|
-
const match = response.match(codeBlockRegex);
|
|
852
|
-
return match ? match[1].trim() : null;
|
|
853
|
-
}
|
|
854
|
-
|
|
855
|
-
/**
|
|
856
|
-
* Assess confidence in AI resolution
|
|
857
|
-
*/
|
|
858
|
-
assessConfidence(response) {
|
|
859
|
-
// Simple heuristic based on response characteristics
|
|
860
|
-
const hasCodeBlock = /```[\s\S]*```/.test(response);
|
|
861
|
-
const hasExplanation = response.length > 500;
|
|
862
|
-
const noErrorIndicators = !/(error|failed|cannot|unable)/i.test(response);
|
|
863
|
-
|
|
864
|
-
let confidence = 0.5;
|
|
865
|
-
if (hasCodeBlock) confidence += 0.3;
|
|
866
|
-
if (noErrorIndicators) confidence += 0.15;
|
|
867
|
-
if (hasExplanation) confidence += 0.05;
|
|
868
|
-
|
|
869
|
-
return Math.min(confidence, 1.0);
|
|
870
|
-
}
|
|
871
|
-
|
|
872
|
-
/**
|
|
873
|
-
* Get usage statistics
|
|
874
|
-
*/
|
|
875
|
-
getStats() {
|
|
876
|
-
return {
|
|
877
|
-
callsMade: this.callCount,
|
|
878
|
-
estimatedTokensUsed: this.totalTokens,
|
|
879
|
-
};
|
|
880
|
-
}
|
|
881
|
-
}
|
|
882
|
-
|
|
883
|
-
// ============================================================================
|
|
884
|
-
// CUSTOM RULES LOADER
|
|
885
|
-
// ============================================================================
|
|
886
|
-
|
|
887
|
-
/**
|
|
888
|
-
* Custom rules loader with caching (following ConfigLoader pattern)
|
|
889
|
-
* Loads project-specific merge rules from .sinapse/merge-rules.yaml
|
|
890
|
-
*/
|
|
891
|
-
class CustomRulesLoader {
|
|
892
|
-
constructor(rootPath = process.cwd()) {
|
|
893
|
-
this.rootPath = rootPath;
|
|
894
|
-
this.rulesPath = path.join(rootPath, '.sinapse', 'merge-rules.yaml');
|
|
895
|
-
this.cache = {
|
|
896
|
-
rules: null,
|
|
897
|
-
lastLoad: null,
|
|
898
|
-
TTL: 5 * 60 * 1000, // 5 minutes
|
|
899
|
-
};
|
|
900
|
-
}
|
|
901
|
-
|
|
902
|
-
/**
|
|
903
|
-
* Check if cache is valid
|
|
904
|
-
*/
|
|
905
|
-
isCacheValid() {
|
|
906
|
-
if (!this.cache.lastLoad || !this.cache.rules) return false;
|
|
907
|
-
const age = Date.now() - this.cache.lastLoad;
|
|
908
|
-
return age < this.cache.TTL;
|
|
909
|
-
}
|
|
910
|
-
|
|
911
|
-
/**
|
|
912
|
-
* Load custom rules from project
|
|
913
|
-
* @returns {Object|null} Custom rules or null if not found
|
|
914
|
-
*/
|
|
915
|
-
loadCustomRules() {
|
|
916
|
-
// Check cache first
|
|
917
|
-
if (this.isCacheValid()) {
|
|
918
|
-
return this.cache.rules;
|
|
919
|
-
}
|
|
920
|
-
|
|
921
|
-
try {
|
|
922
|
-
if (!fs.existsSync(this.rulesPath)) {
|
|
923
|
-
return null;
|
|
924
|
-
}
|
|
925
|
-
|
|
926
|
-
const content = fs.readFileSync(this.rulesPath, 'utf8');
|
|
927
|
-
const rules = yaml.load(content);
|
|
928
|
-
|
|
929
|
-
// Cache the rules
|
|
930
|
-
this.cache.rules = rules;
|
|
931
|
-
this.cache.lastLoad = Date.now();
|
|
932
|
-
|
|
933
|
-
return rules;
|
|
934
|
-
} catch (error) {
|
|
935
|
-
console.warn(`Warning: Could not load custom rules from ${this.rulesPath}: ${error.message}`);
|
|
936
|
-
return null;
|
|
937
|
-
}
|
|
938
|
-
}
|
|
939
|
-
|
|
940
|
-
/**
|
|
941
|
-
* Clear the cache
|
|
942
|
-
*/
|
|
943
|
-
clearCache() {
|
|
944
|
-
this.cache.rules = null;
|
|
945
|
-
this.cache.lastLoad = null;
|
|
946
|
-
}
|
|
947
|
-
|
|
948
|
-
/**
|
|
949
|
-
* Get default rules
|
|
950
|
-
*/
|
|
951
|
-
getDefaultRules() {
|
|
952
|
-
return {
|
|
953
|
-
compatibility: { rules: {} },
|
|
954
|
-
file_patterns: {
|
|
955
|
-
skip: [
|
|
956
|
-
'node_modules/**',
|
|
957
|
-
'.git/**',
|
|
958
|
-
'package-lock.json',
|
|
959
|
-
'yarn.lock',
|
|
960
|
-
'*.log',
|
|
961
|
-
'*.min.*',
|
|
962
|
-
'dist/**',
|
|
963
|
-
'build/**',
|
|
964
|
-
],
|
|
965
|
-
auto_merge: ['*.md', '*.txt', '.gitignore'],
|
|
966
|
-
human_review: ['package.json', 'tsconfig.json', '*.config.js', '.env*'],
|
|
967
|
-
ai_preferred: ['src/**/*.ts', 'src/**/*.tsx', 'src/**/*.js', 'src/**/*.jsx'],
|
|
968
|
-
},
|
|
969
|
-
languages: {
|
|
970
|
-
javascript: {
|
|
971
|
-
patterns: { imports: true, functions: true, classes: true, variables: true, jsx: true },
|
|
972
|
-
imports: { deduplicate: true, sort: true, group: true },
|
|
973
|
-
},
|
|
974
|
-
typescript: {
|
|
975
|
-
patterns: {
|
|
976
|
-
imports: true,
|
|
977
|
-
functions: true,
|
|
978
|
-
classes: true,
|
|
979
|
-
variables: true,
|
|
980
|
-
jsx: true,
|
|
981
|
-
types: true,
|
|
982
|
-
interfaces: true,
|
|
983
|
-
},
|
|
984
|
-
imports: { deduplicate: true, sort: true, group: true },
|
|
985
|
-
},
|
|
986
|
-
python: {
|
|
987
|
-
patterns: { imports: true, functions: true, classes: true },
|
|
988
|
-
imports: { deduplicate: true, sort: true },
|
|
989
|
-
},
|
|
990
|
-
css: {
|
|
991
|
-
patterns: { selectors: true, properties: true },
|
|
992
|
-
conflict_resolution: 'take_newer',
|
|
993
|
-
},
|
|
994
|
-
},
|
|
995
|
-
strategies: {
|
|
996
|
-
default: 'ai_required',
|
|
997
|
-
scenarios: {
|
|
998
|
-
parallel_additions: { strategy: 'combine', order: 'alphabetical' },
|
|
999
|
-
concurrent_modifications: { strategy: 'ai_required' },
|
|
1000
|
-
remove_vs_modify: { strategy: 'human_required' },
|
|
1001
|
-
},
|
|
1002
|
-
},
|
|
1003
|
-
ai: {
|
|
1004
|
-
enabled: true,
|
|
1005
|
-
max_context_tokens: 4000,
|
|
1006
|
-
confidence_threshold: 0.7,
|
|
1007
|
-
max_calls_per_merge: 10,
|
|
1008
|
-
},
|
|
1009
|
-
severity: {
|
|
1010
|
-
lines_threshold: { low: 10, medium: 50, high: 100, critical: 200 },
|
|
1011
|
-
functions_threshold: { low: 1, medium: 3, high: 5, critical: 10 },
|
|
1012
|
-
human_review_threshold: 'high',
|
|
1013
|
-
},
|
|
1014
|
-
hooks: {
|
|
1015
|
-
pre_merge: null,
|
|
1016
|
-
post_merge: null,
|
|
1017
|
-
on_conflict: null,
|
|
1018
|
-
on_human_review: null,
|
|
1019
|
-
},
|
|
1020
|
-
notifications: {
|
|
1021
|
-
on_complete: true,
|
|
1022
|
-
on_conflict: true,
|
|
1023
|
-
channels: [],
|
|
1024
|
-
},
|
|
1025
|
-
};
|
|
1026
|
-
}
|
|
1027
|
-
|
|
1028
|
-
/**
|
|
1029
|
-
* Merge custom rules with defaults
|
|
1030
|
-
* Custom rules take precedence over defaults
|
|
1031
|
-
* @returns {Object} Merged rules
|
|
1032
|
-
*/
|
|
1033
|
-
getMergedRules() {
|
|
1034
|
-
const defaults = this.getDefaultRules();
|
|
1035
|
-
const custom = this.loadCustomRules();
|
|
1036
|
-
|
|
1037
|
-
if (!custom) {
|
|
1038
|
-
return defaults;
|
|
1039
|
-
}
|
|
1040
|
-
|
|
1041
|
-
// Deep merge with custom taking precedence
|
|
1042
|
-
return this.deepMerge(defaults, custom);
|
|
1043
|
-
}
|
|
1044
|
-
|
|
1045
|
-
/**
|
|
1046
|
-
* Deep merge two objects
|
|
1047
|
-
* @param {Object} target - Base object
|
|
1048
|
-
* @param {Object} source - Object to merge (takes precedence)
|
|
1049
|
-
* @returns {Object} Merged object
|
|
1050
|
-
*/
|
|
1051
|
-
deepMerge(target, source) {
|
|
1052
|
-
const result = { ...target };
|
|
1053
|
-
|
|
1054
|
-
for (const key of Object.keys(source)) {
|
|
1055
|
-
if (source[key] === null || source[key] === undefined) {
|
|
1056
|
-
continue;
|
|
1057
|
-
}
|
|
1058
|
-
|
|
1059
|
-
if (
|
|
1060
|
-
typeof source[key] === 'object' &&
|
|
1061
|
-
!Array.isArray(source[key]) &&
|
|
1062
|
-
typeof target[key] === 'object' &&
|
|
1063
|
-
!Array.isArray(target[key])
|
|
1064
|
-
) {
|
|
1065
|
-
result[key] = this.deepMerge(target[key] || {}, source[key]);
|
|
1066
|
-
} else {
|
|
1067
|
-
result[key] = source[key];
|
|
1068
|
-
}
|
|
1069
|
-
}
|
|
1070
|
-
|
|
1071
|
-
return result;
|
|
1072
|
-
}
|
|
1073
|
-
|
|
1074
|
-
/**
|
|
1075
|
-
* Check if file matches any pattern in list
|
|
1076
|
-
* @param {string} filePath - File path to check
|
|
1077
|
-
* @param {string[]} patterns - Glob patterns to match against
|
|
1078
|
-
* @returns {boolean} True if matches any pattern
|
|
1079
|
-
*/
|
|
1080
|
-
matchesPattern(filePath, patterns) {
|
|
1081
|
-
if (!patterns || !Array.isArray(patterns)) return false;
|
|
1082
|
-
|
|
1083
|
-
for (const pattern of patterns) {
|
|
1084
|
-
// Escape special regex characters first, then convert glob patterns
|
|
1085
|
-
const regexPattern = pattern
|
|
1086
|
-
.replace(/[.+^${}()|[\]\\]/g, '\\$&') // Escape regex special chars
|
|
1087
|
-
.replace(/\*\*/g, '<<<GLOBSTAR>>>') // Temp placeholder for **
|
|
1088
|
-
.replace(/\*/g, '[^/]*') // Single * = anything except /
|
|
1089
|
-
.replace(/<<<GLOBSTAR>>>/g, '.*') // ** = anything including /
|
|
1090
|
-
.replace(/\?/g, '.'); // ? = single char
|
|
1091
|
-
|
|
1092
|
-
// Allow pattern to match anywhere in the path (not just start)
|
|
1093
|
-
// For patterns like 'node_modules/**', match anywhere
|
|
1094
|
-
const regex = new RegExp(`(^|/)${regexPattern}(/|$)|^${regexPattern}$`);
|
|
1095
|
-
|
|
1096
|
-
if (regex.test(filePath)) {
|
|
1097
|
-
return true;
|
|
1098
|
-
}
|
|
1099
|
-
}
|
|
1100
|
-
|
|
1101
|
-
return false;
|
|
1102
|
-
}
|
|
1103
|
-
|
|
1104
|
-
/**
|
|
1105
|
-
* Get file handling category based on patterns
|
|
1106
|
-
* @param {string} filePath - File path to categorize
|
|
1107
|
-
* @returns {string} Category: 'skip', 'auto_merge', 'human_review', 'ai_preferred', 'default'
|
|
1108
|
-
*/
|
|
1109
|
-
getFileCategory(filePath) {
|
|
1110
|
-
const rules = this.getMergedRules();
|
|
1111
|
-
const patterns = rules.file_patterns || {};
|
|
1112
|
-
|
|
1113
|
-
if (this.matchesPattern(filePath, patterns.skip)) return 'skip';
|
|
1114
|
-
if (this.matchesPattern(filePath, patterns.human_review)) return 'human_review';
|
|
1115
|
-
if (this.matchesPattern(filePath, patterns.auto_merge)) return 'auto_merge';
|
|
1116
|
-
if (this.matchesPattern(filePath, patterns.ai_preferred)) return 'ai_preferred';
|
|
1117
|
-
|
|
1118
|
-
return 'default';
|
|
1119
|
-
}
|
|
1120
|
-
|
|
1121
|
-
/**
|
|
1122
|
-
* Get compatibility rule for change type combination
|
|
1123
|
-
* @param {string} changeTypeA - First change type
|
|
1124
|
-
* @param {string} changeTypeB - Second change type
|
|
1125
|
-
* @returns {Object|null} Custom rule or null if not defined
|
|
1126
|
-
*/
|
|
1127
|
-
getCompatibilityRule(changeTypeA, changeTypeB) {
|
|
1128
|
-
const rules = this.getMergedRules();
|
|
1129
|
-
const customRules = rules.compatibility?.rules || {};
|
|
1130
|
-
|
|
1131
|
-
// Check both orderings
|
|
1132
|
-
const key1 = `${changeTypeA}:${changeTypeB}`;
|
|
1133
|
-
const key2 = `${changeTypeB}:${changeTypeA}`;
|
|
1134
|
-
|
|
1135
|
-
return customRules[key1] || customRules[key2] || null;
|
|
1136
|
-
}
|
|
1137
|
-
|
|
1138
|
-
/**
|
|
1139
|
-
* Get language-specific configuration
|
|
1140
|
-
* @param {string} language - Language name
|
|
1141
|
-
* @returns {Object} Language config
|
|
1142
|
-
*/
|
|
1143
|
-
getLanguageConfig(language) {
|
|
1144
|
-
const rules = this.getMergedRules();
|
|
1145
|
-
return rules.languages?.[language] || {};
|
|
1146
|
-
}
|
|
1147
|
-
|
|
1148
|
-
/**
|
|
1149
|
-
* Get AI configuration
|
|
1150
|
-
* @returns {Object} AI config
|
|
1151
|
-
*/
|
|
1152
|
-
getAIConfig() {
|
|
1153
|
-
const rules = this.getMergedRules();
|
|
1154
|
-
return rules.ai || { enabled: true, max_context_tokens: 4000, confidence_threshold: 0.7 };
|
|
1155
|
-
}
|
|
1156
|
-
|
|
1157
|
-
/**
|
|
1158
|
-
* Get severity thresholds
|
|
1159
|
-
* @returns {Object} Severity config
|
|
1160
|
-
*/
|
|
1161
|
-
getSeverityConfig() {
|
|
1162
|
-
const rules = this.getMergedRules();
|
|
1163
|
-
return rules.severity || {};
|
|
1164
|
-
}
|
|
1165
|
-
|
|
1166
|
-
/**
|
|
1167
|
-
* Get hooks configuration
|
|
1168
|
-
* @returns {Object} Hooks config
|
|
1169
|
-
*/
|
|
1170
|
-
getHooks() {
|
|
1171
|
-
const rules = this.getMergedRules();
|
|
1172
|
-
return rules.hooks || {};
|
|
1173
|
-
}
|
|
1174
|
-
|
|
1175
|
-
/**
|
|
1176
|
-
* Execute a hook if defined
|
|
1177
|
-
* @param {string} hookName - Name of hook to execute
|
|
1178
|
-
* @param {Object} context - Context data for the hook
|
|
1179
|
-
* @returns {Promise<boolean>} True if hook executed successfully
|
|
1180
|
-
*/
|
|
1181
|
-
async executeHook(hookName, context = {}) {
|
|
1182
|
-
const hooks = this.getHooks();
|
|
1183
|
-
const hookCommand = hooks[hookName];
|
|
1184
|
-
|
|
1185
|
-
if (!hookCommand) return true;
|
|
1186
|
-
|
|
1187
|
-
try {
|
|
1188
|
-
execSync(hookCommand, {
|
|
1189
|
-
cwd: this.rootPath,
|
|
1190
|
-
encoding: 'utf8',
|
|
1191
|
-
env: {
|
|
1192
|
-
...process.env,
|
|
1193
|
-
SINAPSE_MERGE_HOOK: hookName,
|
|
1194
|
-
SINAPSE_MERGE_CONTEXT: JSON.stringify(context),
|
|
1195
|
-
},
|
|
1196
|
-
});
|
|
1197
|
-
return true;
|
|
1198
|
-
} catch (error) {
|
|
1199
|
-
console.warn(`Warning: Hook ${hookName} failed: ${error.message}`);
|
|
1200
|
-
return false;
|
|
1201
|
-
}
|
|
1202
|
-
}
|
|
1203
|
-
}
|
|
1204
|
-
|
|
1205
|
-
// ============================================================================
|
|
1206
|
-
// SEMANTIC MERGE ENGINE (ORCHESTRATOR)
|
|
1207
|
-
// ============================================================================
|
|
1208
|
-
|
|
1209
|
-
class SemanticMergeEngine extends EventEmitter {
|
|
1210
|
-
constructor(config = {}) {
|
|
1211
|
-
super();
|
|
1212
|
-
|
|
1213
|
-
this.rootPath = config.rootPath || process.cwd();
|
|
1214
|
-
this.dryRun = config.dryRun || false;
|
|
1215
|
-
|
|
1216
|
-
// Initialize custom rules loader
|
|
1217
|
-
this.rulesLoader = new CustomRulesLoader(this.rootPath);
|
|
1218
|
-
const aiConfig = this.rulesLoader.getAIConfig();
|
|
1219
|
-
|
|
1220
|
-
// Apply config with custom rules as defaults
|
|
1221
|
-
this.enableAI = config.enableAI !== undefined ? config.enableAI : aiConfig.enabled;
|
|
1222
|
-
this.confidenceThreshold = config.confidenceThreshold || aiConfig.confidence_threshold || 0.7;
|
|
1223
|
-
|
|
1224
|
-
// Initialize components
|
|
1225
|
-
this.analyzer = new SemanticAnalyzer();
|
|
1226
|
-
this.detector = new ConflictDetector(this.rulesLoader);
|
|
1227
|
-
this.autoMerger = new AutoMerger();
|
|
1228
|
-
this.aiResolver = new AIResolver({
|
|
1229
|
-
maxContextTokens: config.maxContextTokens || aiConfig.max_context_tokens || 4000,
|
|
1230
|
-
confidenceThreshold: this.confidenceThreshold,
|
|
1231
|
-
});
|
|
1232
|
-
|
|
1233
|
-
// Storage
|
|
1234
|
-
this.storageDir = config.storageDir || path.join(this.rootPath, '.sinapse', 'merge');
|
|
1235
|
-
}
|
|
1236
|
-
|
|
1237
|
-
/**
|
|
1238
|
-
* Merge changes from multiple task worktrees
|
|
1239
|
-
* @param {Array} taskRequests - Array of { taskId, worktreePath, branch }
|
|
1240
|
-
* @param {string} targetBranch - Branch to merge into
|
|
1241
|
-
* @returns {Promise<Object>} MergeReport
|
|
1242
|
-
*/
|
|
1243
|
-
async merge(taskRequests, targetBranch = 'main') {
|
|
1244
|
-
const report = {
|
|
1245
|
-
startedAt: new Date().toISOString(),
|
|
1246
|
-
tasks: taskRequests.map((t) => t.taskId),
|
|
1247
|
-
targetBranch,
|
|
1248
|
-
filesAnalyzed: 0,
|
|
1249
|
-
conflictsDetected: 0,
|
|
1250
|
-
autoMerged: 0,
|
|
1251
|
-
aiMerged: 0,
|
|
1252
|
-
needsHumanReview: 0,
|
|
1253
|
-
failed: 0,
|
|
1254
|
-
results: [],
|
|
1255
|
-
errors: [],
|
|
1256
|
-
rulesUsed: this.rulesLoader ? 'custom' : 'default',
|
|
1257
|
-
};
|
|
1258
|
-
|
|
1259
|
-
this.emit('merge_started', { tasks: report.tasks, targetBranch });
|
|
1260
|
-
|
|
1261
|
-
try {
|
|
1262
|
-
// Execute pre_merge hook if defined
|
|
1263
|
-
if (this.rulesLoader) {
|
|
1264
|
-
await this.rulesLoader.executeHook('pre_merge', {
|
|
1265
|
-
tasks: report.tasks,
|
|
1266
|
-
targetBranch,
|
|
1267
|
-
});
|
|
1268
|
-
}
|
|
1269
|
-
|
|
1270
|
-
// Step 1: Get baseline (target branch content)
|
|
1271
|
-
const baseline = await this.getBaseline(targetBranch);
|
|
1272
|
-
|
|
1273
|
-
// Step 2: Get changes from each task
|
|
1274
|
-
const taskSnapshots = {};
|
|
1275
|
-
for (const request of taskRequests) {
|
|
1276
|
-
taskSnapshots[request.taskId] = await this.getTaskSnapshot(request);
|
|
1277
|
-
}
|
|
1278
|
-
|
|
1279
|
-
// Step 3: Find modified files across all tasks
|
|
1280
|
-
const modifiedFiles = this.findModifiedFiles(taskSnapshots);
|
|
1281
|
-
report.filesAnalyzed = modifiedFiles.size;
|
|
1282
|
-
|
|
1283
|
-
// Step 4: Process each file
|
|
1284
|
-
for (const filePath of modifiedFiles) {
|
|
1285
|
-
const fileResult = await this.mergeFile(filePath, baseline[filePath] || '', taskSnapshots);
|
|
1286
|
-
|
|
1287
|
-
report.results.push(fileResult);
|
|
1288
|
-
|
|
1289
|
-
switch (fileResult.decision) {
|
|
1290
|
-
case MergeDecision.AUTO_MERGED:
|
|
1291
|
-
report.autoMerged++;
|
|
1292
|
-
break;
|
|
1293
|
-
case MergeDecision.AI_MERGED:
|
|
1294
|
-
report.aiMerged++;
|
|
1295
|
-
break;
|
|
1296
|
-
case MergeDecision.NEEDS_HUMAN_REVIEW:
|
|
1297
|
-
report.needsHumanReview++;
|
|
1298
|
-
// Execute on_human_review hook
|
|
1299
|
-
if (this.rulesLoader) {
|
|
1300
|
-
await this.rulesLoader.executeHook('on_human_review', {
|
|
1301
|
-
filePath,
|
|
1302
|
-
conflicts: fileResult.conflicts,
|
|
1303
|
-
});
|
|
1304
|
-
}
|
|
1305
|
-
break;
|
|
1306
|
-
case MergeDecision.FAILED:
|
|
1307
|
-
report.failed++;
|
|
1308
|
-
break;
|
|
1309
|
-
}
|
|
1310
|
-
|
|
1311
|
-
// Execute on_conflict hook for files with conflicts
|
|
1312
|
-
if (fileResult.conflicts && fileResult.conflicts.length > 0 && this.rulesLoader) {
|
|
1313
|
-
await this.rulesLoader.executeHook('on_conflict', {
|
|
1314
|
-
filePath,
|
|
1315
|
-
conflictCount: fileResult.conflicts.length,
|
|
1316
|
-
});
|
|
1317
|
-
}
|
|
1318
|
-
}
|
|
1319
|
-
|
|
1320
|
-
// Step 5: Apply merged changes (if not dry run)
|
|
1321
|
-
if (!this.dryRun) {
|
|
1322
|
-
await this.applyMergedChanges(report.results);
|
|
1323
|
-
}
|
|
1324
|
-
|
|
1325
|
-
report.completedAt = new Date().toISOString();
|
|
1326
|
-
report.status =
|
|
1327
|
-
report.failed === 0 && report.needsHumanReview === 0
|
|
1328
|
-
? 'success'
|
|
1329
|
-
: report.needsHumanReview > 0
|
|
1330
|
-
? 'needs_review'
|
|
1331
|
-
: 'partial';
|
|
1332
|
-
|
|
1333
|
-
this.emit('merge_completed', report);
|
|
1334
|
-
|
|
1335
|
-
// Execute post_merge hook if defined
|
|
1336
|
-
if (this.rulesLoader) {
|
|
1337
|
-
await this.rulesLoader.executeHook('post_merge', {
|
|
1338
|
-
status: report.status,
|
|
1339
|
-
filesAnalyzed: report.filesAnalyzed,
|
|
1340
|
-
autoMerged: report.autoMerged,
|
|
1341
|
-
aiMerged: report.aiMerged,
|
|
1342
|
-
});
|
|
1343
|
-
}
|
|
1344
|
-
|
|
1345
|
-
// Save report
|
|
1346
|
-
await this.saveReport(report);
|
|
1347
|
-
|
|
1348
|
-
return report;
|
|
1349
|
-
} catch (error) {
|
|
1350
|
-
report.errors.push(error.message);
|
|
1351
|
-
report.status = 'error';
|
|
1352
|
-
report.completedAt = new Date().toISOString();
|
|
1353
|
-
|
|
1354
|
-
this.emit('merge_error', { error: error.message });
|
|
1355
|
-
|
|
1356
|
-
return report;
|
|
1357
|
-
}
|
|
1358
|
-
}
|
|
1359
|
-
|
|
1360
|
-
/**
|
|
1361
|
-
* Merge a single file from multiple tasks
|
|
1362
|
-
*/
|
|
1363
|
-
async mergeFile(filePath, baseContent, taskSnapshots) {
|
|
1364
|
-
this.emit('file_processing', { filePath });
|
|
1365
|
-
|
|
1366
|
-
// Check file category for special handling
|
|
1367
|
-
const category = this.getFileCategory(filePath);
|
|
1368
|
-
|
|
1369
|
-
// Handle human_review category
|
|
1370
|
-
if (category === 'human_review') {
|
|
1371
|
-
return {
|
|
1372
|
-
filePath,
|
|
1373
|
-
decision: MergeDecision.NEEDS_HUMAN_REVIEW,
|
|
1374
|
-
mergedContent: baseContent,
|
|
1375
|
-
explanation: `File ${filePath} is marked for human review in merge rules`,
|
|
1376
|
-
category,
|
|
1377
|
-
};
|
|
1378
|
-
}
|
|
1379
|
-
|
|
1380
|
-
// Step 1: Analyze changes from each task
|
|
1381
|
-
const taskAnalyses = {};
|
|
1382
|
-
const taskContents = {};
|
|
1383
|
-
|
|
1384
|
-
for (const [taskId, snapshot] of Object.entries(taskSnapshots)) {
|
|
1385
|
-
const taskContent = snapshot.files?.[filePath];
|
|
1386
|
-
if (taskContent !== undefined) {
|
|
1387
|
-
taskAnalyses[taskId] = this.analyzer.analyzeDiff(
|
|
1388
|
-
filePath,
|
|
1389
|
-
baseContent,
|
|
1390
|
-
taskContent,
|
|
1391
|
-
taskId,
|
|
1392
|
-
);
|
|
1393
|
-
taskContents[taskId] = taskContent;
|
|
1394
|
-
}
|
|
1395
|
-
}
|
|
1396
|
-
|
|
1397
|
-
// If only one task modified the file, no conflict
|
|
1398
|
-
if (Object.keys(taskAnalyses).length <= 1) {
|
|
1399
|
-
const [taskId, content] = Object.entries(taskContents)[0] || [null, baseContent];
|
|
1400
|
-
return {
|
|
1401
|
-
filePath,
|
|
1402
|
-
decision: MergeDecision.AUTO_MERGED,
|
|
1403
|
-
mergedContent: content,
|
|
1404
|
-
explanation: taskId ? `Single task ${taskId} modified file` : 'No changes',
|
|
1405
|
-
category,
|
|
1406
|
-
};
|
|
1407
|
-
}
|
|
1408
|
-
|
|
1409
|
-
// Handle auto_merge category (simpler merge, take most recent)
|
|
1410
|
-
if (category === 'auto_merge') {
|
|
1411
|
-
// Take the content with most changes
|
|
1412
|
-
let maxChanges = 0;
|
|
1413
|
-
let bestContent = baseContent;
|
|
1414
|
-
let bestTaskId = null;
|
|
1415
|
-
|
|
1416
|
-
for (const [taskId, analysis] of Object.entries(taskAnalyses)) {
|
|
1417
|
-
if (analysis.changes.length > maxChanges) {
|
|
1418
|
-
maxChanges = analysis.changes.length;
|
|
1419
|
-
bestContent = taskContents[taskId];
|
|
1420
|
-
bestTaskId = taskId;
|
|
1421
|
-
}
|
|
1422
|
-
}
|
|
1423
|
-
|
|
1424
|
-
return {
|
|
1425
|
-
filePath,
|
|
1426
|
-
decision: MergeDecision.AUTO_MERGED,
|
|
1427
|
-
mergedContent: bestContent,
|
|
1428
|
-
explanation: `Auto-merge category: used changes from task ${bestTaskId}`,
|
|
1429
|
-
category,
|
|
1430
|
-
};
|
|
1431
|
-
}
|
|
1432
|
-
|
|
1433
|
-
// Step 2: Detect conflicts
|
|
1434
|
-
const conflicts = this.detector.detectConflicts(taskAnalyses);
|
|
1435
|
-
|
|
1436
|
-
if (conflicts.length === 0) {
|
|
1437
|
-
// No conflicts - combine all changes
|
|
1438
|
-
const combined = this.combineNonConflictingChanges(baseContent, taskContents, taskAnalyses);
|
|
1439
|
-
return {
|
|
1440
|
-
filePath,
|
|
1441
|
-
decision: MergeDecision.AUTO_MERGED,
|
|
1442
|
-
mergedContent: combined,
|
|
1443
|
-
explanation: 'No conflicts detected, changes combined',
|
|
1444
|
-
};
|
|
1445
|
-
}
|
|
1446
|
-
|
|
1447
|
-
// Step 3: Try auto-merge for each conflict
|
|
1448
|
-
const results = [];
|
|
1449
|
-
for (const conflict of conflicts) {
|
|
1450
|
-
const autoResult = this.autoMerger.tryAutoMerge(conflict, baseContent, taskContents);
|
|
1451
|
-
|
|
1452
|
-
if (autoResult.success) {
|
|
1453
|
-
results.push({
|
|
1454
|
-
conflict,
|
|
1455
|
-
result: autoResult,
|
|
1456
|
-
decision: MergeDecision.AUTO_MERGED,
|
|
1457
|
-
});
|
|
1458
|
-
} else if (this.enableAI && conflict.mergeStrategy === MergeStrategy.AI_REQUIRED) {
|
|
1459
|
-
// Step 4: Use AI for complex conflicts
|
|
1460
|
-
const aiResult = await this.aiResolver.resolveConflict(
|
|
1461
|
-
conflict,
|
|
1462
|
-
baseContent,
|
|
1463
|
-
taskSnapshots,
|
|
1464
|
-
);
|
|
1465
|
-
results.push({
|
|
1466
|
-
conflict,
|
|
1467
|
-
result: aiResult,
|
|
1468
|
-
decision: aiResult.decision,
|
|
1469
|
-
});
|
|
1470
|
-
} else {
|
|
1471
|
-
results.push({
|
|
1472
|
-
conflict,
|
|
1473
|
-
result: { reason: 'No auto-merge strategy and AI disabled' },
|
|
1474
|
-
decision: MergeDecision.NEEDS_HUMAN_REVIEW,
|
|
1475
|
-
});
|
|
1476
|
-
}
|
|
1477
|
-
}
|
|
1478
|
-
|
|
1479
|
-
// Determine overall file decision
|
|
1480
|
-
const decisions = results.map((r) => r.decision);
|
|
1481
|
-
let finalDecision;
|
|
1482
|
-
let finalContent = baseContent;
|
|
1483
|
-
|
|
1484
|
-
if (decisions.every((d) => d === MergeDecision.AUTO_MERGED || d === MergeDecision.AI_MERGED)) {
|
|
1485
|
-
finalDecision = decisions.includes(MergeDecision.AI_MERGED)
|
|
1486
|
-
? MergeDecision.AI_MERGED
|
|
1487
|
-
: MergeDecision.AUTO_MERGED;
|
|
1488
|
-
|
|
1489
|
-
// Apply all successful merges
|
|
1490
|
-
for (const r of results) {
|
|
1491
|
-
if (r.result.mergedContent) {
|
|
1492
|
-
finalContent = r.result.mergedContent;
|
|
1493
|
-
}
|
|
1494
|
-
}
|
|
1495
|
-
} else if (decisions.includes(MergeDecision.FAILED)) {
|
|
1496
|
-
finalDecision = MergeDecision.FAILED;
|
|
1497
|
-
} else {
|
|
1498
|
-
finalDecision = MergeDecision.NEEDS_HUMAN_REVIEW;
|
|
1499
|
-
}
|
|
1500
|
-
|
|
1501
|
-
return {
|
|
1502
|
-
filePath,
|
|
1503
|
-
decision: finalDecision,
|
|
1504
|
-
mergedContent: finalContent,
|
|
1505
|
-
conflicts: results,
|
|
1506
|
-
explanation: `${results.length} conflicts processed`,
|
|
1507
|
-
};
|
|
1508
|
-
}
|
|
1509
|
-
|
|
1510
|
-
/**
|
|
1511
|
-
* Combine non-conflicting changes from multiple tasks
|
|
1512
|
-
*/
|
|
1513
|
-
combineNonConflictingChanges(baseContent, taskContents, taskAnalyses) {
|
|
1514
|
-
// Simple strategy: use the most changed version
|
|
1515
|
-
let maxChanges = 0;
|
|
1516
|
-
let bestContent = baseContent;
|
|
1517
|
-
|
|
1518
|
-
for (const [taskId, analysis] of Object.entries(taskAnalyses)) {
|
|
1519
|
-
if (analysis.changes.length > maxChanges) {
|
|
1520
|
-
maxChanges = analysis.changes.length;
|
|
1521
|
-
bestContent = taskContents[taskId];
|
|
1522
|
-
}
|
|
1523
|
-
}
|
|
1524
|
-
|
|
1525
|
-
return bestContent;
|
|
1526
|
-
}
|
|
1527
|
-
|
|
1528
|
-
/**
|
|
1529
|
-
* Get baseline content from target branch
|
|
1530
|
-
*/
|
|
1531
|
-
async getBaseline(branch) {
|
|
1532
|
-
const files = {};
|
|
1533
|
-
|
|
1534
|
-
try {
|
|
1535
|
-
// Get list of files
|
|
1536
|
-
const fileList = execFileSync('git', ['ls-tree', '-r', '--name-only', branch], {
|
|
1537
|
-
cwd: this.rootPath,
|
|
1538
|
-
encoding: 'utf8',
|
|
1539
|
-
})
|
|
1540
|
-
.trim()
|
|
1541
|
-
.split('\n');
|
|
1542
|
-
|
|
1543
|
-
for (const filePath of fileList) {
|
|
1544
|
-
if (this.shouldProcessFile(filePath)) {
|
|
1545
|
-
try {
|
|
1546
|
-
const content = execFileSync('git', ['show', `${branch}:${filePath}`], {
|
|
1547
|
-
cwd: this.rootPath,
|
|
1548
|
-
encoding: 'utf8',
|
|
1549
|
-
});
|
|
1550
|
-
files[filePath] = content;
|
|
1551
|
-
} catch {
|
|
1552
|
-
// File might not exist in this branch
|
|
1553
|
-
}
|
|
1554
|
-
}
|
|
1555
|
-
}
|
|
1556
|
-
} catch (error) {
|
|
1557
|
-
console.warn(`Warning: Could not get baseline from ${branch}: ${error.message}`);
|
|
1558
|
-
}
|
|
1559
|
-
|
|
1560
|
-
return files;
|
|
1561
|
-
}
|
|
1562
|
-
|
|
1563
|
-
/**
|
|
1564
|
-
* Get snapshot of task changes
|
|
1565
|
-
*/
|
|
1566
|
-
async getTaskSnapshot(request) {
|
|
1567
|
-
const { taskId, worktreePath, branch, intent } = request;
|
|
1568
|
-
const snapshot = {
|
|
1569
|
-
taskId,
|
|
1570
|
-
intent,
|
|
1571
|
-
files: {},
|
|
1572
|
-
changes: [],
|
|
1573
|
-
};
|
|
1574
|
-
|
|
1575
|
-
const workDir = worktreePath || this.rootPath;
|
|
1576
|
-
|
|
1577
|
-
try {
|
|
1578
|
-
// Get modified files in this task
|
|
1579
|
-
const diffOutput = execFileSync('git', ['diff', '--name-only', `${branch || 'main'}...HEAD`], {
|
|
1580
|
-
cwd: workDir,
|
|
1581
|
-
encoding: 'utf8',
|
|
1582
|
-
}).trim();
|
|
1583
|
-
|
|
1584
|
-
const modifiedFiles = diffOutput ? diffOutput.split('\n') : [];
|
|
1585
|
-
|
|
1586
|
-
for (const filePath of modifiedFiles) {
|
|
1587
|
-
if (this.shouldProcessFile(filePath)) {
|
|
1588
|
-
try {
|
|
1589
|
-
const fullPath = path.join(workDir, filePath);
|
|
1590
|
-
if (fs.existsSync(fullPath)) {
|
|
1591
|
-
snapshot.files[filePath] = fs.readFileSync(fullPath, 'utf8');
|
|
1592
|
-
}
|
|
1593
|
-
} catch {
|
|
1594
|
-
// Skip files that can't be read
|
|
1595
|
-
}
|
|
1596
|
-
}
|
|
1597
|
-
}
|
|
1598
|
-
} catch (error) {
|
|
1599
|
-
console.warn(`Warning: Could not get snapshot for ${taskId}: ${error.message}`);
|
|
1600
|
-
}
|
|
1601
|
-
|
|
1602
|
-
return snapshot;
|
|
1603
|
-
}
|
|
1604
|
-
|
|
1605
|
-
/**
|
|
1606
|
-
* Find all files modified across tasks
|
|
1607
|
-
*/
|
|
1608
|
-
findModifiedFiles(taskSnapshots) {
|
|
1609
|
-
const files = new Set();
|
|
1610
|
-
|
|
1611
|
-
for (const snapshot of Object.values(taskSnapshots)) {
|
|
1612
|
-
for (const filePath of Object.keys(snapshot.files || {})) {
|
|
1613
|
-
files.add(filePath);
|
|
1614
|
-
}
|
|
1615
|
-
}
|
|
1616
|
-
|
|
1617
|
-
return files;
|
|
1618
|
-
}
|
|
1619
|
-
|
|
1620
|
-
/**
|
|
1621
|
-
* Check if file should be processed
|
|
1622
|
-
* Uses custom rules if available, otherwise falls back to defaults
|
|
1623
|
-
*/
|
|
1624
|
-
shouldProcessFile(filePath) {
|
|
1625
|
-
// Use custom rules if available
|
|
1626
|
-
if (this.rulesLoader) {
|
|
1627
|
-
const category = this.rulesLoader.getFileCategory(filePath);
|
|
1628
|
-
return category !== 'skip';
|
|
1629
|
-
}
|
|
1630
|
-
|
|
1631
|
-
// Default skip patterns
|
|
1632
|
-
const skipPatterns = [
|
|
1633
|
-
/node_modules/,
|
|
1634
|
-
/\.git/,
|
|
1635
|
-
/package-lock\.json/,
|
|
1636
|
-
/yarn\.lock/,
|
|
1637
|
-
/\.log$/,
|
|
1638
|
-
/\.min\./,
|
|
1639
|
-
/dist\//,
|
|
1640
|
-
/build\//,
|
|
1641
|
-
];
|
|
1642
|
-
|
|
1643
|
-
return !skipPatterns.some((pattern) => pattern.test(filePath));
|
|
1644
|
-
}
|
|
1645
|
-
|
|
1646
|
-
/**
|
|
1647
|
-
* Get file category for special handling
|
|
1648
|
-
* @param {string} filePath - Path to file
|
|
1649
|
-
* @returns {string} Category: 'skip', 'auto_merge', 'human_review', 'ai_preferred', 'default'
|
|
1650
|
-
*/
|
|
1651
|
-
getFileCategory(filePath) {
|
|
1652
|
-
if (this.rulesLoader) {
|
|
1653
|
-
return this.rulesLoader.getFileCategory(filePath);
|
|
1654
|
-
}
|
|
1655
|
-
return 'default';
|
|
1656
|
-
}
|
|
1657
|
-
|
|
1658
|
-
/**
|
|
1659
|
-
* Get custom rules (for external access)
|
|
1660
|
-
* @returns {Object} Merged rules
|
|
1661
|
-
*/
|
|
1662
|
-
getRules() {
|
|
1663
|
-
if (this.rulesLoader) {
|
|
1664
|
-
return this.rulesLoader.getMergedRules();
|
|
1665
|
-
}
|
|
1666
|
-
return null;
|
|
1667
|
-
}
|
|
1668
|
-
|
|
1669
|
-
/**
|
|
1670
|
-
* Reload custom rules (clear cache and reload)
|
|
1671
|
-
*/
|
|
1672
|
-
reloadRules() {
|
|
1673
|
-
if (this.rulesLoader) {
|
|
1674
|
-
this.rulesLoader.clearCache();
|
|
1675
|
-
// Re-initialize detector with fresh rules
|
|
1676
|
-
this.detector = new ConflictDetector(this.rulesLoader);
|
|
1677
|
-
}
|
|
1678
|
-
}
|
|
1679
|
-
|
|
1680
|
-
/**
|
|
1681
|
-
* Apply merged changes to files
|
|
1682
|
-
*/
|
|
1683
|
-
async applyMergedChanges(results) {
|
|
1684
|
-
for (const result of results) {
|
|
1685
|
-
if (
|
|
1686
|
-
result.mergedContent &&
|
|
1687
|
-
(result.decision === MergeDecision.AUTO_MERGED ||
|
|
1688
|
-
result.decision === MergeDecision.AI_MERGED)
|
|
1689
|
-
) {
|
|
1690
|
-
const fullPath = path.join(this.rootPath, result.filePath);
|
|
1691
|
-
const dir = path.dirname(fullPath);
|
|
1692
|
-
|
|
1693
|
-
if (!fs.existsSync(dir)) {
|
|
1694
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
1695
|
-
}
|
|
1696
|
-
|
|
1697
|
-
fs.writeFileSync(fullPath, result.mergedContent, 'utf8');
|
|
1698
|
-
this.emit('file_merged', { filePath: result.filePath, decision: result.decision });
|
|
1699
|
-
}
|
|
1700
|
-
}
|
|
1701
|
-
}
|
|
1702
|
-
|
|
1703
|
-
/**
|
|
1704
|
-
* Save merge report
|
|
1705
|
-
*/
|
|
1706
|
-
async saveReport(report) {
|
|
1707
|
-
if (!fs.existsSync(this.storageDir)) {
|
|
1708
|
-
fs.mkdirSync(this.storageDir, { recursive: true });
|
|
1709
|
-
}
|
|
1710
|
-
|
|
1711
|
-
const reportPath = path.join(
|
|
1712
|
-
this.storageDir,
|
|
1713
|
-
`merge-report-${new Date().toISOString().replace(/[:.]/g, '-')}.json`,
|
|
1714
|
-
);
|
|
1715
|
-
|
|
1716
|
-
fs.writeFileSync(reportPath, JSON.stringify(report, null, 2));
|
|
1717
|
-
|
|
1718
|
-
// Also save latest
|
|
1719
|
-
const latestPath = path.join(this.storageDir, 'merge-report-latest.json');
|
|
1720
|
-
fs.writeFileSync(latestPath, JSON.stringify(report, null, 2));
|
|
1721
|
-
}
|
|
1722
|
-
|
|
1723
|
-
/**
|
|
1724
|
-
* Get AI resolver statistics
|
|
1725
|
-
*/
|
|
1726
|
-
getAIStats() {
|
|
1727
|
-
return this.aiResolver.getStats();
|
|
1728
|
-
}
|
|
1729
|
-
}
|
|
1730
|
-
|
|
1731
|
-
// ============================================================================
|
|
1732
|
-
// EXPORTS
|
|
1733
|
-
// ============================================================================
|
|
1734
|
-
|
|
1735
|
-
module.exports = SemanticMergeEngine;
|
|
1736
|
-
module.exports.SemanticMergeEngine = SemanticMergeEngine;
|
|
1737
|
-
module.exports.SemanticAnalyzer = SemanticAnalyzer;
|
|
1738
|
-
module.exports.ConflictDetector = ConflictDetector;
|
|
1739
|
-
module.exports.AutoMerger = AutoMerger;
|
|
1740
|
-
module.exports.AIResolver = AIResolver;
|
|
1741
|
-
module.exports.CustomRulesLoader = CustomRulesLoader;
|
|
1742
|
-
|
|
1743
|
-
// Enums
|
|
1744
|
-
module.exports.ChangeType = ChangeType;
|
|
1745
|
-
module.exports.MergeStrategy = MergeStrategy;
|
|
1746
|
-
module.exports.ConflictSeverity = ConflictSeverity;
|
|
1747
|
-
module.exports.MergeDecision = MergeDecision;
|
|
1748
|
-
|