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
|
@@ -28,6 +28,16 @@ const ExecutorAssignment = require('./executor-assignment');
|
|
|
28
28
|
const TerminalSpawner = require('./terminal-spawner');
|
|
29
29
|
const { SessionState, ActionType } = require('./session-state');
|
|
30
30
|
|
|
31
|
+
// IDS Gate Wiring: GateEvaluator wires the IDS verification gates into the
|
|
32
|
+
// development phase. Loaded with a fallback so a missing module never breaks
|
|
33
|
+
// the workflow (graceful degradation — IDS must never block development).
|
|
34
|
+
let GateEvaluator = null;
|
|
35
|
+
try {
|
|
36
|
+
GateEvaluator = require('../ids/gate-evaluator').GateEvaluator;
|
|
37
|
+
} catch (_err) {
|
|
38
|
+
// GateEvaluator unavailable — workflow runs without IDS gate enrichment.
|
|
39
|
+
}
|
|
40
|
+
|
|
31
41
|
// Constants
|
|
32
42
|
const DEFAULT_TIMEOUT_MS = 7200000; // 2 hours
|
|
33
43
|
const CHECKPOINT_TIMEOUT_MS = 1800000; // 30 minutes
|
|
@@ -599,6 +609,37 @@ class WorkflowExecutor {
|
|
|
599
609
|
// Story 12.6: Emit agent spawn for observability (AC1)
|
|
600
610
|
this._emitAgentSpawn(agent, 'development');
|
|
601
611
|
|
|
612
|
+
// IDS Gate Wiring: evaluate the IDS gates mapped to the development phase
|
|
613
|
+
// (G4 advisory dev-context + G5 blocking semantic-handshake). Fail-open:
|
|
614
|
+
// any evaluator failure is logged and the workflow proceeds. Only a real
|
|
615
|
+
// G5 BLOCKER violation fails the phase.
|
|
616
|
+
if (GateEvaluator) {
|
|
617
|
+
try {
|
|
618
|
+
const evaluator = new GateEvaluator(this.config?.ids || {});
|
|
619
|
+
const storyId = path.basename(storyPath, path.extname(storyPath));
|
|
620
|
+
const verdict = await evaluator.evaluateGatesForPhase('2_development', {
|
|
621
|
+
intent: phase.description || storyId,
|
|
622
|
+
storyId,
|
|
623
|
+
filePaths: [],
|
|
624
|
+
});
|
|
625
|
+
|
|
626
|
+
if (verdict.blocked) {
|
|
627
|
+
return {
|
|
628
|
+
status: PhaseStatus.FAILED,
|
|
629
|
+
error: `[IDS-${verdict.blockingGate}] Semantic Handshake blocker: ${verdict.correctionPrompt}`,
|
|
630
|
+
gateVerdict: verdict,
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
if (this.options.debug && verdict.results.length > 0) {
|
|
635
|
+
console.log('[WorkflowExecutor] IDS gate advisory:', JSON.stringify(verdict.results));
|
|
636
|
+
}
|
|
637
|
+
} catch (gateError) {
|
|
638
|
+
// Fail-open: a degraded evaluator never halts development.
|
|
639
|
+
console.warn(`[WorkflowExecutor] IDS gate-evaluator degraded: ${gateError.message}`);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
|
|
602
643
|
// Use terminal spawning (Story 11.2)
|
|
603
644
|
if (phase.spawn_in_terminal && TerminalSpawner.isSpawnerAvailable()) {
|
|
604
645
|
const context = {
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Squad Agent Resolver
|
|
3
|
+
*
|
|
4
|
+
* epic: orchestration-consolidation, F2 — makes the 177 squad personas (plus the
|
|
5
|
+
* framework agents) addressable BY CODE. Before this, the SubagentDispatcher knew
|
|
6
|
+
* only ~10 generic agents (@dev/@qa/...) and built a one-line "You are @x" prompt,
|
|
7
|
+
* discarding the real persona. This indexes every agent .md across `squads/` and
|
|
8
|
+
* the framework agent dirs, and loads the FULL persona on demand.
|
|
9
|
+
*
|
|
10
|
+
* Convention (verified across all squads): the agent id IS the file basename in
|
|
11
|
+
* kebab-case (e.g. `penetration-tester.md` -> id `penetration-tester`), which
|
|
12
|
+
* matches the embedded `id:` field. We key by basename for robustness and also
|
|
13
|
+
* register the embedded id / display name as aliases when present.
|
|
14
|
+
*
|
|
15
|
+
* @module core/registry/squad-agent-resolver
|
|
16
|
+
* @version 1.0.0
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
const fs = require('fs');
|
|
20
|
+
const path = require('path');
|
|
21
|
+
|
|
22
|
+
/** Directories scanned for agent definitions, relative to projectRoot. */
|
|
23
|
+
const AGENT_DIRS = [
|
|
24
|
+
'squads', // squads/<squad>/agents/<id>.md
|
|
25
|
+
path.join('.sinapse-ai', 'agents'),
|
|
26
|
+
path.join('.sinapse-ai', 'development', 'agents'),
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Short-form aliases used across the framework (dispatcher agentMapping, CLAUDE.md
|
|
31
|
+
* command table) → canonical file id. Lets '@dev' resolve to the developer persona
|
|
32
|
+
* instead of falling through to a one-line generic prompt.
|
|
33
|
+
*/
|
|
34
|
+
const ALIASES = {
|
|
35
|
+
dev: 'developer',
|
|
36
|
+
qa: 'quality-gate',
|
|
37
|
+
pm: 'project-lead',
|
|
38
|
+
po: 'product-lead',
|
|
39
|
+
sm: 'sprint-lead',
|
|
40
|
+
ux: 'ux-design-expert',
|
|
41
|
+
'ux-expert': 'ux-design-expert',
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
class SquadAgentResolver {
|
|
45
|
+
/**
|
|
46
|
+
* @param {string} projectRoot - Project root directory
|
|
47
|
+
*/
|
|
48
|
+
constructor(projectRoot = process.cwd()) {
|
|
49
|
+
this.projectRoot = projectRoot;
|
|
50
|
+
this._index = null; // Map<normalizedKey, entry> — built lazily
|
|
51
|
+
this._personaCache = new Map(); // id -> persona content
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Normalize an agent reference for lookup: strip leading '@', lowercase,
|
|
56
|
+
* collapse separators. So '@penetration-tester', 'penetration_tester' and
|
|
57
|
+
* 'Penetration Tester' all resolve to the same key.
|
|
58
|
+
* @param {string} ref
|
|
59
|
+
* @returns {string}
|
|
60
|
+
*/
|
|
61
|
+
static normalizeKey(ref) {
|
|
62
|
+
return String(ref || '')
|
|
63
|
+
.replace(/^@/, '')
|
|
64
|
+
.trim()
|
|
65
|
+
.toLowerCase()
|
|
66
|
+
.replace(/[\s_]+/g, '-');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Build (once) the index of every agent definition on disk.
|
|
71
|
+
* @returns {Map<string, Object>} normalizedKey -> { id, name, squad, filePath }
|
|
72
|
+
*/
|
|
73
|
+
buildIndex() {
|
|
74
|
+
if (this._index) return this._index;
|
|
75
|
+
const index = new Map();
|
|
76
|
+
|
|
77
|
+
const addEntry = (filePath, squad) => {
|
|
78
|
+
const base = path.basename(filePath, '.md');
|
|
79
|
+
if (!base || base.toUpperCase() === 'README') return;
|
|
80
|
+
const key = SquadAgentResolver.normalizeKey(base);
|
|
81
|
+
// First writer wins for a given key, but squad agents take precedence over
|
|
82
|
+
// framework duplicates only if a squad entry isn't already registered.
|
|
83
|
+
if (!index.has(key)) {
|
|
84
|
+
index.set(key, { id: base, name: base, squad, filePath });
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
for (const rel of AGENT_DIRS) {
|
|
89
|
+
const dir = path.join(this.projectRoot, rel);
|
|
90
|
+
if (!fs.existsSync(dir)) continue;
|
|
91
|
+
|
|
92
|
+
if (rel === 'squads') {
|
|
93
|
+
// squads/<squad>/agents/*.md
|
|
94
|
+
let squadDirs = [];
|
|
95
|
+
try {
|
|
96
|
+
squadDirs = fs.readdirSync(dir, { withFileTypes: true });
|
|
97
|
+
} catch {
|
|
98
|
+
squadDirs = [];
|
|
99
|
+
}
|
|
100
|
+
for (const sd of squadDirs) {
|
|
101
|
+
if (!sd.isDirectory()) continue;
|
|
102
|
+
const agentsDir = path.join(dir, sd.name, 'agents');
|
|
103
|
+
if (!fs.existsSync(agentsDir)) continue;
|
|
104
|
+
for (const f of this._listMd(agentsDir)) {
|
|
105
|
+
addEntry(path.join(agentsDir, f), sd.name);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
} else {
|
|
109
|
+
// flat dir of *.md
|
|
110
|
+
for (const f of this._listMd(dir)) {
|
|
111
|
+
addEntry(path.join(dir, f), null);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
this._index = index;
|
|
117
|
+
return index;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* List .md files in a directory (non-recursive), tolerant of read errors.
|
|
122
|
+
* @param {string} dir
|
|
123
|
+
* @returns {string[]}
|
|
124
|
+
* @private
|
|
125
|
+
*/
|
|
126
|
+
_listMd(dir) {
|
|
127
|
+
try {
|
|
128
|
+
return fs.readdirSync(dir).filter((f) => f.toLowerCase().endsWith('.md'));
|
|
129
|
+
} catch {
|
|
130
|
+
return [];
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Resolve an agent reference to its index entry.
|
|
136
|
+
* @param {string} ref - e.g. '@penetration-tester', 'dev', 'cloud-security-engineer'
|
|
137
|
+
* @returns {Object|null} { id, name, squad, filePath } or null when unknown
|
|
138
|
+
*/
|
|
139
|
+
resolve(ref) {
|
|
140
|
+
const index = this.buildIndex();
|
|
141
|
+
const key = SquadAgentResolver.normalizeKey(ref);
|
|
142
|
+
return index.get(key) || index.get(ALIASES[key]) || null;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* True when the reference maps to a known agent definition on disk.
|
|
147
|
+
* @param {string} ref
|
|
148
|
+
* @returns {boolean}
|
|
149
|
+
*/
|
|
150
|
+
has(ref) {
|
|
151
|
+
return this.resolve(ref) !== null;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Load the full persona markdown for an agent reference.
|
|
156
|
+
* @param {string} ref
|
|
157
|
+
* @returns {string|null} persona content, or null when unknown/unreadable
|
|
158
|
+
*/
|
|
159
|
+
loadPersona(ref) {
|
|
160
|
+
const entry = this.resolve(ref);
|
|
161
|
+
if (!entry) return null;
|
|
162
|
+
if (this._personaCache.has(entry.id)) return this._personaCache.get(entry.id);
|
|
163
|
+
let content = null;
|
|
164
|
+
try {
|
|
165
|
+
content = fs.readFileSync(entry.filePath, 'utf8');
|
|
166
|
+
} catch {
|
|
167
|
+
content = null;
|
|
168
|
+
}
|
|
169
|
+
this._personaCache.set(entry.id, content);
|
|
170
|
+
return content;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* All known agent ids (sorted), for diagnostics / `sinapse` listing.
|
|
175
|
+
* @returns {string[]}
|
|
176
|
+
*/
|
|
177
|
+
listIds() {
|
|
178
|
+
return [...this.buildIndex().values()].map((e) => e.id).sort();
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Count of indexed agents.
|
|
183
|
+
* @returns {number}
|
|
184
|
+
*/
|
|
185
|
+
size() {
|
|
186
|
+
return this.buildIndex().size;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Normalized metadata for an agent, extracted from whatever structure the
|
|
191
|
+
* file uses (frontmatter, `# Agent: X`, `# X`, or an embedded ```yaml block).
|
|
192
|
+
* This is the uniform schema (SCHEMA-001 closure) without mutating the 199
|
|
193
|
+
* heterogeneous persona files — the canonical shape is DERIVED, not imposed.
|
|
194
|
+
*
|
|
195
|
+
* @param {string} ref
|
|
196
|
+
* @returns {{id, name, squad, type, hasStructuredYaml, file}|null}
|
|
197
|
+
*/
|
|
198
|
+
describe(ref) {
|
|
199
|
+
const entry = this.resolve(ref);
|
|
200
|
+
if (!entry) return null;
|
|
201
|
+
const content = this.loadPersona(entry.id) || '';
|
|
202
|
+
return {
|
|
203
|
+
id: entry.id,
|
|
204
|
+
name: SquadAgentResolver.extractName(content, entry.id),
|
|
205
|
+
squad: entry.squad || 'framework',
|
|
206
|
+
type: /-orqx$/.test(entry.id) ? 'orchestrator' : 'specialist',
|
|
207
|
+
hasStructuredYaml: /```ya?ml/.test(content) || /^\s*agent:\s*$/m.test(content),
|
|
208
|
+
file: entry.filePath,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Describe every indexed agent (sorted by id) — the uniform registry view.
|
|
214
|
+
* @returns {Array<Object>}
|
|
215
|
+
*/
|
|
216
|
+
list() {
|
|
217
|
+
return this.listIds().map((id) => this.describe(id));
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Best-effort display name from heterogeneous structures. Falls back to a
|
|
222
|
+
* title-cased id so the result is never empty.
|
|
223
|
+
* @param {string} content - File content
|
|
224
|
+
* @param {string} id - Canonical id (filename)
|
|
225
|
+
* @returns {string}
|
|
226
|
+
*/
|
|
227
|
+
static extractName(content, id) {
|
|
228
|
+
const src = String(content || '');
|
|
229
|
+
// 1. YAML frontmatter `name:`
|
|
230
|
+
const fm = src.match(/^---\s*\n([\s\S]*?)\n---/);
|
|
231
|
+
if (fm) {
|
|
232
|
+
const m = fm[1].match(/^\s*name:\s*["']?([^"'\n]+)["']?\s*$/m);
|
|
233
|
+
if (m && m[1].trim()) return m[1].trim();
|
|
234
|
+
}
|
|
235
|
+
// 2. Embedded yaml `name:` (inside an ```yaml block or agent: section)
|
|
236
|
+
const ym = src.match(/^\s*name:\s*["']?([^"'\n]+)["']?\s*$/m);
|
|
237
|
+
if (ym && ym[1].trim()) return ym[1].trim();
|
|
238
|
+
// 3. `# Agent: Name`
|
|
239
|
+
const ah = src.match(/^#\s*Agent:\s*(.+?)\s*$/m);
|
|
240
|
+
if (ah && ah[1].trim()) return ah[1].trim();
|
|
241
|
+
// 4. First `# Heading`
|
|
242
|
+
const h1 = src.match(/^#\s+(.+?)\s*$/m);
|
|
243
|
+
if (h1 && h1[1].trim()) return h1[1].trim().replace(/^@/, '');
|
|
244
|
+
// 5. Title-cased id
|
|
245
|
+
return String(id)
|
|
246
|
+
.split('-')
|
|
247
|
+
.map((w) => (w ? w[0].toUpperCase() + w.slice(1) : w))
|
|
248
|
+
.join(' ');
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
module.exports = SquadAgentResolver;
|
|
253
|
+
module.exports.SquadAgentResolver = SquadAgentResolver;
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* IDS Telemetry Sink — SINAPSE Framework
|
|
5
|
+
* @story Frente 4.3 — Telemetria OTel + DORA + Gate Decisions JSONL (Stream B)
|
|
6
|
+
*
|
|
7
|
+
* A LOCAL-only, always-on sink for IDS gate decision events.
|
|
8
|
+
* This is NOT the opt-in user telemetry stub (telemetry/index.js).
|
|
9
|
+
* This sink records framework-internal operational data only — no PII,
|
|
10
|
+
* no user paths, no prompt content.
|
|
11
|
+
*
|
|
12
|
+
* Design principles:
|
|
13
|
+
* - FAIL-OPEN TOTAL: any error is swallowed silently. Never throws. Never blocks.
|
|
14
|
+
* - Zero external deps: pure Node stdlib (fs, path, os).
|
|
15
|
+
* - OTel GenAI semantic conventions for field names.
|
|
16
|
+
* - Separate from opt-in telemetry; isEnabled() is NOT consulted.
|
|
17
|
+
*
|
|
18
|
+
* Output file: <projectRoot>/.sinapse/telemetry/gate-decisions.jsonl
|
|
19
|
+
* (gitignored by default — .sinapse/ is in .gitignore)
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
const fs = require('fs');
|
|
23
|
+
const path = require('path');
|
|
24
|
+
|
|
25
|
+
// ─── Constants (OTel GenAI semantic conventions) ─────────────────────────────
|
|
26
|
+
|
|
27
|
+
const OPERATION_GATE_EVALUATE = 'ids.gate.evaluate';
|
|
28
|
+
const OPERATION_SESSION_END = 'session.end';
|
|
29
|
+
const MODEL_IDS = 'sinapse-ids';
|
|
30
|
+
|
|
31
|
+
// ─── Sink path resolution ─────────────────────────────────────────────────────
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Resolve the absolute path to the JSONL sink file.
|
|
35
|
+
* Uses process.cwd() as project root — same convention as DashboardEmitter.
|
|
36
|
+
* Caller may override via SINAPSE_TELEMETRY_SINK env var (useful in tests).
|
|
37
|
+
*
|
|
38
|
+
* @returns {string}
|
|
39
|
+
*/
|
|
40
|
+
function resolveSinkPath() {
|
|
41
|
+
if (process.env.SINAPSE_TELEMETRY_SINK) {
|
|
42
|
+
return process.env.SINAPSE_TELEMETRY_SINK;
|
|
43
|
+
}
|
|
44
|
+
return path.join(process.cwd(), '.sinapse', 'telemetry', 'gate-decisions.jsonl');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Ensure the directory for the sink exists. Fail-open.
|
|
49
|
+
* @param {string} sinkPath
|
|
50
|
+
*/
|
|
51
|
+
function ensureSinkDir(sinkPath) {
|
|
52
|
+
try {
|
|
53
|
+
fs.mkdirSync(path.dirname(sinkPath), { recursive: true });
|
|
54
|
+
} catch {
|
|
55
|
+
// fail-open: if we can't create the dir, the appendFileSync below will
|
|
56
|
+
// also fail and be swallowed by the outer try/catch.
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Append a single JSON line to the sink. Fail-open.
|
|
62
|
+
* @param {object} record — must be JSON-serialisable.
|
|
63
|
+
*/
|
|
64
|
+
function appendLine(record) {
|
|
65
|
+
try {
|
|
66
|
+
const sinkPath = resolveSinkPath();
|
|
67
|
+
ensureSinkDir(sinkPath);
|
|
68
|
+
fs.appendFileSync(sinkPath, JSON.stringify(record) + '\n', 'utf8');
|
|
69
|
+
} catch {
|
|
70
|
+
/* fail-open: telemetry MUST NEVER block the caller */
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// ─── Session ID resolution ────────────────────────────────────────────────────
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Resolve the current session id from environment variables injected by
|
|
78
|
+
* Claude Code. Falls back to 'unknown' when not available.
|
|
79
|
+
* @returns {string}
|
|
80
|
+
*/
|
|
81
|
+
function resolveSessionId() {
|
|
82
|
+
return (
|
|
83
|
+
process.env.CLAUDE_SESSION_ID ||
|
|
84
|
+
process.env.CLAUDE_CODE_SESSION_ID ||
|
|
85
|
+
process.env.SINAPSE_SESSION_ID ||
|
|
86
|
+
'unknown'
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// ─── Public API ───────────────────────────────────────────────────────────────
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Emit a gate-decision event as a JSONL line using OTel GenAI field names.
|
|
94
|
+
*
|
|
95
|
+
* Fields emitted (NO PII):
|
|
96
|
+
* - timestamp ISO-8601
|
|
97
|
+
* - gen_ai.operation.name "ids.gate.evaluate"
|
|
98
|
+
* - gen_ai.request.model "sinapse-ids"
|
|
99
|
+
* - gen_ai.usage.input_tokens always 0 (no LLM call)
|
|
100
|
+
* - gen_ai.usage.output_tokens always 0 (no LLM call)
|
|
101
|
+
* - tool gateId (e.g. "G1")
|
|
102
|
+
* - sessionId from CLAUDE_SESSION_ID env or "unknown"
|
|
103
|
+
* - phase phaseId (e.g. "epic_creation")
|
|
104
|
+
* - blocked boolean
|
|
105
|
+
* - warnings string[] (gate warning messages)
|
|
106
|
+
*
|
|
107
|
+
* FAIL-OPEN: any error inside this function is swallowed. Returns void.
|
|
108
|
+
*
|
|
109
|
+
* @param {{
|
|
110
|
+
* tool: string,
|
|
111
|
+
* phase: string,
|
|
112
|
+
* blocked: boolean,
|
|
113
|
+
* warnings?: string[],
|
|
114
|
+
* sessionId?: string,
|
|
115
|
+
* }} record
|
|
116
|
+
*/
|
|
117
|
+
function emitGateDecision(record) {
|
|
118
|
+
try {
|
|
119
|
+
appendLine({
|
|
120
|
+
timestamp: new Date().toISOString(),
|
|
121
|
+
'gen_ai.operation.name': OPERATION_GATE_EVALUATE,
|
|
122
|
+
'gen_ai.request.model': MODEL_IDS,
|
|
123
|
+
'gen_ai.usage.input_tokens': 0,
|
|
124
|
+
'gen_ai.usage.output_tokens': 0,
|
|
125
|
+
tool: String(record.tool || 'unknown'),
|
|
126
|
+
sessionId: record.sessionId || resolveSessionId(),
|
|
127
|
+
phase: String(record.phase || 'unknown'),
|
|
128
|
+
blocked: record.blocked === true,
|
|
129
|
+
warnings: Array.isArray(record.warnings) ? record.warnings : [],
|
|
130
|
+
});
|
|
131
|
+
} catch {
|
|
132
|
+
/* fail-open */
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Emit a session-end event with DORA base counters.
|
|
138
|
+
*
|
|
139
|
+
* Fields emitted:
|
|
140
|
+
* - timestamp
|
|
141
|
+
* - gen_ai.operation.name "session.end"
|
|
142
|
+
* - gen_ai.request.model "sinapse-ids"
|
|
143
|
+
* - gen_ai.usage.input_tokens 0
|
|
144
|
+
* - gen_ai.usage.output_tokens 0
|
|
145
|
+
* - sessionId
|
|
146
|
+
* - dora.toolExecutions total tool calls in the session
|
|
147
|
+
* - dora.filesModified Write + Edit tool calls count
|
|
148
|
+
* - dora.sessionDurationMs session wall-clock duration in ms
|
|
149
|
+
*
|
|
150
|
+
* FAIL-OPEN. Returns void.
|
|
151
|
+
*
|
|
152
|
+
* @param {{
|
|
153
|
+
* sessionId: string,
|
|
154
|
+
* toolExecutions: number,
|
|
155
|
+
* filesModified: number,
|
|
156
|
+
* sessionDurationMs: number,
|
|
157
|
+
* }} record
|
|
158
|
+
*/
|
|
159
|
+
function emitSessionEnd(record) {
|
|
160
|
+
try {
|
|
161
|
+
appendLine({
|
|
162
|
+
timestamp: new Date().toISOString(),
|
|
163
|
+
'gen_ai.operation.name': OPERATION_SESSION_END,
|
|
164
|
+
'gen_ai.request.model': MODEL_IDS,
|
|
165
|
+
'gen_ai.usage.input_tokens': 0,
|
|
166
|
+
'gen_ai.usage.output_tokens': 0,
|
|
167
|
+
sessionId: String(record.sessionId || 'unknown'),
|
|
168
|
+
'dora.toolExecutions': Number(record.toolExecutions) || 0,
|
|
169
|
+
'dora.filesModified': Number(record.filesModified) || 0,
|
|
170
|
+
'dora.sessionDurationMs': Number(record.sessionDurationMs) || 0,
|
|
171
|
+
});
|
|
172
|
+
} catch {
|
|
173
|
+
/* fail-open */
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// ─── Exported (test-accessible) internals ────────────────────────────────────
|
|
178
|
+
|
|
179
|
+
module.exports = {
|
|
180
|
+
emitGateDecision,
|
|
181
|
+
emitSessionEnd,
|
|
182
|
+
// Exposed for tests only — NOT part of the public contract.
|
|
183
|
+
_resolveSinkPath: resolveSinkPath,
|
|
184
|
+
_resolveSessionId: resolveSessionId,
|
|
185
|
+
OPERATION_GATE_EVALUATE,
|
|
186
|
+
OPERATION_SESSION_END,
|
|
187
|
+
MODEL_IDS,
|
|
188
|
+
};
|