sinapse-ai 1.8.0 → 1.9.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/hooks/mind-clone-governance.py +212 -212
- package/.claude/hooks/read-protection.py +152 -152
- package/.claude/hooks/slug-validation.py +175 -175
- package/.claude/hooks/sql-governance.py +183 -183
- package/.claude/rules/documentation-first.md +1 -1
- package/.claude/rules/hook-governance.md +1 -1
- package/.claude/rules/mandatory-delegation.md +1 -1
- package/.claude/rules/project-intelligence.md +1 -1
- package/.codex/agents/analyst.md +4 -371
- package/.codex/agents/animations-orqx.md +4 -57
- package/.codex/agents/architect.md +4 -560
- package/.codex/agents/brand-orqx.md +4 -95
- package/.codex/agents/claude-mastery-chief.md +4 -0
- package/.codex/agents/cloning-orqx.md +4 -70
- package/.codex/agents/commercial-orqx.md +4 -67
- package/.codex/agents/config-engineer.md +2 -2
- package/.codex/agents/content-orqx.md +4 -77
- package/.codex/agents/copy-orqx.md +4 -65
- package/.codex/agents/cost-optimizer.md +4 -0
- package/.codex/agents/council-orqx.md +4 -68
- package/.codex/agents/courses-orqx.md +4 -64
- package/.codex/agents/cro-persuasion.md +4 -0
- package/.codex/agents/cyber-orqx.md +4 -67
- package/.codex/agents/data-engineer.md +4 -542
- package/.codex/agents/design-orqx.md +4 -65
- package/.codex/agents/design-system.md +4 -210
- package/.codex/agents/developer.md +4 -666
- package/.codex/agents/devops.md +4 -668
- package/.codex/agents/finance-orqx.md +4 -57
- package/.codex/agents/fiscal-compliance-br.md +4 -0
- package/.codex/agents/forecast-strategist.md +4 -0
- package/.codex/agents/growth-orqx.md +4 -75
- package/.codex/agents/hooks-architect.md +2 -2
- package/.codex/agents/mcp-integrator.md +2 -2
- package/.codex/agents/paidmedia-orqx.md +4 -67
- package/.codex/agents/platform-aesthetic-director.md +4 -0
- package/.codex/agents/premium-packaging-strategist.md +4 -0
- package/.codex/agents/product-lead.md +4 -371
- package/.codex/agents/product-orqx.md +4 -57
- package/.codex/agents/product-surface-director.md +4 -0
- package/.codex/agents/project-integrator.md +2 -2
- package/.codex/agents/project-lead.md +4 -414
- package/.codex/agents/quality-gate.md +4 -547
- package/.codex/agents/research-orqx.md +4 -67
- package/.codex/agents/roadmap-sentinel.md +2 -2
- package/.codex/agents/skill-craftsman.md +2 -2
- package/.codex/agents/snps-orqx.md +4 -684
- package/.codex/agents/sop-extractor.md +4 -61
- package/.codex/agents/sprint-lead.md +4 -324
- package/.codex/agents/squad-creator.md +4 -402
- package/.codex/agents/storytelling-orqx.md +4 -65
- package/.codex/agents/swarm-orqx.md +4 -64
- package/.codex/agents/ux-design-expert.md +4 -532
- package/.codex/agents/ux-designer.md +4 -124
- package/.codex/command-registry.json +9 -9
- package/.codex/delegation-matrix.json +375 -839
- package/.codex/delegation-parity.json +658 -0
- package/.codex/handoff-packet.parity.schema.json +148 -0
- package/.codex/handoff-packet.template.json +26 -0
- package/.codex/instructions.md +8 -8
- package/.codex/scripts/resolve-codex-agent.js +482 -0
- package/.codex/scripts/resolve-codex-command.js +75 -12
- package/.codex/scripts/resolve-codex-delegation.js +131 -92
- package/.codex/skills/sinapse-claude/SKILL.md +3 -3
- package/.codex/skills/sinapse-po/SKILL.md +1 -1
- package/.codex/tasks/resolve-sinapse-conflict.md +1 -1
- package/.sinapse-ai/constitution.md +5 -5
- package/.sinapse-ai/core/doctor/checks/git-hooks.js +163 -19
- package/.sinapse-ai/core/events/dashboard-emitter.js +30 -9
- package/.sinapse-ai/core/execution/subagent-dispatcher.js +1 -1
- package/.sinapse-ai/core/synapse/engine.js +15 -0
- package/.sinapse-ai/core/ui/observability-panel.js +240 -0
- package/.sinapse-ai/core-config.yaml +0 -20
- package/.sinapse-ai/data/entity-registry.yaml +185 -236
- package/.sinapse-ai/development/agents/snps-orqx.md +16 -26
- package/.sinapse-ai/development/tasks/build-autonomous.md +11 -1
- package/.sinapse-ai/development/tasks/build-resume.md +8 -0
- package/.sinapse-ai/development/tasks/build-status.md +8 -0
- package/.sinapse-ai/development/tasks/build.md +8 -0
- package/.sinapse-ai/development/tasks/cleanup-worktrees.md +8 -1
- package/.sinapse-ai/development/tasks/gotcha.md +8 -0
- package/.sinapse-ai/development/tasks/gotchas.md +8 -0
- package/.sinapse-ai/development/tasks/ids-health.md +14 -6
- package/.sinapse-ai/development/tasks/list-mcps.md +15 -0
- package/.sinapse-ai/development/tasks/merge-worktree.md +8 -1
- package/.sinapse-ai/development/tasks/qa-review-build.md +18 -0
- package/.sinapse-ai/development/tasks/remove-mcp.md +8 -1
- package/.sinapse-ai/development/tasks/validate-agents.md +26 -14
- package/.sinapse-ai/development/templates/service-template/README.md.hbs +159 -159
- package/.sinapse-ai/development/templates/service-template/__tests__/index.test.ts.hbs +238 -238
- package/.sinapse-ai/development/templates/service-template/client.ts.hbs +404 -404
- package/.sinapse-ai/development/templates/service-template/errors.ts.hbs +183 -183
- package/.sinapse-ai/development/templates/service-template/index.ts.hbs +121 -121
- package/.sinapse-ai/development/templates/service-template/package.json.hbs +88 -88
- package/.sinapse-ai/development/templates/service-template/types.ts.hbs +146 -146
- package/.sinapse-ai/development/templates/squad-template/LICENSE +22 -22
- package/.sinapse-ai/git-hooks/lib/framework-guard.js +258 -0
- package/.sinapse-ai/git-hooks/lib/secret-scanner-core.js +355 -0
- package/.sinapse-ai/git-hooks/lib/staged-secret-scan.js +179 -0
- package/.sinapse-ai/git-hooks/lib/staged-sql-guard.js +204 -0
- package/.sinapse-ai/git-hooks/post-commit +28 -0
- package/.sinapse-ai/git-hooks/pre-commit +81 -0
- package/.sinapse-ai/git-hooks/pre-push +83 -0
- package/.sinapse-ai/hooks/ids-post-commit.js +13 -11
- package/.sinapse-ai/hooks/ids-pre-push.js +9 -7
- package/.sinapse-ai/infrastructure/scripts/codex-parity/resolve.js +161 -0
- package/.sinapse-ai/infrastructure/scripts/dashboard-status-writer.js +6 -2
- package/.sinapse-ai/infrastructure/scripts/ide-sync/index.js +65 -68
- package/.sinapse-ai/infrastructure/scripts/sync-codex-local-first.js +156 -1
- package/.sinapse-ai/infrastructure/scripts/validate-codex-delegation.js +1 -4
- package/.sinapse-ai/infrastructure/scripts/validate-codex-integration.js +41 -5
- package/.sinapse-ai/infrastructure/templates/coderabbit.yaml.template +280 -280
- package/.sinapse-ai/infrastructure/templates/config/env.example +16 -16
- package/.sinapse-ai/infrastructure/templates/config/gitignore-additions.tmpl +59 -59
- package/.sinapse-ai/infrastructure/templates/github/CODEOWNERS.template +12 -12
- package/.sinapse-ai/infrastructure/templates/github-workflows/ci.yml.template +170 -170
- package/.sinapse-ai/infrastructure/templates/github-workflows/pr-automation.yml.template +331 -331
- package/.sinapse-ai/infrastructure/templates/github-workflows/release.yml.template +197 -197
- package/.sinapse-ai/infrastructure/templates/gitignore/gitignore-brownfield-merge.tmpl +19 -19
- package/.sinapse-ai/infrastructure/templates/gitignore/gitignore-node.tmpl +86 -86
- package/.sinapse-ai/infrastructure/templates/gitignore/gitignore-python.tmpl +146 -146
- package/.sinapse-ai/infrastructure/templates/gitignore/gitignore-sinapse-base.tmpl +64 -64
- package/.sinapse-ai/infrastructure/templates/safe-collab/CODEOWNERS.template +16 -16
- package/.sinapse-ai/infrastructure/templates/sinapse-sync.yaml.template +183 -183
- package/.sinapse-ai/install-manifest.yaml +112 -164
- package/.sinapse-ai/local-config.yaml.template +65 -65
- package/.sinapse-ai/product/templates/adr.hbs +126 -126
- package/.sinapse-ai/product/templates/dbdr.hbs +242 -242
- package/.sinapse-ai/product/templates/epic.hbs +213 -213
- package/.sinapse-ai/product/templates/ide-rules/codex-rules.md +30 -0
- package/.sinapse-ai/product/templates/pmdr.hbs +187 -187
- package/.sinapse-ai/product/templates/prd-v2.0.hbs +217 -217
- package/.sinapse-ai/product/templates/prd.hbs +202 -202
- package/.sinapse-ai/product/templates/statusline/statusline-script.js +31 -8
- package/.sinapse-ai/product/templates/statusline/track-agent-clear.cjs +79 -0
- package/.sinapse-ai/product/templates/statusline/track-agent.cjs +218 -0
- package/.sinapse-ai/product/templates/story.hbs +264 -264
- package/.sinapse-ai/product/templates/task.hbs +171 -171
- package/.sinapse-ai/product/templates/tmpl-comment-on-examples.sql +159 -159
- package/.sinapse-ai/product/templates/tmpl-migration-script.sql +92 -92
- package/.sinapse-ai/product/templates/tmpl-rls-granular-policies.sql +105 -105
- package/.sinapse-ai/product/templates/tmpl-rls-kiss-policy.sql +11 -11
- package/.sinapse-ai/product/templates/tmpl-rls-roles.sql +136 -136
- package/.sinapse-ai/product/templates/tmpl-rls-simple.sql +78 -78
- package/.sinapse-ai/product/templates/tmpl-rls-tenant.sql +153 -153
- package/.sinapse-ai/product/templates/tmpl-rollback-script.sql +78 -78
- package/.sinapse-ai/product/templates/tmpl-seed-data.sql +141 -141
- package/.sinapse-ai/product/templates/tmpl-smoke-test.sql +17 -17
- package/.sinapse-ai/product/templates/tmpl-staging-copy-merge.sql +140 -140
- package/.sinapse-ai/product/templates/tmpl-stored-proc.sql +141 -141
- package/.sinapse-ai/product/templates/tmpl-trigger.sql +153 -153
- package/.sinapse-ai/product/templates/tmpl-view-materialized.sql +134 -134
- package/.sinapse-ai/product/templates/tmpl-view.sql +178 -178
- package/AGENTS.md +193 -0
- package/CHANGELOG.md +1247 -0
- package/LICENSE +63 -63
- package/README.en.md +17 -18
- package/README.md +18 -19
- package/bin/cli.js +1 -1
- package/bin/commands/install.js +194 -22
- package/bin/commands/status.js +14 -1
- package/bin/commands/uninstall.js +2 -2
- package/bin/commands/update.js +52 -0
- package/bin/lib/setup-statusline.js +191 -0
- package/bin/sinapse-init.js +11 -83
- package/bin/utils/framework-guard.js +17 -4
- package/bin/utils/secret-scanner-core.js +109 -7
- package/bin/utils/staged-sql-guard.js +204 -0
- package/bin/utils/validate-publish.js +63 -0
- package/docs/agent-reference-guide.md +5 -7
- package/docs/framework/agent-prefix-convention.md +58 -0
- package/docs/framework/architecture-overview.md +4 -4
- package/docs/framework/collaboration-activation.md +45 -0
- package/docs/framework/guiding-principles.md +9 -9
- package/docs/getting-started.md +1 -1
- package/docs/guides/agent-reference.md +1 -1
- package/docs/guides/codex-config.md +4 -5
- package/docs/pt/architecture/sub-orqx-pattern.md +20 -18
- package/docs/security/overview.md +1 -1
- package/package.json +16 -12
- package/packages/installer/src/index.js +26 -0
- package/packages/installer/src/installer/git-hooks-installer.js +211 -47
- package/packages/installer/src/installer/sinapse-ai-installer.js +71 -0
- package/packages/installer/src/wizard/feedback.js +1 -1
- package/packages/installer/src/wizard/ide-config-generator.js +26 -26
- package/packages/installer/src/wizard/index.js +53 -4
- package/packages/sinapse-install/bin/edmcp.js +0 -0
- package/packages/sinapse-install/bin/sinapse-install.js +0 -0
- package/scripts/audit-tasks.cjs +112 -91
- package/scripts/check-markdown-links.py +352 -352
- package/scripts/prepare-hooks.js +58 -0
- package/scripts/regenerate-orqx-stubs.ps1 +2 -3
- package/scripts/sync-counts.js +10 -2
- package/scripts/sync-squad-yaml-components.js +108 -6
- package/scripts/validate-agents-md.js +128 -0
- package/scripts/validate-all.js +1 -0
- package/scripts/validate-squad-orqx.js +19 -9
- package/sinapse/agents/sinapse-orqx.md +16 -26
- package/sinapse/agents/snps-orqx.md +15 -25
- package/sinapse/knowledge-base/routing-catalog.md +1 -1
- package/sinapse/tasks/diagnose-and-route.md +1 -1
- package/sinapse/tasks/squad-status-report.md +1 -1
- package/squads/claude-code-mastery/agents/claude-mastery-chief.md +1 -1
- package/squads/claude-code-mastery/agents/hooks-architect.md +60 -68
- package/squads/claude-code-mastery/knowledge-base/swarm-orchestration-patterns.md +1 -1
- package/squads/claude-code-mastery/squad.yaml +8 -0
- package/squads/claude-code-mastery/tasks/audit-setup.md +1 -1
- package/squads/claude-code-mastery/workflows/optimization-cycle.yaml +4 -4
- package/squads/claude-code-mastery/workflows/project-setup-cycle.yaml +4 -4
- package/squads/squad-animations/README.md +1 -1
- package/squads/squad-animations/squad.yaml +1 -1
- package/squads/squad-brand/squad.yaml +1 -1
- package/squads/squad-cloning/README.md +1 -1
- package/squads/squad-cloning/squad.yaml +1 -1
- package/squads/squad-commercial/README.md +1 -1
- package/squads/squad-commercial/squad.yaml +2 -3
- package/squads/squad-content/README.md +1 -1
- package/squads/squad-content/squad.yaml +1 -1
- package/squads/squad-copy/README.md +1 -1
- package/squads/squad-copy/squad.yaml +2 -3
- package/squads/squad-council/README.md +1 -1
- package/squads/squad-courses/README.md +1 -1
- package/squads/squad-courses/squad.yaml +1 -1
- package/squads/squad-cybersecurity/README.md +1 -1
- package/squads/squad-cybersecurity/squad.yaml +2 -3
- package/squads/squad-design/README.md +1 -1
- package/squads/{squad-artdir → squad-design}/agents/cro-persuasion.md +1 -1
- package/squads/{squad-artdir → squad-design}/agents/platform-aesthetic-director.md +2 -2
- package/squads/{squad-artdir → squad-design}/agents/premium-packaging-strategist.md +2 -2
- package/squads/{squad-artdir → squad-design}/agents/product-surface-director.md +3 -3
- package/squads/squad-design/squad.yaml +6 -3
- package/squads/squad-finance/README.md +1 -1
- package/squads/squad-finance/squad.yaml +7 -1
- package/squads/squad-growth/README.md +1 -1
- package/squads/squad-growth/squad.yaml +1 -1
- package/squads/squad-paidmedia/README.md +1 -1
- package/squads/squad-paidmedia/squad.yaml +2 -3
- package/squads/squad-product/README.md +1 -1
- package/squads/squad-product/squad.yaml +1 -1
- package/squads/squad-research/README.md +1 -1
- package/squads/squad-research/squad.yaml +2 -3
- package/squads/squad-storytelling/README.md +1 -1
- package/squads/squad-storytelling/squad.yaml +2 -3
- package/.codex/agents/brad-frost.md +0 -46
- package/.codex/agents/claude-orqx.md +0 -72
- package/.codex/agents/copy-chief.md +0 -162
- package/.codex/agents/cyber-chief.md +0 -169
- package/.codex/agents/dan-mall.md +0 -43
- package/.codex/agents/data-chief.md +0 -198
- package/.codex/agents/dave-malouf.md +0 -43
- package/.codex/agents/db-sage.md +0 -152
- package/.codex/agents/design-chief.md +0 -226
- package/.codex/agents/dev.md +0 -102
- package/.codex/agents/legal-chief.md +0 -199
- package/.codex/agents/nano-banana-generator.md +0 -42
- package/.codex/agents/pm.md +0 -81
- package/.codex/agents/po.md +0 -85
- package/.codex/agents/qa.md +0 -98
- package/.codex/agents/sm.md +0 -77
- package/.codex/agents/squad-chief.md +0 -1553
- package/.codex/agents/squad.md +0 -66
- package/.codex/agents/story-chief.md +0 -180
- package/.codex/agents/tools-orqx.md +0 -219
- package/.codex/agents/traffic-masters-chief.md +0 -211
- package/.sinapse-ai/core/memory/__tests__/active-modules.verify.js +0 -265
- package/.sinapse-ai/core/permissions/__tests__/permission-mode.test.js +0 -293
- package/.sinapse-ai/data/registry-update-log.jsonl +0 -158
- package/.sinapse-ai/infrastructure/scripts/ide-sync/gemini-commands.js +0 -298
- package/.sinapse-ai/infrastructure/scripts/ide-sync/transformers/antigravity.js +0 -121
- package/.sinapse-ai/infrastructure/scripts/ide-sync/transformers/cursor.js +0 -119
- package/.sinapse-ai/infrastructure/scripts/ide-sync/transformers/github-copilot.js +0 -191
- package/.sinapse-ai/infrastructure/scripts/ide-sync/transformers/kimi.js +0 -448
- package/.sinapse-ai/infrastructure/tests/project-status-loader.test.js +0 -569
- package/.sinapse-ai/infrastructure/tests/regression-suite-v2.md +0 -622
- package/.sinapse-ai/infrastructure/tests/validate-module.js +0 -98
- package/.sinapse-ai/infrastructure/tests/worktree-manager.test.js +0 -620
- package/.sinapse-ai/monitor/hooks/lib/__init__.py +0 -2
- package/.sinapse-ai/monitor/hooks/lib/enrich.py +0 -59
- package/.sinapse-ai/monitor/hooks/lib/send_event.py +0 -48
- package/.sinapse-ai/monitor/hooks/notification.py +0 -30
- package/.sinapse-ai/monitor/hooks/post_tool_use.py +0 -46
- package/.sinapse-ai/monitor/hooks/pre_compact.py +0 -30
- package/.sinapse-ai/monitor/hooks/pre_tool_use.py +0 -41
- package/.sinapse-ai/monitor/hooks/stop.py +0 -30
- package/.sinapse-ai/monitor/hooks/subagent_stop.py +0 -30
- package/.sinapse-ai/monitor/hooks/user_prompt_submit.py +0 -39
- package/.sinapse-ai/product/templates/statusline/track-agent.sh +0 -69
- package/.sinapse-ai/workflow-intelligence/__tests__/confidence-scorer.test.js +0 -335
- package/.sinapse-ai/workflow-intelligence/__tests__/integration.test.js +0 -340
- package/.sinapse-ai/workflow-intelligence/__tests__/suggestion-engine.test.js +0 -438
- package/.sinapse-ai/workflow-intelligence/__tests__/wave-analyzer.test.js +0 -448
- package/.sinapse-ai/workflow-intelligence/__tests__/workflow-registry.test.js +0 -303
- package/bin/sinapse-graph.js +0 -19
- package/docs/codex-integration-process.md +0 -22
- package/docs/codex-parity-program.md +0 -27
- package/packages/installer/src/__tests__/performance-benchmark.js +0 -383
- package/packages/installer/tests/integration/environment-configuration.test.js +0 -332
- package/packages/installer/tests/integration/wizard-detection.test.js +0 -352
- package/packages/installer/tests/unit/artifact-copy-pipeline/artifact-copy-pipeline.test.js +0 -383
- package/packages/installer/tests/unit/claude-md-template-v5/claude-md-template-v5.test.js +0 -193
- package/packages/installer/tests/unit/config-validator.test.js +0 -315
- package/packages/installer/tests/unit/detection/detect-project-type.test.js +0 -539
- package/packages/installer/tests/unit/doctor/doctor-checks.test.js +0 -636
- package/packages/installer/tests/unit/doctor/doctor-orchestrator.test.js +0 -192
- package/packages/installer/tests/unit/entity-registry-bootstrap.test.js +0 -186
- package/packages/installer/tests/unit/env-template.test.js +0 -187
- package/packages/installer/tests/unit/generate-settings-json/generate-settings-json.test.js +0 -310
- package/packages/installer/tests/unit/git-hooks-installer.test.js +0 -262
- package/packages/installer/tests/unit/ide-sync-integration/ide-sync-integration.test.js +0 -231
- package/packages/installer/tests/unit/merger/env-merger.test.js +0 -191
- package/packages/installer/tests/unit/merger/markdown-merger.test.js +0 -262
- package/packages/installer/tests/unit/merger/strategies.test.js +0 -154
- package/packages/installer/tests/unit/merger/yaml-merger.test.js +0 -328
- package/packages/sinapse-install/tests/unit/chrome-brain.smoke.test.js +0 -66
- package/scripts/install-monitor-hooks.sh +0 -82
- package/squads/squad-artdir/README.md +0 -90
- package/squads/squad-artdir/agents/accessibility-guardian.md +0 -184
- package/squads/squad-artdir/agents/artdir-orqx.md +0 -222
- package/squads/squad-artdir/agents/color-psychologist.md +0 -166
- package/squads/squad-artdir/agents/design-system-architect.md +0 -100
- package/squads/squad-artdir/agents/ia-architect.md +0 -169
- package/squads/squad-artdir/agents/interaction-designer.md +0 -162
- package/squads/squad-artdir/agents/layout-engineer.md +0 -163
- package/squads/squad-artdir/agents/motion-architect.md +0 -185
- package/squads/squad-artdir/agents/type-systemist.md +0 -138
- package/squads/squad-artdir/agents/visual-strategist.md +0 -127
- package/squads/squad-artdir/checklists/seven-pillars-validation-checklist.md +0 -172
- package/squads/squad-artdir/knowledge-base/case-nyo-ia-reference.md +0 -289
- package/squads/squad-artdir/knowledge-base/deliverables-templates.md +0 -457
- package/squads/squad-artdir/knowledge-base/motion-technique-catalog.md +0 -247
- package/squads/squad-artdir/knowledge-base/premium-packaging-principles.md +0 -133
- package/squads/squad-artdir/knowledge-base/psychological-toolkit.md +0 -229
- package/squads/squad-artdir/knowledge-base/saas-art-direction-canon.md +0 -242
- package/squads/squad-artdir/knowledge-base/seven-pillars-framework.md +0 -289
- package/squads/squad-artdir/knowledge-base/ten-pillars-framework.md +0 -221
- package/squads/squad-artdir/package.json +0 -20
- package/squads/squad-artdir/squad.yaml +0 -299
- package/squads/squad-artdir/tasks/audit-conversion.md +0 -97
- package/squads/squad-artdir/tasks/audit-drift-multi-surface.md +0 -55
- package/squads/squad-artdir/tasks/consult-saas-canon.md +0 -54
- package/squads/squad-artdir/tasks/create-art-direction-brief.md +0 -110
- package/squads/squad-artdir/tasks/create-premium-packaging-brief.md +0 -61
- package/squads/squad-artdir/tasks/create-wireflow.md +0 -84
- package/squads/squad-artdir/tasks/design-color-system.md +0 -81
- package/squads/squad-artdir/tasks/design-product-surface.md +0 -60
- package/squads/squad-artdir/tasks/design-token-system.md +0 -58
- package/squads/squad-artdir/tasks/diagnose-visual-language.md +0 -92
- package/squads/squad-artdir/tasks/first-5-minutes-choreography.md +0 -65
- package/squads/squad-artdir/tasks/specify-motion-system.md +0 -84
- package/squads/squad-artdir/tasks/validate-against-pillars.md +0 -143
- package/squads/squad-artdir/templates/art-direction-brief-template.md +0 -215
- package/squads/squad-artdir/workflows/conversion-audit-cycle.yaml +0 -142
- package/squads/squad-artdir/workflows/full-art-direction-cycle.yaml +0 -179
- package/squads/squad-artdir/workflows/saas-platform-art-direction-cycle.yaml +0 -338
- package/squads/squad-commercial/agents/legal-chief.md +0 -199
- package/squads/squad-copy/agents/copy-chief.md +0 -162
- package/squads/squad-cybersecurity/agents/cyber-chief.md +0 -169
- package/squads/squad-design/agents/design-chief.md +0 -226
- package/squads/squad-paidmedia/agents/traffic-masters-chief.md +0 -211
- package/squads/squad-research/agents/data-chief.md +0 -198
- package/squads/squad-storytelling/agents/story-chief.md +0 -180
|
@@ -1,231 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* IDE Sync Integration Tests (Story INS-4.5)
|
|
5
|
-
*
|
|
6
|
-
* Verifies that the installer calls commandSync and commandValidate
|
|
7
|
-
* via the adapter pattern (save cwd, chdir, finally restore).
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
const path = require('path');
|
|
11
|
-
|
|
12
|
-
// Mock the ide-sync module before requiring wizard
|
|
13
|
-
const mockCommandSync = jest.fn();
|
|
14
|
-
const mockCommandValidate = jest.fn();
|
|
15
|
-
|
|
16
|
-
jest.mock('../../../../../.sinapse-ai/infrastructure/scripts/ide-sync/index', () => ({
|
|
17
|
-
commandSync: mockCommandSync,
|
|
18
|
-
commandValidate: mockCommandValidate,
|
|
19
|
-
}));
|
|
20
|
-
|
|
21
|
-
// We need to verify that the wizard source code has the correct integration
|
|
22
|
-
const fs = require('fs');
|
|
23
|
-
const WIZARD_PATH = path.join(
|
|
24
|
-
__dirname, '..', '..', '..', 'src', 'wizard', 'index.js'
|
|
25
|
-
);
|
|
26
|
-
|
|
27
|
-
describe('IDE Sync Integration (Story INS-4.5)', () => {
|
|
28
|
-
let wizardSource;
|
|
29
|
-
|
|
30
|
-
beforeAll(() => {
|
|
31
|
-
wizardSource = fs.readFileSync(WIZARD_PATH, 'utf8');
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
describe('AC1: IDE sync called via adapter pattern', () => {
|
|
35
|
-
test('wizard imports commandSync and commandValidate from ide-sync', () => {
|
|
36
|
-
expect(wizardSource).toContain(
|
|
37
|
-
"const { commandSync, commandValidate } = require('../../../../.sinapse-ai/infrastructure/scripts/ide-sync/index')"
|
|
38
|
-
);
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
test('wizard uses programmatic API (not child_process.exec)', () => {
|
|
42
|
-
// Should NOT shell out to ide-sync
|
|
43
|
-
expect(wizardSource).not.toMatch(/child_process.*ide-sync/);
|
|
44
|
-
expect(wizardSource).not.toMatch(/exec\(.*ide-sync/);
|
|
45
|
-
expect(wizardSource).not.toMatch(/spawn\(.*ide-sync/);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
test('adapter pattern: saves cwd before calling commandSync', () => {
|
|
49
|
-
expect(wizardSource).toContain('const savedCwd = process.cwd()');
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
test('adapter pattern: uses explicit targetProjectRoot variable (not bare process.cwd())', () => {
|
|
53
|
-
expect(wizardSource).toContain('const targetProjectRoot = process.cwd()');
|
|
54
|
-
expect(wizardSource).toContain('process.chdir(targetProjectRoot)');
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
test('adapter pattern: restores cwd in finally block', () => {
|
|
58
|
-
// The finally block should restore savedCwd
|
|
59
|
-
expect(wizardSource).toContain('process.chdir(savedCwd)');
|
|
60
|
-
expect(wizardSource).toMatch(/finally\s*\{[^}]*process\.chdir\(savedCwd\)/s);
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
test('commandSync called with { quiet: true }', () => {
|
|
64
|
-
expect(wizardSource).toContain("await commandSync({ quiet: true })");
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
test('does NOT pass projectRoot or ides as parameters to commandSync', () => {
|
|
68
|
-
// commandSync uses process.cwd() internally — no projectRoot param
|
|
69
|
-
expect(wizardSource).not.toMatch(/commandSync\(\{[^}]*projectRoot/);
|
|
70
|
-
expect(wizardSource).not.toMatch(/commandSync\(\{[^}]*ides/);
|
|
71
|
-
});
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
describe('AC3: Graceful failure', () => {
|
|
75
|
-
test('sync failure is caught and does not propagate', () => {
|
|
76
|
-
// The try/catch should set ideSyncStatus to failed, not throw
|
|
77
|
-
expect(wizardSource).toContain("answers.ideSyncStatus = 'failed'");
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
test('failure message suggests sinapse doctor --fix', () => {
|
|
81
|
-
expect(wizardSource).toContain("sinapse doctor --fix");
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
test('install summary includes sync status on success', () => {
|
|
85
|
-
expect(wizardSource).toContain("answers.ideSyncStatus = 'synced'");
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
test('install summary includes sync status on failure', () => {
|
|
89
|
-
expect(wizardSource).toContain("answers.ideSyncStatus = 'failed'");
|
|
90
|
-
});
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
describe('AC4: Validate sync output', () => {
|
|
94
|
-
test('commandValidate called after commandSync', () => {
|
|
95
|
-
// commandValidate should appear after commandSync in the source
|
|
96
|
-
const syncIndex = wizardSource.indexOf('await commandSync({ quiet: true })');
|
|
97
|
-
const validateIndex = wizardSource.indexOf('await commandValidate(');
|
|
98
|
-
expect(syncIndex).toBeGreaterThan(-1);
|
|
99
|
-
expect(validateIndex).toBeGreaterThan(-1);
|
|
100
|
-
expect(validateIndex).toBeGreaterThan(syncIndex);
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
test('commandValidate uses same adapter pattern (within same finally block)', () => {
|
|
104
|
-
// Both commandSync and commandValidate should be within the same
|
|
105
|
-
// saved cwd / finally block
|
|
106
|
-
const savedCwdIndex = wizardSource.indexOf('const savedCwd = process.cwd()');
|
|
107
|
-
const syncIndex = wizardSource.indexOf('await commandSync({ quiet: true })');
|
|
108
|
-
const validateIndex = wizardSource.indexOf('await commandValidate(');
|
|
109
|
-
const finallyIndex = wizardSource.indexOf('process.chdir(savedCwd)');
|
|
110
|
-
|
|
111
|
-
// All should be in order: savedCwd < sync < validate < finally restore
|
|
112
|
-
expect(savedCwdIndex).toBeLessThan(syncIndex);
|
|
113
|
-
expect(syncIndex).toBeLessThan(validateIndex);
|
|
114
|
-
expect(validateIndex).toBeLessThan(finallyIndex);
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
test('validation drift logged as WARN not ERROR', () => {
|
|
118
|
-
expect(wizardSource).toContain("answers.ideSyncValidation = 'drift'");
|
|
119
|
-
// Should use console.warn, not console.error for drift
|
|
120
|
-
expect(wizardSource).toMatch(/console\.warn\(.*drift/i);
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
test('commandValidate console output suppressed (quiet workaround)', () => {
|
|
124
|
-
// commandValidate does not support quiet — wizard suppresses console.log
|
|
125
|
-
expect(wizardSource).toContain('const _origLog = console.log');
|
|
126
|
-
expect(wizardSource).toContain('console.log = () => {}');
|
|
127
|
-
// console.log must be restored in a finally block
|
|
128
|
-
expect(wizardSource).toContain('console.log = _origLog');
|
|
129
|
-
});
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
describe('AC5: Behavioral tests with mocks', () => {
|
|
133
|
-
beforeEach(() => {
|
|
134
|
-
mockCommandSync.mockReset();
|
|
135
|
-
mockCommandValidate.mockReset();
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
test('commandSync is called with { quiet: true } when invoked', async () => {
|
|
139
|
-
mockCommandSync.mockResolvedValue(undefined);
|
|
140
|
-
mockCommandValidate.mockResolvedValue(undefined);
|
|
141
|
-
|
|
142
|
-
// Simulate the adapter pattern call sequence
|
|
143
|
-
const savedCwd = process.cwd();
|
|
144
|
-
try {
|
|
145
|
-
await mockCommandSync({ quiet: true });
|
|
146
|
-
await mockCommandValidate({ quiet: true });
|
|
147
|
-
} finally {
|
|
148
|
-
process.chdir(savedCwd);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
expect(mockCommandSync).toHaveBeenCalledWith({ quiet: true });
|
|
152
|
-
expect(mockCommandValidate).toHaveBeenCalledWith({ quiet: true });
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
test('commandSync failure does not throw — install continues', async () => {
|
|
156
|
-
mockCommandSync.mockRejectedValue(new Error('sync failed'));
|
|
157
|
-
|
|
158
|
-
let ideSyncStatus = 'unknown';
|
|
159
|
-
const savedCwd = process.cwd();
|
|
160
|
-
try {
|
|
161
|
-
process.chdir(process.cwd());
|
|
162
|
-
await mockCommandSync({ quiet: true });
|
|
163
|
-
ideSyncStatus = 'synced';
|
|
164
|
-
} catch (syncError) {
|
|
165
|
-
ideSyncStatus = 'failed';
|
|
166
|
-
} finally {
|
|
167
|
-
process.chdir(savedCwd);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// Install should continue — status is failed, no uncaught throw
|
|
171
|
-
expect(ideSyncStatus).toBe('failed');
|
|
172
|
-
expect(process.cwd()).toBe(savedCwd);
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
test('cwd is restored even when commandSync throws', async () => {
|
|
176
|
-
mockCommandSync.mockRejectedValue(new Error('sync failed'));
|
|
177
|
-
const originalCwd = process.cwd();
|
|
178
|
-
|
|
179
|
-
const savedCwd = process.cwd();
|
|
180
|
-
try {
|
|
181
|
-
process.chdir(process.cwd());
|
|
182
|
-
await mockCommandSync({ quiet: true });
|
|
183
|
-
} catch {
|
|
184
|
-
// Expected — sync failed
|
|
185
|
-
} finally {
|
|
186
|
-
process.chdir(savedCwd);
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
expect(process.cwd()).toBe(originalCwd);
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
test('commandValidate called after successful sync', async () => {
|
|
193
|
-
mockCommandSync.mockResolvedValue(undefined);
|
|
194
|
-
mockCommandValidate.mockResolvedValue(undefined);
|
|
195
|
-
|
|
196
|
-
const savedCwd = process.cwd();
|
|
197
|
-
let validateCalled = false;
|
|
198
|
-
try {
|
|
199
|
-
process.chdir(process.cwd());
|
|
200
|
-
await mockCommandSync({ quiet: true });
|
|
201
|
-
await mockCommandValidate({ quiet: true });
|
|
202
|
-
validateCalled = true;
|
|
203
|
-
} finally {
|
|
204
|
-
process.chdir(savedCwd);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
expect(validateCalled).toBe(true);
|
|
208
|
-
expect(mockCommandValidate).toHaveBeenCalled();
|
|
209
|
-
});
|
|
210
|
-
|
|
211
|
-
test('commandValidate NOT called when commandSync fails', async () => {
|
|
212
|
-
mockCommandSync.mockRejectedValue(new Error('sync failed'));
|
|
213
|
-
|
|
214
|
-
const savedCwd = process.cwd();
|
|
215
|
-
try {
|
|
216
|
-
process.chdir(process.cwd());
|
|
217
|
-
await mockCommandSync({ quiet: true });
|
|
218
|
-
// This line should NOT be reached
|
|
219
|
-
await mockCommandValidate({ quiet: true });
|
|
220
|
-
} catch {
|
|
221
|
-
// Expected — sync failed, validate not called
|
|
222
|
-
} finally {
|
|
223
|
-
process.chdir(savedCwd);
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
expect(mockCommandSync).toHaveBeenCalled();
|
|
227
|
-
expect(mockCommandValidate).not.toHaveBeenCalled();
|
|
228
|
-
});
|
|
229
|
-
});
|
|
230
|
-
});
|
|
231
|
-
|
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview Tests for EnvMerger
|
|
3
|
-
* Story 9.2: .env File Merge Implementation
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const { EnvMerger } = require('../../../src/merger/strategies/env-merger.js');
|
|
7
|
-
const { parseEnvFile } = require('../../../src/merger/parsers/env-parser.js');
|
|
8
|
-
|
|
9
|
-
describe('EnvMerger', () => {
|
|
10
|
-
let merger;
|
|
11
|
-
|
|
12
|
-
beforeEach(() => {
|
|
13
|
-
merger = new EnvMerger();
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
describe('canMerge', () => {
|
|
17
|
-
it('should always return true for .env files', () => {
|
|
18
|
-
expect(merger.canMerge('', '')).toBe(true);
|
|
19
|
-
expect(merger.canMerge('KEY=value', 'OTHER=value')).toBe(true);
|
|
20
|
-
});
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
describe('merge', () => {
|
|
24
|
-
it('should add new variables from new content', async () => {
|
|
25
|
-
const existing = 'EXISTING_VAR=existing_value';
|
|
26
|
-
const newContent = 'NEW_VAR=new_value';
|
|
27
|
-
|
|
28
|
-
const result = await merger.merge(existing, newContent);
|
|
29
|
-
|
|
30
|
-
expect(result.content).toContain('EXISTING_VAR=existing_value');
|
|
31
|
-
expect(result.content).toContain('NEW_VAR=new_value');
|
|
32
|
-
expect(result.stats.preserved).toBe(1);
|
|
33
|
-
expect(result.stats.added).toBe(1);
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it('should preserve existing values over new values', async () => {
|
|
37
|
-
const existing = 'API_KEY=my_secret_key';
|
|
38
|
-
const newContent = 'API_KEY=placeholder_key';
|
|
39
|
-
|
|
40
|
-
const result = await merger.merge(existing, newContent);
|
|
41
|
-
|
|
42
|
-
// The original value is preserved at the start
|
|
43
|
-
expect(result.content.startsWith('API_KEY=my_secret_key')).toBe(true);
|
|
44
|
-
// The suggested value appears in SINAPSE_SUGGESTED comment
|
|
45
|
-
expect(result.content).toContain('SINAPSE_SUGGESTED: API_KEY=placeholder_key');
|
|
46
|
-
expect(result.stats.preserved).toBe(1);
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it('should add SINAPSE_SUGGESTED comment for differing values', async () => {
|
|
50
|
-
const existing = 'PORT=3000';
|
|
51
|
-
const newContent = 'PORT=8080';
|
|
52
|
-
|
|
53
|
-
const result = await merger.merge(existing, newContent);
|
|
54
|
-
|
|
55
|
-
expect(result.content).toContain('PORT=3000');
|
|
56
|
-
expect(result.content).toContain('# SINAPSE_SUGGESTED: PORT=8080');
|
|
57
|
-
expect(result.stats.conflicts).toBe(1);
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
it('should preserve comments from existing file', async () => {
|
|
61
|
-
const existing = `# Database configuration
|
|
62
|
-
DB_HOST=localhost
|
|
63
|
-
DB_PORT=5432`;
|
|
64
|
-
const newContent = 'NEW_VAR=value';
|
|
65
|
-
|
|
66
|
-
const result = await merger.merge(existing, newContent);
|
|
67
|
-
|
|
68
|
-
expect(result.content).toContain('# Database configuration');
|
|
69
|
-
expect(result.content).toContain('DB_HOST=localhost');
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it('should add new variables in SINAPSE Variables section', async () => {
|
|
73
|
-
const existing = 'EXISTING=value';
|
|
74
|
-
const newContent = `SINAPSE_VAR1=value1
|
|
75
|
-
SINAPSE_VAR2=value2`;
|
|
76
|
-
|
|
77
|
-
const result = await merger.merge(existing, newContent);
|
|
78
|
-
|
|
79
|
-
// Header includes date: "# === SINAPSE Variables (added YYYY-MM-DD) ==="
|
|
80
|
-
expect(result.content).toMatch(/# === SINAPSE Variables \(added \d{4}-\d{2}-\d{2}\) ===/);
|
|
81
|
-
expect(result.content).toContain('SINAPSE_VAR1=value1');
|
|
82
|
-
expect(result.content).toContain('SINAPSE_VAR2=value2');
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
it('should handle empty existing content', async () => {
|
|
86
|
-
const existing = '';
|
|
87
|
-
const newContent = 'NEW_VAR=value';
|
|
88
|
-
|
|
89
|
-
const result = await merger.merge(existing, newContent);
|
|
90
|
-
|
|
91
|
-
expect(result.content).toContain('NEW_VAR=value');
|
|
92
|
-
expect(result.stats.added).toBe(1);
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
it('should handle empty new content', async () => {
|
|
96
|
-
const existing = 'EXISTING=value';
|
|
97
|
-
const newContent = '';
|
|
98
|
-
|
|
99
|
-
const result = await merger.merge(existing, newContent);
|
|
100
|
-
|
|
101
|
-
expect(result.content).toContain('EXISTING=value');
|
|
102
|
-
expect(result.stats.preserved).toBe(1);
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
it('should handle multiline values', async () => {
|
|
106
|
-
const existing = `PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----
|
|
107
|
-
MIIEpQIBAAKCAQEA
|
|
108
|
-
-----END RSA PRIVATE KEY-----"`;
|
|
109
|
-
const newContent = 'OTHER=value';
|
|
110
|
-
|
|
111
|
-
const result = await merger.merge(existing, newContent);
|
|
112
|
-
|
|
113
|
-
expect(result.content).toContain('PRIVATE_KEY=');
|
|
114
|
-
expect(result.content).toContain('OTHER=value');
|
|
115
|
-
});
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
describe('preview', () => {
|
|
119
|
-
it('should return same result as merge with preview option', async () => {
|
|
120
|
-
const existing = 'A=1';
|
|
121
|
-
const newContent = 'B=2';
|
|
122
|
-
|
|
123
|
-
const previewResult = await merger.preview(existing, newContent);
|
|
124
|
-
const mergeResult = await merger.merge(existing, newContent, { preview: true });
|
|
125
|
-
|
|
126
|
-
expect(previewResult.content).toBe(mergeResult.content);
|
|
127
|
-
expect(previewResult.stats).toEqual(mergeResult.stats);
|
|
128
|
-
});
|
|
129
|
-
});
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
describe('parseEnvFile', () => {
|
|
133
|
-
it('should parse simple key-value pairs', () => {
|
|
134
|
-
const content = `KEY1=value1
|
|
135
|
-
KEY2=value2`;
|
|
136
|
-
|
|
137
|
-
const result = parseEnvFile(content);
|
|
138
|
-
|
|
139
|
-
expect(result.variables.get('KEY1').value).toBe('value1');
|
|
140
|
-
expect(result.variables.get('KEY2').value).toBe('value2');
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
it('should handle quoted values', () => {
|
|
144
|
-
const content = `QUOTED="value with spaces"
|
|
145
|
-
SINGLE='single quoted'`;
|
|
146
|
-
|
|
147
|
-
const result = parseEnvFile(content);
|
|
148
|
-
|
|
149
|
-
expect(result.variables.get('QUOTED').value).toBe('"value with spaces"');
|
|
150
|
-
expect(result.variables.get('SINGLE').value).toBe("'single quoted'");
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
it('should preserve comments', () => {
|
|
154
|
-
const content = `# This is a comment
|
|
155
|
-
KEY=value
|
|
156
|
-
# Another comment`;
|
|
157
|
-
|
|
158
|
-
const result = parseEnvFile(content);
|
|
159
|
-
|
|
160
|
-
expect(result.comments.length).toBeGreaterThan(0);
|
|
161
|
-
expect(result.variables.get('KEY').value).toBe('value');
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
it('should handle empty lines', () => {
|
|
165
|
-
const content = `KEY1=value1
|
|
166
|
-
|
|
167
|
-
KEY2=value2`;
|
|
168
|
-
|
|
169
|
-
const result = parseEnvFile(content);
|
|
170
|
-
|
|
171
|
-
expect(result.variables.get('KEY1').value).toBe('value1');
|
|
172
|
-
expect(result.variables.get('KEY2').value).toBe('value2');
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
it('should handle values with equals signs', () => {
|
|
176
|
-
const content = 'URL=https://example.com?param=value';
|
|
177
|
-
|
|
178
|
-
const result = parseEnvFile(content);
|
|
179
|
-
|
|
180
|
-
expect(result.variables.get('URL').value).toBe('https://example.com?param=value');
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
it('should handle empty values', () => {
|
|
184
|
-
const content = 'EMPTY_VAR=';
|
|
185
|
-
|
|
186
|
-
const result = parseEnvFile(content);
|
|
187
|
-
|
|
188
|
-
expect(result.variables.has('EMPTY_VAR')).toBe(true);
|
|
189
|
-
expect(result.variables.get('EMPTY_VAR').value).toBe('');
|
|
190
|
-
});
|
|
191
|
-
});
|
|
@@ -1,262 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview Tests for MarkdownMerger
|
|
3
|
-
* Story 9.3: Markdown Merge Implementation
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const { MarkdownMerger } = require('../../../src/merger/strategies/markdown-merger.js');
|
|
7
|
-
const {
|
|
8
|
-
parseMarkdownSections,
|
|
9
|
-
slugify,
|
|
10
|
-
hasSinapseMarkers,
|
|
11
|
-
} = require('../../../src/merger/parsers/markdown-section-parser.js');
|
|
12
|
-
|
|
13
|
-
describe('MarkdownMerger', () => {
|
|
14
|
-
let merger;
|
|
15
|
-
|
|
16
|
-
beforeEach(() => {
|
|
17
|
-
merger = new MarkdownMerger();
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
describe('canMerge', () => {
|
|
21
|
-
it('should return true for content with SINAPSE markers', () => {
|
|
22
|
-
const content = `# Title
|
|
23
|
-
<!-- SINAPSE-MANAGED-START: section1 -->
|
|
24
|
-
Content
|
|
25
|
-
<!-- SINAPSE-MANAGED-END: section1 -->`;
|
|
26
|
-
|
|
27
|
-
expect(merger.canMerge(content, '')).toBe(true);
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it('should return false for content without SINAPSE markers', () => {
|
|
31
|
-
const content = `# Title
|
|
32
|
-
Some content without markers`;
|
|
33
|
-
|
|
34
|
-
expect(merger.canMerge(content, '')).toBe(false);
|
|
35
|
-
});
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
describe('merge', () => {
|
|
39
|
-
it('should update SINAPSE-managed sections', async () => {
|
|
40
|
-
const existing = `# My Rules
|
|
41
|
-
|
|
42
|
-
<!-- SINAPSE-MANAGED-START: agent-system -->
|
|
43
|
-
## Old Agent System
|
|
44
|
-
Old content
|
|
45
|
-
<!-- SINAPSE-MANAGED-END: agent-system -->
|
|
46
|
-
|
|
47
|
-
## My Custom Section
|
|
48
|
-
Custom content`;
|
|
49
|
-
|
|
50
|
-
const newContent = `# Template
|
|
51
|
-
|
|
52
|
-
<!-- SINAPSE-MANAGED-START: agent-system -->
|
|
53
|
-
## Agent System
|
|
54
|
-
New updated content
|
|
55
|
-
<!-- SINAPSE-MANAGED-END: agent-system -->`;
|
|
56
|
-
|
|
57
|
-
const result = await merger.merge(existing, newContent);
|
|
58
|
-
|
|
59
|
-
expect(result.content).toContain('## Agent System');
|
|
60
|
-
expect(result.content).toContain('New updated content');
|
|
61
|
-
expect(result.content).toContain('## My Custom Section');
|
|
62
|
-
expect(result.content).toContain('Custom content');
|
|
63
|
-
expect(result.stats.updated).toBe(1);
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
it('should preserve user sections', async () => {
|
|
67
|
-
const existing = `# Rules
|
|
68
|
-
|
|
69
|
-
<!-- SINAPSE-MANAGED-START: core -->
|
|
70
|
-
Core content
|
|
71
|
-
<!-- SINAPSE-MANAGED-END: core -->
|
|
72
|
-
|
|
73
|
-
## My Custom Rules
|
|
74
|
-
1. Rule one
|
|
75
|
-
2. Rule two`;
|
|
76
|
-
|
|
77
|
-
const newContent = `# Template
|
|
78
|
-
|
|
79
|
-
<!-- SINAPSE-MANAGED-START: core -->
|
|
80
|
-
Updated core
|
|
81
|
-
<!-- SINAPSE-MANAGED-END: core -->`;
|
|
82
|
-
|
|
83
|
-
const result = await merger.merge(existing, newContent);
|
|
84
|
-
|
|
85
|
-
expect(result.content).toContain('## My Custom Rules');
|
|
86
|
-
expect(result.content).toContain('1. Rule one');
|
|
87
|
-
expect(result.content).toContain('2. Rule two');
|
|
88
|
-
expect(result.stats.preserved).toBeGreaterThan(0);
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
it('should add new SINAPSE sections that do not exist', async () => {
|
|
92
|
-
const existing = `# Rules
|
|
93
|
-
|
|
94
|
-
<!-- SINAPSE-MANAGED-START: core -->
|
|
95
|
-
Core content
|
|
96
|
-
<!-- SINAPSE-MANAGED-END: core -->`;
|
|
97
|
-
|
|
98
|
-
const newContent = `# Template
|
|
99
|
-
|
|
100
|
-
<!-- SINAPSE-MANAGED-START: core -->
|
|
101
|
-
Updated core
|
|
102
|
-
<!-- SINAPSE-MANAGED-END: core -->
|
|
103
|
-
|
|
104
|
-
<!-- SINAPSE-MANAGED-START: new-section -->
|
|
105
|
-
New section content
|
|
106
|
-
<!-- SINAPSE-MANAGED-END: new-section -->`;
|
|
107
|
-
|
|
108
|
-
const result = await merger.merge(existing, newContent);
|
|
109
|
-
|
|
110
|
-
expect(result.content).toContain('<!-- SINAPSE-MANAGED-START: new-section -->');
|
|
111
|
-
expect(result.content).toContain('New section content');
|
|
112
|
-
expect(result.stats.added).toBe(1);
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
it('should handle files with no SINAPSE sections', async () => {
|
|
116
|
-
const existing = `# My Custom Rules
|
|
117
|
-
|
|
118
|
-
## Section 1
|
|
119
|
-
Content 1
|
|
120
|
-
|
|
121
|
-
## Section 2
|
|
122
|
-
Content 2`;
|
|
123
|
-
|
|
124
|
-
const newContent = `# Template
|
|
125
|
-
|
|
126
|
-
<!-- SINAPSE-MANAGED-START: core -->
|
|
127
|
-
Core content
|
|
128
|
-
<!-- SINAPSE-MANAGED-END: core -->`;
|
|
129
|
-
|
|
130
|
-
const result = await merger.merge(existing, newContent);
|
|
131
|
-
|
|
132
|
-
// Should preserve existing content and add SINAPSE section
|
|
133
|
-
expect(result.content).toContain('## Section 1');
|
|
134
|
-
expect(result.content).toContain('Content 1');
|
|
135
|
-
});
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
describe('migrateLegacy', () => {
|
|
139
|
-
it('should append SINAPSE sections to legacy file', async () => {
|
|
140
|
-
const existing = `# My Old Rules
|
|
141
|
-
Custom content here`;
|
|
142
|
-
|
|
143
|
-
const template = `# Template
|
|
144
|
-
|
|
145
|
-
<!-- SINAPSE-MANAGED-START: core -->
|
|
146
|
-
Core content
|
|
147
|
-
<!-- SINAPSE-MANAGED-END: core -->`;
|
|
148
|
-
|
|
149
|
-
// migrateLegacy expects a parsed template object, so use merge which handles that
|
|
150
|
-
const result = await merger.merge(existing, template);
|
|
151
|
-
|
|
152
|
-
expect(result.content).toContain('# My Old Rules');
|
|
153
|
-
expect(result.content).toContain('Custom content here');
|
|
154
|
-
expect(result.content).toContain('<!-- SINAPSE-MANAGED-START: core -->');
|
|
155
|
-
expect(result.isLegacyMigration).toBe(true);
|
|
156
|
-
});
|
|
157
|
-
});
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
describe('parseMarkdownSections', () => {
|
|
161
|
-
it('should identify SINAPSE-managed sections', () => {
|
|
162
|
-
const content = `# Title
|
|
163
|
-
|
|
164
|
-
<!-- SINAPSE-MANAGED-START: section1 -->
|
|
165
|
-
Managed content
|
|
166
|
-
<!-- SINAPSE-MANAGED-END: section1 -->
|
|
167
|
-
|
|
168
|
-
## User Section
|
|
169
|
-
User content`;
|
|
170
|
-
|
|
171
|
-
const result = parseMarkdownSections(content);
|
|
172
|
-
|
|
173
|
-
const managedSection = result.sections.find((s) => s.id === 'section1');
|
|
174
|
-
expect(managedSection).toBeDefined();
|
|
175
|
-
expect(managedSection.managed).toBe(true);
|
|
176
|
-
expect(managedSection.lines.join('\n')).toContain('Managed content');
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
it('should identify user sections', () => {
|
|
180
|
-
const content = `# Title
|
|
181
|
-
|
|
182
|
-
<!-- SINAPSE-MANAGED-START: managed -->
|
|
183
|
-
Managed
|
|
184
|
-
<!-- SINAPSE-MANAGED-END: managed -->
|
|
185
|
-
|
|
186
|
-
## User Section
|
|
187
|
-
User content`;
|
|
188
|
-
|
|
189
|
-
const result = parseMarkdownSections(content);
|
|
190
|
-
|
|
191
|
-
const userSections = result.sections.filter((s) => !s.managed);
|
|
192
|
-
expect(userSections.length).toBeGreaterThan(0);
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
it('should handle nested content in managed sections', () => {
|
|
196
|
-
const content = `<!-- SINAPSE-MANAGED-START: test -->
|
|
197
|
-
## Heading
|
|
198
|
-
- List item 1
|
|
199
|
-
- List item 2
|
|
200
|
-
|
|
201
|
-
\`\`\`javascript
|
|
202
|
-
const code = true;
|
|
203
|
-
\`\`\`
|
|
204
|
-
<!-- SINAPSE-MANAGED-END: test -->`;
|
|
205
|
-
|
|
206
|
-
const result = parseMarkdownSections(content);
|
|
207
|
-
|
|
208
|
-
const section = result.sections.find((s) => s.id === 'test');
|
|
209
|
-
const sectionContent = section.lines.join('\n');
|
|
210
|
-
expect(sectionContent).toContain('## Heading');
|
|
211
|
-
expect(sectionContent).toContain('- List item 1');
|
|
212
|
-
expect(sectionContent).toContain('const code = true');
|
|
213
|
-
});
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
describe('slugify', () => {
|
|
217
|
-
it('should convert text to lowercase slug', () => {
|
|
218
|
-
expect(slugify('Hello World')).toBe('hello-world');
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
it('should handle special characters', () => {
|
|
222
|
-
expect(slugify('Test & Example!')).toBe('test-example');
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
it('should collapse multiple dashes', () => {
|
|
226
|
-
expect(slugify('Multiple Spaces')).toBe('multiple-spaces');
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
it('should trim leading and trailing dashes', () => {
|
|
230
|
-
expect(slugify(' Trimmed ')).toBe('trimmed');
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
it('should handle numbers', () => {
|
|
234
|
-
// Dots are removed, so numbers become consecutive
|
|
235
|
-
expect(slugify('Section 1.2.3')).toBe('section-123');
|
|
236
|
-
// With spaces between numbers
|
|
237
|
-
expect(slugify('Section 1 2 3')).toBe('section-1-2-3');
|
|
238
|
-
});
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
describe('hasSinapseMarkers', () => {
|
|
242
|
-
it('should return true for content with SINAPSE markers', () => {
|
|
243
|
-
const content = `<!-- SINAPSE-MANAGED-START: test -->
|
|
244
|
-
Content
|
|
245
|
-
<!-- SINAPSE-MANAGED-END: test -->`;
|
|
246
|
-
|
|
247
|
-
expect(hasSinapseMarkers(content)).toBe(true);
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
it('should return false for content without markers', () => {
|
|
251
|
-
const content = '# Just a heading\nSome content';
|
|
252
|
-
|
|
253
|
-
expect(hasSinapseMarkers(content)).toBe(false);
|
|
254
|
-
});
|
|
255
|
-
|
|
256
|
-
it('should return false for incomplete markers', () => {
|
|
257
|
-
const content = '<!-- SINAPSE-MANAGED-START: test -->';
|
|
258
|
-
|
|
259
|
-
expect(hasSinapseMarkers(content)).toBe(false);
|
|
260
|
-
});
|
|
261
|
-
});
|
|
262
|
-
|