sinapse-ai 1.7.0 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/CLAUDE.md +5 -11
- package/.claude/hooks/README.md +14 -1
- package/.claude/hooks/code-intel-pretool.cjs +115 -0
- package/.claude/hooks/enforce-delegation.cjs +31 -3
- package/.claude/hooks/enforce-framework-boundary.cjs +324 -0
- package/.claude/hooks/enforce-permission-mode.cjs +249 -0
- package/.claude/hooks/mind-clone-governance.py +212 -212
- package/.claude/hooks/read-protection.py +152 -152
- package/.claude/hooks/secret-scanning.cjs +34 -43
- package/.claude/hooks/slug-validation.py +175 -175
- package/.claude/hooks/sql-governance.py +183 -183
- package/.claude/hooks/synapse-engine.cjs +23 -23
- package/.claude/hooks/telemetry-post-tool.cjs +128 -0
- package/.claude/hooks/telemetry-stop.cjs +132 -0
- package/.claude/hooks/verify-packages.cjs +9 -2
- package/.claude/rules/documentation-first.md +1 -1
- package/.claude/rules/hook-governance.md +3 -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 +373 -838
- package/.codex/delegation-parity.json +657 -0
- package/.codex/handoff-packet.parity.schema.json +148 -0
- package/.codex/handoff-packet.template.json +26 -0
- package/.codex/instructions.md +6 -6
- 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/cli/commands/health/index.js +24 -0
- package/.sinapse-ai/constitution.md +5 -5
- package/.sinapse-ai/core/README.md +11 -0
- package/.sinapse-ai/core/config/config-loader.js +19 -0
- package/.sinapse-ai/core/doctor/checks/git-hooks.js +97 -19
- package/.sinapse-ai/core/events/dashboard-emitter.js +30 -9
- package/.sinapse-ai/core/execution/build-orchestrator.js +4 -1
- package/.sinapse-ai/core/execution/parallel-executor.js +7 -1
- package/.sinapse-ai/core/execution/subagent-dispatcher.js +126 -28
- package/.sinapse-ai/core/execution/wave-executor.js +4 -1
- package/.sinapse-ai/core/grounding/README.md +71 -11
- package/.sinapse-ai/core/health-check/checks/project/framework-config.js +38 -2
- package/.sinapse-ai/core/health-check/checks/project/package-json.js +47 -3
- package/.sinapse-ai/core/health-check/checks/services/gemini-cli.js +117 -0
- package/.sinapse-ai/core/health-check/checks/services/index.js +2 -0
- package/.sinapse-ai/core/health-check/healers/index.js +40 -3
- package/.sinapse-ai/core/ideation/ideation-engine.js +170 -121
- package/.sinapse-ai/core/ids/gate-evaluator.js +318 -0
- package/.sinapse-ai/core/ids/gates/g5-semantic-handshake.js +190 -0
- package/.sinapse-ai/core/ids/gates/g6-ci-integrity.js +162 -0
- package/.sinapse-ai/core/ids/index.js +30 -0
- package/.sinapse-ai/core/memory/__tests__/active-modules.verify.js +11 -0
- package/.sinapse-ai/core/orchestration/agent-invoker.js +29 -6
- package/.sinapse-ai/core/orchestration/brownfield-handler.js +36 -3
- package/.sinapse-ai/core/orchestration/executors/epic-3-executor.js +76 -5
- package/.sinapse-ai/core/orchestration/executors/epic-4-executor.js +63 -17
- package/.sinapse-ai/core/orchestration/executors/epic-6-executor.js +153 -41
- package/.sinapse-ai/core/orchestration/executors/epic-executor.js +40 -0
- package/.sinapse-ai/core/orchestration/greenfield-handler.js +87 -3
- package/.sinapse-ai/core/orchestration/master-orchestrator.js +105 -7
- package/.sinapse-ai/core/orchestration/parallel-executor.js +6 -1
- package/.sinapse-ai/core/orchestration/workflow-executor.js +41 -0
- package/.sinapse-ai/core/registry/squad-agent-resolver.js +253 -0
- package/.sinapse-ai/core/telemetry/ids-sink.js +188 -0
- package/.sinapse-ai/core/ui/observability-panel.js +240 -0
- package/.sinapse-ai/core/utils/output-formatter.js +8 -290
- package/.sinapse-ai/core-config.yaml +29 -1
- package/.sinapse-ai/data/entity-registry.yaml +15056 -13761
- package/.sinapse-ai/development/agents/developer.md +2 -0
- package/.sinapse-ai/development/agents/devops.md +9 -0
- package/.sinapse-ai/development/agents/snps-orqx.md +12 -22
- package/.sinapse-ai/development/external-executors/README.md +18 -0
- package/.sinapse-ai/development/external-executors/codex.md +56 -0
- package/.sinapse-ai/development/scripts/populate-entity-registry.js +65 -9
- package/.sinapse-ai/development/scripts/squad/squad-downloader.js +54 -11
- 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/delegate-to-external-executor.md +152 -0
- package/.sinapse-ai/development/tasks/github-devops-pre-push-quality-gate.md +46 -29
- 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/update-sinapse.md +3 -3
- 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 +283 -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 +77 -0
- package/.sinapse-ai/hooks/ids-post-commit.js +13 -11
- package/.sinapse-ai/hooks/ids-pre-push.js +9 -7
- package/.sinapse-ai/hooks/sinapse-brand-grounding.cjs +4 -7
- package/.sinapse-ai/hooks/sinapse-ds-grounding.cjs +4 -7
- package/.sinapse-ai/hooks/sinapse-vault-grounding.cjs +4 -7
- package/.sinapse-ai/infrastructure/integrations/ai-providers/ai-provider-factory.js +4 -1
- package/.sinapse-ai/infrastructure/integrations/ai-providers/claude-provider.js +57 -55
- 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 +139 -21
- package/.sinapse-ai/infrastructure/scripts/ide-sync/persona-renderer.js +97 -0
- 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 +239 -223
- 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/.sinapse-ai/scripts/pm.sh +18 -6
- package/AGENTS.md +193 -0
- package/LICENSE +63 -63
- package/README.en.md +17 -18
- package/README.md +18 -19
- package/bin/cli.js +18 -1
- package/bin/commands/agents.js +96 -0
- package/bin/commands/doctor.js +15 -0
- package/bin/commands/ideate.js +129 -0
- package/bin/commands/install.js +194 -22
- package/bin/commands/status.js +14 -1
- package/bin/commands/uninstall.js +40 -0
- package/bin/commands/update.js +52 -0
- package/bin/lib/setup-statusline.js +191 -0
- package/bin/postinstall.js +50 -4
- package/bin/sinapse-init.js +11 -83
- package/bin/sinapse.js +146 -2
- package/bin/utils/framework-guard.js +17 -4
- package/bin/utils/secret-scanner-core.js +283 -0
- package/bin/utils/staged-secret-scan.js +106 -40
- package/bin/utils/staged-sql-guard.js +204 -0
- package/bin/utils/validate-publish.js +63 -0
- package/docs/agent-reference-guide.md +4 -6
- package/docs/framework/agent-prefix-convention.md +58 -0
- package/docs/framework/collaboration-activation.md +45 -0
- package/docs/security/overview.md +1 -1
- package/package.json +16 -8
- package/packages/installer/src/index.js +26 -0
- package/packages/installer/src/installer/git-hooks-installer.js +546 -0
- package/packages/installer/src/installer/sinapse-ai-installer.js +87 -0
- package/packages/installer/src/wizard/feedback.js +1 -1
- package/packages/installer/src/wizard/ide-config-generator.js +40 -25
- package/packages/installer/src/wizard/index.js +50 -0
- package/packages/installer/src/wizard/validators.js +38 -1
- package/packages/installer/tests/unit/artifact-copy-pipeline/artifact-copy-pipeline.test.js +24 -1
- package/packages/installer/tests/unit/doctor/doctor-checks.test.js +42 -3
- package/packages/installer/tests/unit/entity-registry-bootstrap.test.js +10 -4
- package/packages/installer/tests/unit/git-hooks-installer.test.js +262 -0
- 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/eval-runner.js +422 -0
- package/scripts/generate-install-manifest.js +13 -9
- package/scripts/generate-synapse-runtime.js +51 -0
- package/scripts/prepare-hooks.js +58 -0
- package/scripts/regenerate-orqx-stubs.ps1 +2 -2
- package/scripts/validate-agents-md.js +128 -0
- package/scripts/validate-all.js +2 -0
- package/scripts/validate-evals.js +466 -0
- package/scripts/validate-schemas.js +539 -0
- package/scripts/validate-squad-orqx.js +9 -2
- package/sinapse/agents/sinapse-orqx.md +12 -22
- package/sinapse/agents/snps-orqx.md +11 -21
- package/squads/claude-code-mastery/squad.yaml +8 -0
- package/squads/squad-animations/squad.yaml +1 -1
- package/squads/squad-brand/squad.yaml +1 -1
- package/squads/squad-cloning/squad.yaml +1 -1
- package/squads/squad-commercial/squad.yaml +2 -3
- package/squads/squad-content/squad.yaml +1 -1
- package/squads/squad-copy/squad.yaml +2 -3
- package/squads/squad-courses/squad.yaml +1 -1
- package/squads/squad-cybersecurity/squad.yaml +2 -3
- 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/squad.yaml +7 -1
- package/squads/squad-growth/squad.yaml +1 -1
- package/squads/squad-paidmedia/squad.yaml +2 -3
- package/squads/squad-product/squad.yaml +1 -1
- package/squads/squad-research/squad.yaml +2 -3
- 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/data/registry-update-log.jsonl +0 -72
- package/.sinapse-ai/development/scripts/elicitation-engine.js +0 -385
- package/.sinapse-ai/development/scripts/elicitation-session-manager.js +0 -300
- package/.sinapse-ai/development/tasks/test-validation-task.md +0 -172
- 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/bin/sinapse-graph.js +0 -19
- package/docs/codex-integration-process.md +0 -22
- package/docs/codex-parity-program.md +0 -27
- 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
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Hook: Enforce Permission Mode — PreToolUse guard
|
|
6
|
+
*
|
|
7
|
+
* RULE: When the project is in "explore" (read-only) mode, Write and Edit
|
|
8
|
+
* operations are BLOCKED. Read operations are always allowed.
|
|
9
|
+
* Bash commands classified as write/delete/execute are also blocked.
|
|
10
|
+
*
|
|
11
|
+
* Protocol (Claude Code PreToolUse):
|
|
12
|
+
* exit 0 → allow (operation proceeds)
|
|
13
|
+
* exit 2 → block (message shown to model via stderr)
|
|
14
|
+
*
|
|
15
|
+
* Fail-open policy:
|
|
16
|
+
* - If the permission config cannot be loaded, the hook allows (exit 0).
|
|
17
|
+
* - If mode is "ask" or "auto", the hook allows (exit 0).
|
|
18
|
+
* - Any unexpected error: exit 0.
|
|
19
|
+
*
|
|
20
|
+
* @module enforce-permission-mode
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
const fs = require('fs');
|
|
24
|
+
const path = require('path');
|
|
25
|
+
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
// Project root resolution
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
|
|
30
|
+
function projectRoot() {
|
|
31
|
+
return process.env.CLAUDE_PROJECT_DIR || process.cwd();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
// Lightweight mode loader (no yaml dependency — parses the simple key: value)
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Parse `permissions.mode` from a minimal YAML config without requiring js-yaml.
|
|
40
|
+
* Handles:
|
|
41
|
+
* permissions:
|
|
42
|
+
* mode: explore
|
|
43
|
+
*
|
|
44
|
+
* Returns 'ask' (the safe default) if the file is missing, unreadable, or
|
|
45
|
+
* the key is absent.
|
|
46
|
+
*
|
|
47
|
+
* @param {string} configPath
|
|
48
|
+
* @returns {string} mode name
|
|
49
|
+
*/
|
|
50
|
+
function loadPermissionMode(configPath) {
|
|
51
|
+
try {
|
|
52
|
+
const content = fs.readFileSync(configPath, 'utf8');
|
|
53
|
+
// Match "mode: <value>" under a "permissions:" block
|
|
54
|
+
const match = content.match(/^\s*mode:\s*["']?(\w+)["']?\s*$/m);
|
|
55
|
+
if (match) {
|
|
56
|
+
return match[1].toLowerCase();
|
|
57
|
+
}
|
|
58
|
+
} catch {
|
|
59
|
+
// File missing or unreadable — fail-open
|
|
60
|
+
}
|
|
61
|
+
return 'ask';
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// ---------------------------------------------------------------------------
|
|
65
|
+
// Operation classifier (mirrors OperationGuard.classifyOperation)
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
|
|
68
|
+
const SAFE_COMMANDS = [
|
|
69
|
+
'git status', 'git log', 'git diff', 'git branch', 'git show',
|
|
70
|
+
'git ls-files', 'git remote -v',
|
|
71
|
+
'ls', 'pwd', 'cat', 'head', 'tail', 'wc', 'find', 'grep', 'which',
|
|
72
|
+
'file', 'stat',
|
|
73
|
+
'npm list', 'npm outdated', 'npm audit', 'npm view', 'npm search',
|
|
74
|
+
'yarn list', 'yarn info', 'bun pm ls',
|
|
75
|
+
'node --version', 'npm --version', 'yarn --version', 'bun --version',
|
|
76
|
+
'git --version', 'python --version', 'python3 --version',
|
|
77
|
+
'uname', 'whoami', 'hostname', 'date', 'uptime', 'df -h', 'free -h',
|
|
78
|
+
'env', 'printenv',
|
|
79
|
+
'curl -I', 'ping -c', 'nslookup', 'dig',
|
|
80
|
+
'ps aux', 'top -l 1', 'htop',
|
|
81
|
+
'gh auth status', 'gh repo view', 'gh pr list', 'gh pr view',
|
|
82
|
+
'gh issue list', 'gh issue view', 'gh api',
|
|
83
|
+
];
|
|
84
|
+
|
|
85
|
+
const DESTRUCTIVE_PATTERNS = [
|
|
86
|
+
/\brm\s+(-[rf]+\s+)?/,
|
|
87
|
+
/\brmdir\b/,
|
|
88
|
+
/\bunlink\b/,
|
|
89
|
+
/\bgit\s+reset\s+--hard\b/,
|
|
90
|
+
/\bgit\s+push\s+--force\b/,
|
|
91
|
+
/\bgit\s+push\s+-f\b/,
|
|
92
|
+
/\bgit\s+clean\s+-[fd]+/,
|
|
93
|
+
/\bgit\s+checkout\s+\.\s*$/,
|
|
94
|
+
/\bgit\s+restore\s+\.\s*$/,
|
|
95
|
+
/\bgit\s+stash\s+drop\b/,
|
|
96
|
+
/\bgit\s+branch\s+-[dD]\b/,
|
|
97
|
+
/\bDROP\s+(TABLE|DATABASE|INDEX|VIEW)\b/i,
|
|
98
|
+
/\bDELETE\s+FROM\b/i,
|
|
99
|
+
/\bTRUNCATE\b/i,
|
|
100
|
+
/\bALTER\s+TABLE\b.*\bDROP\b/i,
|
|
101
|
+
/\bkill\s+-9\b/,
|
|
102
|
+
/\bkillall\b/,
|
|
103
|
+
/\bshutdown\b/,
|
|
104
|
+
/\breboot\b/,
|
|
105
|
+
/\bnpm\s+uninstall\b/,
|
|
106
|
+
/\byarn\s+remove\b/,
|
|
107
|
+
/\bbun\s+remove\b/,
|
|
108
|
+
];
|
|
109
|
+
|
|
110
|
+
const WRITE_PATTERNS = [
|
|
111
|
+
/[^<]>/,
|
|
112
|
+
/>>/,
|
|
113
|
+
/\bmkdir\b/,
|
|
114
|
+
/\btouch\b/,
|
|
115
|
+
/\bmv\b/,
|
|
116
|
+
/\bcp\b/,
|
|
117
|
+
/\bln\b/,
|
|
118
|
+
/\bchmod\b/,
|
|
119
|
+
/\bchown\b/,
|
|
120
|
+
/\bsed\s+-i\b/,
|
|
121
|
+
/\bawk\s+-i\b/,
|
|
122
|
+
/\bgit\s+add\b/,
|
|
123
|
+
/\bgit\s+commit\b/,
|
|
124
|
+
/\bgit\s+push\b/,
|
|
125
|
+
/\bgit\s+merge\b/,
|
|
126
|
+
/\bgit\s+rebase\b/,
|
|
127
|
+
/\bgit\s+cherry-pick\b/,
|
|
128
|
+
/\bgit\s+stash\b/,
|
|
129
|
+
/\bnpm\s+install\b/,
|
|
130
|
+
/\bnpm\s+i\b/,
|
|
131
|
+
/\bnpm\s+ci\b/,
|
|
132
|
+
/\byarn\s+add\b/,
|
|
133
|
+
/\byarn\s+install\b/,
|
|
134
|
+
/\bbun\s+install\b/,
|
|
135
|
+
/\bbun\s+add\b/,
|
|
136
|
+
];
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Classify a Bash command as read/write/delete/execute.
|
|
140
|
+
* @param {string} command
|
|
141
|
+
* @returns {string}
|
|
142
|
+
*/
|
|
143
|
+
function classifyBashCommand(command) {
|
|
144
|
+
const normalized = command.trim().toLowerCase();
|
|
145
|
+
for (const safe of SAFE_COMMANDS) {
|
|
146
|
+
if (normalized.startsWith(safe.toLowerCase())) return 'read';
|
|
147
|
+
}
|
|
148
|
+
for (const pat of DESTRUCTIVE_PATTERNS) {
|
|
149
|
+
if (pat.test(command)) return 'delete';
|
|
150
|
+
}
|
|
151
|
+
for (const pat of WRITE_PATTERNS) {
|
|
152
|
+
if (pat.test(command)) return 'write';
|
|
153
|
+
}
|
|
154
|
+
return 'execute';
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Classify a tool call into an operation type.
|
|
159
|
+
* @param {string} tool
|
|
160
|
+
* @param {Object} params
|
|
161
|
+
* @returns {string}
|
|
162
|
+
*/
|
|
163
|
+
function classifyOperation(tool, params) {
|
|
164
|
+
if (['Read', 'Glob', 'Grep', 'WebFetch', 'WebSearch'].includes(tool)) return 'read';
|
|
165
|
+
if (['Write', 'Edit', 'NotebookEdit'].includes(tool)) return 'write';
|
|
166
|
+
if (tool === 'Bash') return classifyBashCommand(params.command || '');
|
|
167
|
+
if (tool === 'Task') {
|
|
168
|
+
const readOnlyAgents = ['Explore', 'Plan', 'claude-code-guide'];
|
|
169
|
+
return readOnlyAgents.includes(params.subagent_type) ? 'read' : 'execute';
|
|
170
|
+
}
|
|
171
|
+
if (tool.startsWith('mcp__')) return 'execute';
|
|
172
|
+
return 'read'; // default to read (safe)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// ---------------------------------------------------------------------------
|
|
176
|
+
// Main
|
|
177
|
+
// ---------------------------------------------------------------------------
|
|
178
|
+
|
|
179
|
+
function main() {
|
|
180
|
+
// Parse stdin — fail-open on any parse error
|
|
181
|
+
let input;
|
|
182
|
+
try {
|
|
183
|
+
input = JSON.parse(fs.readFileSync(0, 'utf8'));
|
|
184
|
+
} catch {
|
|
185
|
+
process.exit(0);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const toolName = (input.tool_name || '').trim();
|
|
189
|
+
const toolInput = input.tool_input || {};
|
|
190
|
+
|
|
191
|
+
// Resolve project root
|
|
192
|
+
const root = projectRoot();
|
|
193
|
+
const configPath = path.join(root, '.sinapse', 'config.yaml');
|
|
194
|
+
|
|
195
|
+
// Load permission mode — fail-open if unresolvable
|
|
196
|
+
let mode;
|
|
197
|
+
try {
|
|
198
|
+
mode = loadPermissionMode(configPath);
|
|
199
|
+
} catch {
|
|
200
|
+
process.exit(0);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Only enforce in explore mode. All other modes: allow.
|
|
204
|
+
if (mode !== 'explore') {
|
|
205
|
+
process.exit(0);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Classify the operation
|
|
209
|
+
let operation;
|
|
210
|
+
try {
|
|
211
|
+
operation = classifyOperation(toolName, toolInput);
|
|
212
|
+
} catch {
|
|
213
|
+
process.exit(0); // fail-open
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// In explore mode, only reads are allowed
|
|
217
|
+
if (operation === 'read') {
|
|
218
|
+
process.exit(0);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Build context for the block message
|
|
222
|
+
let detail = '';
|
|
223
|
+
if (toolName === 'Bash' && toolInput.command) {
|
|
224
|
+
const cmd = toolInput.command;
|
|
225
|
+
detail = `\nCommand: ${cmd.length > 120 ? cmd.slice(0, 120) + '...' : cmd}`;
|
|
226
|
+
} else if (toolInput.file_path) {
|
|
227
|
+
detail = `\nFile: ${toolInput.file_path}`;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// BLOCK — exit 2
|
|
231
|
+
process.stderr.write(
|
|
232
|
+
`\nPERMISSION-MODE BLOCK [Explore / Read-Only]\n` +
|
|
233
|
+
`Tool: ${toolName} Operation: ${operation}${detail}\n` +
|
|
234
|
+
`\n` +
|
|
235
|
+
`The project is in Explore (read-only) mode. Write, Edit, and destructive\n` +
|
|
236
|
+
`Bash commands are not allowed in this mode.\n` +
|
|
237
|
+
`\n` +
|
|
238
|
+
`To enable writes, change the permission mode:\n` +
|
|
239
|
+
` *mode ask — confirm before each change\n` +
|
|
240
|
+
` *mode auto — full autonomy (no prompts)\n` +
|
|
241
|
+
`\n` +
|
|
242
|
+
`Or update .sinapse/config.yaml:\n` +
|
|
243
|
+
` permissions:\n` +
|
|
244
|
+
` mode: ask\n`,
|
|
245
|
+
);
|
|
246
|
+
process.exit(2);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
main();
|
|
@@ -1,212 +1,212 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
Hook: Mind Clone Governance
|
|
4
|
-
|
|
5
|
-
REGRA: Agents baseados em pessoas reais (mind clones) DEVEM passar pelo
|
|
6
|
-
pipeline de extração de DNA antes de serem criados.
|
|
7
|
-
|
|
8
|
-
Este hook intercepta Write/Edit em squads/*/agents/*.md e verifica:
|
|
9
|
-
1. Se é um mind clone (baseado em pessoa real)
|
|
10
|
-
2. Se existe DNA extraído correspondente
|
|
11
|
-
|
|
12
|
-
NÃO BLOQUEIA:
|
|
13
|
-
- Orchestrators (nome contém 'chief', 'orchestrator', 'chair')
|
|
14
|
-
- Tool agents (nome contém 'validator', 'calculator', 'generator')
|
|
15
|
-
- Process agents (nome contém 'architect', 'mapper', 'designer')
|
|
16
|
-
- Edição de arquivo existente (apenas criação é bloqueada)
|
|
17
|
-
|
|
18
|
-
Exit Codes:
|
|
19
|
-
- 0: Permitido
|
|
20
|
-
- 2: Bloqueado (mind clone sem DNA)
|
|
21
|
-
"""
|
|
22
|
-
|
|
23
|
-
import json
|
|
24
|
-
import sys
|
|
25
|
-
import os
|
|
26
|
-
import re
|
|
27
|
-
from pathlib import Path
|
|
28
|
-
|
|
29
|
-
# =============================================================================
|
|
30
|
-
# CONFIGURAÇÃO
|
|
31
|
-
# =============================================================================
|
|
32
|
-
|
|
33
|
-
# Padrões que indicam que NÃO é um mind clone (agents funcionais)
|
|
34
|
-
FUNCTIONAL_AGENT_PATTERNS = [
|
|
35
|
-
# Orchestrators
|
|
36
|
-
r'.*-chief$',
|
|
37
|
-
r'.*-orchestrator$',
|
|
38
|
-
r'.*-chair$',
|
|
39
|
-
r'^orchestrator$',
|
|
40
|
-
|
|
41
|
-
# Tool agents
|
|
42
|
-
r'.*-validator$',
|
|
43
|
-
r'.*-calculator$',
|
|
44
|
-
r'.*-generator$',
|
|
45
|
-
r'.*-extractor$',
|
|
46
|
-
r'.*-analyzer$',
|
|
47
|
-
|
|
48
|
-
# Process agents
|
|
49
|
-
r'.*-architect$',
|
|
50
|
-
r'.*-mapper$',
|
|
51
|
-
r'.*-designer$',
|
|
52
|
-
r'.*-engineer$',
|
|
53
|
-
|
|
54
|
-
# Generic functional
|
|
55
|
-
r'^tools?-.*',
|
|
56
|
-
r'^process-.*',
|
|
57
|
-
r'^workflow-.*',
|
|
58
|
-
]
|
|
59
|
-
|
|
60
|
-
# Locais onde DNA pode estar
|
|
61
|
-
DNA_LOCATIONS = [
|
|
62
|
-
"squads/{pack}/data/minds/{agent_id}_dna.yaml",
|
|
63
|
-
"squads/{pack}/data/minds/{agent_id}_dna.md",
|
|
64
|
-
"squads/{pack}/data/{agent_id}-dna.yaml",
|
|
65
|
-
"outputs/minds/{agent_id}/",
|
|
66
|
-
]
|
|
67
|
-
|
|
68
|
-
# =============================================================================
|
|
69
|
-
# LÓGICA DO HOOK
|
|
70
|
-
# =============================================================================
|
|
71
|
-
|
|
72
|
-
def get_project_root():
|
|
73
|
-
"""Obtém o root do projeto via variável de ambiente ou cwd."""
|
|
74
|
-
return os.environ.get("CLAUDE_PROJECT_DIR", os.getcwd())
|
|
75
|
-
|
|
76
|
-
def extract_agent_info(file_path: str) -> tuple:
|
|
77
|
-
"""Extrai pack_name e agent_id do path."""
|
|
78
|
-
# squads/{pack}/agents/{agent_id}.md
|
|
79
|
-
match = re.match(r'.*/squads/([^/]+)/agents/([^/]+)\.md$', file_path)
|
|
80
|
-
if match:
|
|
81
|
-
return match.group(1), match.group(2)
|
|
82
|
-
return None, None
|
|
83
|
-
|
|
84
|
-
def is_functional_agent(agent_id: str) -> bool:
|
|
85
|
-
"""Verifica se o agent é funcional (não é mind clone)."""
|
|
86
|
-
for pattern in FUNCTIONAL_AGENT_PATTERNS:
|
|
87
|
-
if re.match(pattern, agent_id, re.IGNORECASE):
|
|
88
|
-
return True
|
|
89
|
-
return False
|
|
90
|
-
|
|
91
|
-
def has_dna_extracted(project_root: str, pack_name: str, agent_id: str) -> tuple:
|
|
92
|
-
"""Verifica se existe DNA extraído para o agent."""
|
|
93
|
-
for location_template in DNA_LOCATIONS:
|
|
94
|
-
location = location_template.format(pack=pack_name, agent_id=agent_id)
|
|
95
|
-
full_path = os.path.join(project_root, location)
|
|
96
|
-
|
|
97
|
-
# Se é diretório, verificar se existe
|
|
98
|
-
if location.endswith('/'):
|
|
99
|
-
if os.path.isdir(full_path):
|
|
100
|
-
return True, full_path
|
|
101
|
-
# Se é arquivo, verificar se existe
|
|
102
|
-
elif os.path.isfile(full_path):
|
|
103
|
-
return True, full_path
|
|
104
|
-
|
|
105
|
-
return False, None
|
|
106
|
-
|
|
107
|
-
def file_already_exists(file_path: str) -> bool:
|
|
108
|
-
"""Verifica se o arquivo já existe (edit vs create)."""
|
|
109
|
-
return os.path.isfile(file_path)
|
|
110
|
-
|
|
111
|
-
def main():
|
|
112
|
-
# Ler input do stdin
|
|
113
|
-
try:
|
|
114
|
-
input_data = json.load(sys.stdin)
|
|
115
|
-
except json.JSONDecodeError:
|
|
116
|
-
# Se não conseguir parsear, permitir (fail-open)
|
|
117
|
-
sys.exit(0)
|
|
118
|
-
|
|
119
|
-
tool_name = input_data.get("tool_name", "")
|
|
120
|
-
tool_input = input_data.get("tool_input", {})
|
|
121
|
-
|
|
122
|
-
# Só processar Write e Edit
|
|
123
|
-
if tool_name not in ["Write", "Edit"]:
|
|
124
|
-
sys.exit(0)
|
|
125
|
-
|
|
126
|
-
file_path = tool_input.get("file_path", "")
|
|
127
|
-
if not file_path:
|
|
128
|
-
sys.exit(0)
|
|
129
|
-
|
|
130
|
-
# Só processar arquivos em squads/*/agents/
|
|
131
|
-
if "/squads/" not in file_path or "/agents/" not in file_path:
|
|
132
|
-
sys.exit(0)
|
|
133
|
-
|
|
134
|
-
if not file_path.endswith(".md"):
|
|
135
|
-
sys.exit(0)
|
|
136
|
-
|
|
137
|
-
project_root = get_project_root()
|
|
138
|
-
|
|
139
|
-
# Extrair informações do path
|
|
140
|
-
pack_name, agent_id = extract_agent_info(file_path)
|
|
141
|
-
if not pack_name or not agent_id:
|
|
142
|
-
sys.exit(0)
|
|
143
|
-
|
|
144
|
-
# Se é agent funcional (não mind clone), permitir
|
|
145
|
-
if is_functional_agent(agent_id):
|
|
146
|
-
sys.exit(0)
|
|
147
|
-
|
|
148
|
-
# Block 3b — fail-closed para edição de arquivo existente:
|
|
149
|
-
# se o arquivo NÃO carrega o marker BEGIN PERSONA NOTICE, bloqueia.
|
|
150
|
-
# (Antes era fail-open em arquivos existentes — todos os 22 personas
|
|
151
|
-
# foram grandfathered em 2025 sem disclaimer. Decisão 1c do clinical
|
|
152
|
-
# audit dim-7 exige disclaimer obrigatório agora.)
|
|
153
|
-
if file_already_exists(file_path):
|
|
154
|
-
try:
|
|
155
|
-
with open(file_path, "r", encoding="utf-8") as fh:
|
|
156
|
-
existing = fh.read()
|
|
157
|
-
if "<!-- BEGIN PERSONA NOTICE" in existing:
|
|
158
|
-
sys.exit(0)
|
|
159
|
-
# Edição de mind clone existente sem o disclaimer.
|
|
160
|
-
print(
|
|
161
|
-
f"\nMIND CLONE GOVERNANCE: arquivo {agent_id}.md é uma persona simulada "
|
|
162
|
-
"mas não carrega o marker '<!-- BEGIN PERSONA NOTICE -->'. "
|
|
163
|
-
"Rode 'node scripts/apply-persona-disclaimer.js' antes de editar.",
|
|
164
|
-
file=sys.stderr,
|
|
165
|
-
)
|
|
166
|
-
sys.exit(2)
|
|
167
|
-
except Exception:
|
|
168
|
-
# Fail-open em erros de leitura — preserva princípio "hook não derruba dev".
|
|
169
|
-
sys.exit(0)
|
|
170
|
-
|
|
171
|
-
# Verificar se existe DNA extraído
|
|
172
|
-
has_dna, dna_path = has_dna_extracted(project_root, pack_name, agent_id)
|
|
173
|
-
|
|
174
|
-
if has_dna:
|
|
175
|
-
sys.exit(0)
|
|
176
|
-
|
|
177
|
-
# BLOQUEAR: Tentando criar mind clone sem DNA
|
|
178
|
-
error_message = f"""
|
|
179
|
-
╔══════════════════════════════════════════════════════════════════════════════╗
|
|
180
|
-
║ 🧬 MIND CLONE GOVERNANCE: DNA não encontrado ║
|
|
181
|
-
╠══════════════════════════════════════════════════════════════════════════════╣
|
|
182
|
-
║ ║
|
|
183
|
-
║ Agent: {agent_id:<60} ║
|
|
184
|
-
║ Pack: {pack_name:<60} ║
|
|
185
|
-
║ ║
|
|
186
|
-
║ PROBLEMA: Este parece ser um MIND CLONE (baseado em pessoa real), ║
|
|
187
|
-
║ mas não foi encontrado DNA extraído. ║
|
|
188
|
-
║ ║
|
|
189
|
-
║ Mind clones DEVEM passar pelo pipeline de extração: ║
|
|
190
|
-
║ 1. *collect-sources → Coletar fontes (livros, entrevistas, artigos) ║
|
|
191
|
-
║ 2. *extract-voice-dna → Extrair padrões linguísticos ║
|
|
192
|
-
║ 3. *extract-thinking-dna → Extrair frameworks e heurísticas ║
|
|
193
|
-
║ 4. *create-agent → Criar agent a partir do DNA ║
|
|
194
|
-
║ ║
|
|
195
|
-
║ LOCAIS VERIFICADOS: ║
|
|
196
|
-
║ • squads/{pack_name}/data/minds/{agent_id}_dna.yaml
|
|
197
|
-
║ • squads/{pack_name}/data/minds/{agent_id}_dna.md
|
|
198
|
-
║ • outputs/minds/{agent_id}/
|
|
199
|
-
║ ║
|
|
200
|
-
║ SOLUÇÕES: ║
|
|
201
|
-
║ 1. Execute o pipeline de clone: /squad-creator → *collect-sources ║
|
|
202
|
-
║ 2. OU se é agent FUNCIONAL, renomeie com sufixo: ║
|
|
203
|
-
║ -chief, -orchestrator, -validator, -architect, etc. ║
|
|
204
|
-
║ ║
|
|
205
|
-
╚══════════════════════════════════════════════════════════════════════════════╝
|
|
206
|
-
"""
|
|
207
|
-
print(error_message, file=sys.stderr)
|
|
208
|
-
sys.exit(2)
|
|
209
|
-
|
|
210
|
-
if __name__ == "__main__":
|
|
211
|
-
main()
|
|
212
|
-
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Hook: Mind Clone Governance
|
|
4
|
+
|
|
5
|
+
REGRA: Agents baseados em pessoas reais (mind clones) DEVEM passar pelo
|
|
6
|
+
pipeline de extração de DNA antes de serem criados.
|
|
7
|
+
|
|
8
|
+
Este hook intercepta Write/Edit em squads/*/agents/*.md e verifica:
|
|
9
|
+
1. Se é um mind clone (baseado em pessoa real)
|
|
10
|
+
2. Se existe DNA extraído correspondente
|
|
11
|
+
|
|
12
|
+
NÃO BLOQUEIA:
|
|
13
|
+
- Orchestrators (nome contém 'chief', 'orchestrator', 'chair')
|
|
14
|
+
- Tool agents (nome contém 'validator', 'calculator', 'generator')
|
|
15
|
+
- Process agents (nome contém 'architect', 'mapper', 'designer')
|
|
16
|
+
- Edição de arquivo existente (apenas criação é bloqueada)
|
|
17
|
+
|
|
18
|
+
Exit Codes:
|
|
19
|
+
- 0: Permitido
|
|
20
|
+
- 2: Bloqueado (mind clone sem DNA)
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
import json
|
|
24
|
+
import sys
|
|
25
|
+
import os
|
|
26
|
+
import re
|
|
27
|
+
from pathlib import Path
|
|
28
|
+
|
|
29
|
+
# =============================================================================
|
|
30
|
+
# CONFIGURAÇÃO
|
|
31
|
+
# =============================================================================
|
|
32
|
+
|
|
33
|
+
# Padrões que indicam que NÃO é um mind clone (agents funcionais)
|
|
34
|
+
FUNCTIONAL_AGENT_PATTERNS = [
|
|
35
|
+
# Orchestrators
|
|
36
|
+
r'.*-chief$',
|
|
37
|
+
r'.*-orchestrator$',
|
|
38
|
+
r'.*-chair$',
|
|
39
|
+
r'^orchestrator$',
|
|
40
|
+
|
|
41
|
+
# Tool agents
|
|
42
|
+
r'.*-validator$',
|
|
43
|
+
r'.*-calculator$',
|
|
44
|
+
r'.*-generator$',
|
|
45
|
+
r'.*-extractor$',
|
|
46
|
+
r'.*-analyzer$',
|
|
47
|
+
|
|
48
|
+
# Process agents
|
|
49
|
+
r'.*-architect$',
|
|
50
|
+
r'.*-mapper$',
|
|
51
|
+
r'.*-designer$',
|
|
52
|
+
r'.*-engineer$',
|
|
53
|
+
|
|
54
|
+
# Generic functional
|
|
55
|
+
r'^tools?-.*',
|
|
56
|
+
r'^process-.*',
|
|
57
|
+
r'^workflow-.*',
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
# Locais onde DNA pode estar
|
|
61
|
+
DNA_LOCATIONS = [
|
|
62
|
+
"squads/{pack}/data/minds/{agent_id}_dna.yaml",
|
|
63
|
+
"squads/{pack}/data/minds/{agent_id}_dna.md",
|
|
64
|
+
"squads/{pack}/data/{agent_id}-dna.yaml",
|
|
65
|
+
"outputs/minds/{agent_id}/",
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
# =============================================================================
|
|
69
|
+
# LÓGICA DO HOOK
|
|
70
|
+
# =============================================================================
|
|
71
|
+
|
|
72
|
+
def get_project_root():
|
|
73
|
+
"""Obtém o root do projeto via variável de ambiente ou cwd."""
|
|
74
|
+
return os.environ.get("CLAUDE_PROJECT_DIR", os.getcwd())
|
|
75
|
+
|
|
76
|
+
def extract_agent_info(file_path: str) -> tuple:
|
|
77
|
+
"""Extrai pack_name e agent_id do path."""
|
|
78
|
+
# squads/{pack}/agents/{agent_id}.md
|
|
79
|
+
match = re.match(r'.*/squads/([^/]+)/agents/([^/]+)\.md$', file_path)
|
|
80
|
+
if match:
|
|
81
|
+
return match.group(1), match.group(2)
|
|
82
|
+
return None, None
|
|
83
|
+
|
|
84
|
+
def is_functional_agent(agent_id: str) -> bool:
|
|
85
|
+
"""Verifica se o agent é funcional (não é mind clone)."""
|
|
86
|
+
for pattern in FUNCTIONAL_AGENT_PATTERNS:
|
|
87
|
+
if re.match(pattern, agent_id, re.IGNORECASE):
|
|
88
|
+
return True
|
|
89
|
+
return False
|
|
90
|
+
|
|
91
|
+
def has_dna_extracted(project_root: str, pack_name: str, agent_id: str) -> tuple:
|
|
92
|
+
"""Verifica se existe DNA extraído para o agent."""
|
|
93
|
+
for location_template in DNA_LOCATIONS:
|
|
94
|
+
location = location_template.format(pack=pack_name, agent_id=agent_id)
|
|
95
|
+
full_path = os.path.join(project_root, location)
|
|
96
|
+
|
|
97
|
+
# Se é diretório, verificar se existe
|
|
98
|
+
if location.endswith('/'):
|
|
99
|
+
if os.path.isdir(full_path):
|
|
100
|
+
return True, full_path
|
|
101
|
+
# Se é arquivo, verificar se existe
|
|
102
|
+
elif os.path.isfile(full_path):
|
|
103
|
+
return True, full_path
|
|
104
|
+
|
|
105
|
+
return False, None
|
|
106
|
+
|
|
107
|
+
def file_already_exists(file_path: str) -> bool:
|
|
108
|
+
"""Verifica se o arquivo já existe (edit vs create)."""
|
|
109
|
+
return os.path.isfile(file_path)
|
|
110
|
+
|
|
111
|
+
def main():
|
|
112
|
+
# Ler input do stdin
|
|
113
|
+
try:
|
|
114
|
+
input_data = json.load(sys.stdin)
|
|
115
|
+
except json.JSONDecodeError:
|
|
116
|
+
# Se não conseguir parsear, permitir (fail-open)
|
|
117
|
+
sys.exit(0)
|
|
118
|
+
|
|
119
|
+
tool_name = input_data.get("tool_name", "")
|
|
120
|
+
tool_input = input_data.get("tool_input", {})
|
|
121
|
+
|
|
122
|
+
# Só processar Write e Edit
|
|
123
|
+
if tool_name not in ["Write", "Edit"]:
|
|
124
|
+
sys.exit(0)
|
|
125
|
+
|
|
126
|
+
file_path = tool_input.get("file_path", "")
|
|
127
|
+
if not file_path:
|
|
128
|
+
sys.exit(0)
|
|
129
|
+
|
|
130
|
+
# Só processar arquivos em squads/*/agents/
|
|
131
|
+
if "/squads/" not in file_path or "/agents/" not in file_path:
|
|
132
|
+
sys.exit(0)
|
|
133
|
+
|
|
134
|
+
if not file_path.endswith(".md"):
|
|
135
|
+
sys.exit(0)
|
|
136
|
+
|
|
137
|
+
project_root = get_project_root()
|
|
138
|
+
|
|
139
|
+
# Extrair informações do path
|
|
140
|
+
pack_name, agent_id = extract_agent_info(file_path)
|
|
141
|
+
if not pack_name or not agent_id:
|
|
142
|
+
sys.exit(0)
|
|
143
|
+
|
|
144
|
+
# Se é agent funcional (não mind clone), permitir
|
|
145
|
+
if is_functional_agent(agent_id):
|
|
146
|
+
sys.exit(0)
|
|
147
|
+
|
|
148
|
+
# Block 3b — fail-closed para edição de arquivo existente:
|
|
149
|
+
# se o arquivo NÃO carrega o marker BEGIN PERSONA NOTICE, bloqueia.
|
|
150
|
+
# (Antes era fail-open em arquivos existentes — todos os 22 personas
|
|
151
|
+
# foram grandfathered em 2025 sem disclaimer. Decisão 1c do clinical
|
|
152
|
+
# audit dim-7 exige disclaimer obrigatório agora.)
|
|
153
|
+
if file_already_exists(file_path):
|
|
154
|
+
try:
|
|
155
|
+
with open(file_path, "r", encoding="utf-8") as fh:
|
|
156
|
+
existing = fh.read()
|
|
157
|
+
if "<!-- BEGIN PERSONA NOTICE" in existing:
|
|
158
|
+
sys.exit(0)
|
|
159
|
+
# Edição de mind clone existente sem o disclaimer.
|
|
160
|
+
print(
|
|
161
|
+
f"\nMIND CLONE GOVERNANCE: arquivo {agent_id}.md é uma persona simulada "
|
|
162
|
+
"mas não carrega o marker '<!-- BEGIN PERSONA NOTICE -->'. "
|
|
163
|
+
"Rode 'node scripts/apply-persona-disclaimer.js' antes de editar.",
|
|
164
|
+
file=sys.stderr,
|
|
165
|
+
)
|
|
166
|
+
sys.exit(2)
|
|
167
|
+
except Exception:
|
|
168
|
+
# Fail-open em erros de leitura — preserva princípio "hook não derruba dev".
|
|
169
|
+
sys.exit(0)
|
|
170
|
+
|
|
171
|
+
# Verificar se existe DNA extraído
|
|
172
|
+
has_dna, dna_path = has_dna_extracted(project_root, pack_name, agent_id)
|
|
173
|
+
|
|
174
|
+
if has_dna:
|
|
175
|
+
sys.exit(0)
|
|
176
|
+
|
|
177
|
+
# BLOQUEAR: Tentando criar mind clone sem DNA
|
|
178
|
+
error_message = f"""
|
|
179
|
+
╔══════════════════════════════════════════════════════════════════════════════╗
|
|
180
|
+
║ 🧬 MIND CLONE GOVERNANCE: DNA não encontrado ║
|
|
181
|
+
╠══════════════════════════════════════════════════════════════════════════════╣
|
|
182
|
+
║ ║
|
|
183
|
+
║ Agent: {agent_id:<60} ║
|
|
184
|
+
║ Pack: {pack_name:<60} ║
|
|
185
|
+
║ ║
|
|
186
|
+
║ PROBLEMA: Este parece ser um MIND CLONE (baseado em pessoa real), ║
|
|
187
|
+
║ mas não foi encontrado DNA extraído. ║
|
|
188
|
+
║ ║
|
|
189
|
+
║ Mind clones DEVEM passar pelo pipeline de extração: ║
|
|
190
|
+
║ 1. *collect-sources → Coletar fontes (livros, entrevistas, artigos) ║
|
|
191
|
+
║ 2. *extract-voice-dna → Extrair padrões linguísticos ║
|
|
192
|
+
║ 3. *extract-thinking-dna → Extrair frameworks e heurísticas ║
|
|
193
|
+
║ 4. *create-agent → Criar agent a partir do DNA ║
|
|
194
|
+
║ ║
|
|
195
|
+
║ LOCAIS VERIFICADOS: ║
|
|
196
|
+
║ • squads/{pack_name}/data/minds/{agent_id}_dna.yaml
|
|
197
|
+
║ • squads/{pack_name}/data/minds/{agent_id}_dna.md
|
|
198
|
+
║ • outputs/minds/{agent_id}/
|
|
199
|
+
║ ║
|
|
200
|
+
║ SOLUÇÕES: ║
|
|
201
|
+
║ 1. Execute o pipeline de clone: /squad-creator → *collect-sources ║
|
|
202
|
+
║ 2. OU se é agent FUNCIONAL, renomeie com sufixo: ║
|
|
203
|
+
║ -chief, -orchestrator, -validator, -architect, etc. ║
|
|
204
|
+
║ ║
|
|
205
|
+
╚══════════════════════════════════════════════════════════════════════════════╝
|
|
206
|
+
"""
|
|
207
|
+
print(error_message, file=sys.stderr)
|
|
208
|
+
sys.exit(2)
|
|
209
|
+
|
|
210
|
+
if __name__ == "__main__":
|
|
211
|
+
main()
|
|
212
|
+
|