@josstei/maestro 1.6.4-rc.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/.agents/plugins/marketplace.json +20 -0
- package/CHANGELOG.md +485 -0
- package/EXAMPLES.md +255 -0
- package/GEMINI.md +231 -0
- package/LICENSE +201 -0
- package/QWEN.md +241 -0
- package/README.md +220 -0
- package/agents/accessibility_specialist.md +20 -0
- package/agents/analytics_engineer.md +22 -0
- package/agents/api_designer.md +19 -0
- package/agents/architect.md +19 -0
- package/agents/cloud_architect.md +19 -0
- package/agents/cobol_engineer.md +22 -0
- package/agents/code_reviewer.md +17 -0
- package/agents/coder.md +22 -0
- package/agents/compliance_reviewer.md +19 -0
- package/agents/content_strategist.md +19 -0
- package/agents/copywriter.md +19 -0
- package/agents/data_engineer.md +22 -0
- package/agents/database_administrator.md +21 -0
- package/agents/db2_dba.md +21 -0
- package/agents/debugger.md +19 -0
- package/agents/design_system_engineer.md +22 -0
- package/agents/devops_engineer.md +23 -0
- package/agents/hlasm_assembler_specialist.md +22 -0
- package/agents/i18n_specialist.md +21 -0
- package/agents/ibm_i_specialist.md +22 -0
- package/agents/integration_engineer.md +23 -0
- package/agents/ml_engineer.md +23 -0
- package/agents/mlops_engineer.md +23 -0
- package/agents/mobile_engineer.md +23 -0
- package/agents/observability_engineer.md +23 -0
- package/agents/performance_engineer.md +21 -0
- package/agents/platform_engineer.md +24 -0
- package/agents/product_manager.md +20 -0
- package/agents/prompt_engineer.md +22 -0
- package/agents/refactor.md +22 -0
- package/agents/release_manager.md +22 -0
- package/agents/security_engineer.md +21 -0
- package/agents/seo_specialist.md +21 -0
- package/agents/site_reliability_engineer.md +21 -0
- package/agents/solutions_architect.md +19 -0
- package/agents/technical_writer.md +21 -0
- package/agents/tester.md +23 -0
- package/agents/ux_designer.md +20 -0
- package/agents/zos_sysprog.md +21 -0
- package/bin/maestro-mcp-server.js +10 -0
- package/claude/.claude-plugin/plugin.json +21 -0
- package/claude/.mcp.json +11 -0
- package/claude/README.md +191 -0
- package/claude/agents/accessibility-specialist.md +36 -0
- package/claude/agents/analytics-engineer.md +38 -0
- package/claude/agents/api-designer.md +33 -0
- package/claude/agents/architect.md +33 -0
- package/claude/agents/cloud-architect.md +33 -0
- package/claude/agents/cobol-engineer.md +38 -0
- package/claude/agents/code-reviewer.md +31 -0
- package/claude/agents/coder.md +38 -0
- package/claude/agents/compliance-reviewer.md +33 -0
- package/claude/agents/content-strategist.md +33 -0
- package/claude/agents/copywriter.md +33 -0
- package/claude/agents/data-engineer.md +37 -0
- package/claude/agents/database-administrator.md +37 -0
- package/claude/agents/db2-dba.md +37 -0
- package/claude/agents/debugger.md +32 -0
- package/claude/agents/design-system-engineer.md +38 -0
- package/claude/agents/devops-engineer.md +39 -0
- package/claude/agents/hlasm-assembler-specialist.md +38 -0
- package/claude/agents/i18n-specialist.md +37 -0
- package/claude/agents/ibm-i-specialist.md +38 -0
- package/claude/agents/integration-engineer.md +39 -0
- package/claude/agents/ml-engineer.md +39 -0
- package/claude/agents/mlops-engineer.md +39 -0
- package/claude/agents/mobile-engineer.md +39 -0
- package/claude/agents/observability-engineer.md +39 -0
- package/claude/agents/performance-engineer.md +34 -0
- package/claude/agents/platform-engineer.md +40 -0
- package/claude/agents/product-manager.md +34 -0
- package/claude/agents/prompt-engineer.md +38 -0
- package/claude/agents/refactor.md +38 -0
- package/claude/agents/release-manager.md +38 -0
- package/claude/agents/security-engineer.md +37 -0
- package/claude/agents/seo-specialist.md +37 -0
- package/claude/agents/site-reliability-engineer.md +37 -0
- package/claude/agents/solutions-architect.md +33 -0
- package/claude/agents/technical-writer.md +37 -0
- package/claude/agents/tester.md +39 -0
- package/claude/agents/ux-designer.md +34 -0
- package/claude/agents/zos-sysprog.md +37 -0
- package/claude/hooks/claude-hooks.json +48 -0
- package/claude/mcp/maestro-server.js +9 -0
- package/claude/mcp-config.example.json +9 -0
- package/claude/scripts/adapters/claude-adapter.js +7 -0
- package/claude/scripts/hook-runner.js +8 -0
- package/claude/scripts/policy-enforcer.js +294 -0
- package/claude/skills/a11y-audit/SKILL.md +26 -0
- package/claude/skills/archive/SKILL.md +24 -0
- package/claude/skills/code-review/SKILL.md +7 -0
- package/claude/skills/compliance-check/SKILL.md +26 -0
- package/claude/skills/debug-workflow/SKILL.md +27 -0
- package/claude/skills/delegation/SKILL.md +7 -0
- package/claude/skills/design-dialogue/SKILL.md +7 -0
- package/claude/skills/execute/SKILL.md +38 -0
- package/claude/skills/execution/SKILL.md +7 -0
- package/claude/skills/implementation-planning/SKILL.md +7 -0
- package/claude/skills/orchestrate/SKILL.md +38 -0
- package/claude/skills/perf-check/SKILL.md +26 -0
- package/claude/skills/resume-session/SKILL.md +38 -0
- package/claude/skills/review-code/SKILL.md +27 -0
- package/claude/skills/security-audit/SKILL.md +28 -0
- package/claude/skills/seo-audit/SKILL.md +26 -0
- package/claude/skills/session-management/SKILL.md +7 -0
- package/claude/skills/status/SKILL.md +22 -0
- package/claude/skills/validation/SKILL.md +7 -0
- package/claude/src/agents/accessibility-specialist.md +163 -0
- package/claude/src/agents/analytics-engineer.md +182 -0
- package/claude/src/agents/api-designer.md +124 -0
- package/claude/src/agents/architect.md +120 -0
- package/claude/src/agents/cloud-architect.md +134 -0
- package/claude/src/agents/cobol-engineer.md +127 -0
- package/claude/src/agents/code-reviewer.md +123 -0
- package/claude/src/agents/coder.md +132 -0
- package/claude/src/agents/compliance-reviewer.md +219 -0
- package/claude/src/agents/content-strategist.md +111 -0
- package/claude/src/agents/copywriter.md +113 -0
- package/claude/src/agents/data-engineer.md +130 -0
- package/claude/src/agents/database-administrator.md +126 -0
- package/claude/src/agents/db2-dba.md +124 -0
- package/claude/src/agents/debugger.md +133 -0
- package/claude/src/agents/design-system-engineer.md +258 -0
- package/claude/src/agents/devops-engineer.md +138 -0
- package/claude/src/agents/hlasm-assembler-specialist.md +134 -0
- package/claude/src/agents/i18n-specialist.md +241 -0
- package/claude/src/agents/ibm-i-specialist.md +132 -0
- package/claude/src/agents/integration-engineer.md +133 -0
- package/claude/src/agents/ml-engineer.md +115 -0
- package/claude/src/agents/mlops-engineer.md +116 -0
- package/claude/src/agents/mobile-engineer.md +115 -0
- package/claude/src/agents/observability-engineer.md +133 -0
- package/claude/src/agents/performance-engineer.md +139 -0
- package/claude/src/agents/platform-engineer.md +129 -0
- package/claude/src/agents/product-manager.md +170 -0
- package/claude/src/agents/prompt-engineer.md +129 -0
- package/claude/src/agents/refactor.md +138 -0
- package/claude/src/agents/release-manager.md +132 -0
- package/claude/src/agents/security-engineer.md +143 -0
- package/claude/src/agents/seo-specialist.md +129 -0
- package/claude/src/agents/site-reliability-engineer.md +131 -0
- package/claude/src/agents/solutions-architect.md +137 -0
- package/claude/src/agents/technical-writer.md +129 -0
- package/claude/src/agents/tester.md +135 -0
- package/claude/src/agents/ux-designer.md +168 -0
- package/claude/src/agents/zos-sysprog.md +134 -0
- package/claude/src/config/setting-resolver.js +32 -0
- package/claude/src/core/agent-registry.js +67 -0
- package/claude/src/core/canonical-source.js +39 -0
- package/claude/src/core/env-file-parser.js +82 -0
- package/claude/src/core/feature-blocks.js +34 -0
- package/claude/src/core/logger.js +12 -0
- package/claude/src/core/markdown-state.js +36 -0
- package/claude/src/core/policy-rules.js +32 -0
- package/claude/src/core/project-root-resolver.js +184 -0
- package/claude/src/core/stdin-reader.js +77 -0
- package/claude/src/core/version.js +50 -0
- package/claude/src/entry-points/core-command-registry.js +37 -0
- package/claude/src/entry-points/preamble-builders.js +54 -0
- package/claude/src/entry-points/registry.js +199 -0
- package/claude/src/entry-points/templates/claude-core-command.md.tmpl +38 -0
- package/claude/src/entry-points/templates/claude-skill.md.tmpl +18 -0
- package/claude/src/entry-points/templates/codex-core-command.md.tmpl +16 -0
- package/claude/src/entry-points/templates/codex-skill.md.tmpl +11 -0
- package/claude/src/entry-points/templates/gemini-command.toml.tmpl +17 -0
- package/claude/src/entry-points/templates/gemini-core-command.toml.tmpl +30 -0
- package/claude/src/generated/agent-registry.json +630 -0
- package/claude/src/generated/hook-registry.json +18 -0
- package/claude/src/generated/resource-registry.json +16 -0
- package/claude/src/hooks/logic/after-agent-logic.js +54 -0
- package/claude/src/hooks/logic/before-agent-logic.js +57 -0
- package/claude/src/hooks/logic/hook-state.js +127 -0
- package/claude/src/hooks/logic/session-end-logic.js +17 -0
- package/claude/src/hooks/logic/session-start-logic.js +25 -0
- package/claude/src/lib/discovery/index.js +172 -0
- package/claude/src/lib/errors/index.js +104 -0
- package/claude/src/lib/framework-detection.js +50 -0
- package/claude/src/lib/frontmatter/index.js +262 -0
- package/claude/src/lib/io/index.js +96 -0
- package/claude/src/lib/naming/index.js +94 -0
- package/claude/src/lib/validation/index.js +124 -0
- package/claude/src/lib/yaml-emit.js +38 -0
- package/claude/src/mcp/content/provider.js +68 -0
- package/claude/src/mcp/content/runtime-content.js +188 -0
- package/claude/src/mcp/contracts/cache-path-rejector.js +39 -0
- package/claude/src/mcp/contracts/downstream-context.js +106 -0
- package/claude/src/mcp/contracts/plan-schema.js +148 -0
- package/claude/src/mcp/contracts/workspace-marker.js +61 -0
- package/claude/src/mcp/core/create-server.js +76 -0
- package/claude/src/mcp/core/line-reader.js +35 -0
- package/claude/src/mcp/core/project-root-cache.js +120 -0
- package/claude/src/mcp/core/protocol-dispatcher.js +274 -0
- package/claude/src/mcp/core/recovery-hints.js +43 -0
- package/claude/src/mcp/core/tool-outcome.js +77 -0
- package/claude/src/mcp/core/tool-registry.js +82 -0
- package/claude/src/mcp/handlers/assess-task-complexity.js +108 -0
- package/claude/src/mcp/handlers/blocker-parser.js +34 -0
- package/claude/src/mcp/handlers/design-gate.js +393 -0
- package/claude/src/mcp/handlers/get-agent.js +54 -0
- package/claude/src/mcp/handlers/get-runtime-context.js +49 -0
- package/claude/src/mcp/handlers/get-skill-content.js +51 -0
- package/claude/src/mcp/handlers/initialize-workspace.js +45 -0
- package/claude/src/mcp/handlers/reconciliation.js +224 -0
- package/claude/src/mcp/handlers/resolve-settings.js +39 -0
- package/claude/src/mcp/handlers/session-state-core.js +108 -0
- package/claude/src/mcp/handlers/session-state-tools.js +562 -0
- package/claude/src/mcp/handlers/validate-plan.js +76 -0
- package/claude/src/mcp/maestro-server.js +122 -0
- package/claude/src/mcp/runtime/runtime-config-map.js +70 -0
- package/claude/src/mcp/tool-packs/content/index.js +80 -0
- package/claude/src/mcp/tool-packs/contracts.js +30 -0
- package/claude/src/mcp/tool-packs/index.js +15 -0
- package/claude/src/mcp/tool-packs/session/index.js +243 -0
- package/claude/src/mcp/tool-packs/workspace/index.js +98 -0
- package/claude/src/mcp/utils/extension-root.js +31 -0
- package/claude/src/mcp/validation/agent-checker.js +81 -0
- package/claude/src/mcp/validation/dag-checker.js +214 -0
- package/claude/src/mcp/validation/file-overlap-checker.js +63 -0
- package/claude/src/mcp/validation/schema-checker.js +108 -0
- package/claude/src/platforms/claude/runtime-config.js +60 -0
- package/claude/src/platforms/shared/adapters/claude-adapter.js +36 -0
- package/claude/src/platforms/shared/adapters/conventions.js +29 -0
- package/claude/src/platforms/shared/adapters/exit-codes.js +6 -0
- package/claude/src/platforms/shared/adapters/factory.js +40 -0
- package/claude/src/platforms/shared/agent-names.js +10 -0
- package/claude/src/platforms/shared/hook-runner.js +52 -0
- package/claude/src/references/architecture.md +139 -0
- package/claude/src/references/orchestration-steps.md +193 -0
- package/claude/src/skills/shared/code-review/SKILL.md +145 -0
- package/claude/src/skills/shared/delegation/SKILL.md +370 -0
- package/claude/src/skills/shared/delegation/protocols/agent-base-protocol.md +145 -0
- package/claude/src/skills/shared/delegation/protocols/filesystem-safety-protocol.md +31 -0
- package/claude/src/skills/shared/design-dialogue/SKILL.md +284 -0
- package/claude/src/skills/shared/execution/SKILL.md +258 -0
- package/claude/src/skills/shared/implementation-planning/SKILL.md +303 -0
- package/claude/src/skills/shared/session-management/SKILL.md +314 -0
- package/claude/src/skills/shared/validation/SKILL.md +204 -0
- package/claude/src/state/session-state.js +113 -0
- package/claude/src/templates/design-document.md +95 -0
- package/claude/src/templates/implementation-plan.md +86 -0
- package/claude/src/templates/session-state.md +68 -0
- package/claude/src/version.json +3 -0
- package/commands/maestro/a11y-audit.toml +22 -0
- package/commands/maestro/archive.toml +23 -0
- package/commands/maestro/compliance-check.toml +22 -0
- package/commands/maestro/debug.toml +23 -0
- package/commands/maestro/execute.toml +30 -0
- package/commands/maestro/orchestrate.toml +30 -0
- package/commands/maestro/perf-check.toml +22 -0
- package/commands/maestro/resume.toml +38 -0
- package/commands/maestro/review.toml +23 -0
- package/commands/maestro/security-audit.toml +24 -0
- package/commands/maestro/seo-audit.toml +22 -0
- package/commands/maestro/status.toml +21 -0
- package/docs/architecture.md +310 -0
- package/docs/cicd.md +647 -0
- package/docs/flow.md +255 -0
- package/docs/maestro-cheatsheet.md +199 -0
- package/docs/overview.md +141 -0
- package/docs/runtime-claude.md +190 -0
- package/docs/runtime-codex.md +197 -0
- package/docs/runtime-gemini.md +170 -0
- package/docs/runtime-qwen.md +147 -0
- package/docs/usage.md +312 -0
- package/gemini-extension.json +55 -0
- package/hooks/adapters/gemini-adapter.js +2 -0
- package/hooks/adapters/qwen-adapter.js +2 -0
- package/hooks/hook-runner.js +3 -0
- package/hooks/hooks.json +56 -0
- package/mcp/maestro-server.js +4 -0
- package/package.json +93 -0
- package/plugins/maestro/.app.json +3 -0
- package/plugins/maestro/.codex-plugin/plugin.json +41 -0
- package/plugins/maestro/.mcp.json +16 -0
- package/plugins/maestro/README.md +57 -0
- package/plugins/maestro/references/runtime-guide.md +125 -0
- package/plugins/maestro/skills/a11y-audit/SKILL.md +16 -0
- package/plugins/maestro/skills/archive/SKILL.md +16 -0
- package/plugins/maestro/skills/code-review/SKILL.md +6 -0
- package/plugins/maestro/skills/compliance-check/SKILL.md +16 -0
- package/plugins/maestro/skills/debug-workflow/SKILL.md +16 -0
- package/plugins/maestro/skills/delegation/SKILL.md +6 -0
- package/plugins/maestro/skills/design-dialogue/SKILL.md +6 -0
- package/plugins/maestro/skills/execute/SKILL.md +16 -0
- package/plugins/maestro/skills/execution/SKILL.md +6 -0
- package/plugins/maestro/skills/implementation-planning/SKILL.md +6 -0
- package/plugins/maestro/skills/orchestrate/SKILL.md +16 -0
- package/plugins/maestro/skills/perf-check/SKILL.md +16 -0
- package/plugins/maestro/skills/resume-session/SKILL.md +16 -0
- package/plugins/maestro/skills/review-code/SKILL.md +16 -0
- package/plugins/maestro/skills/security-audit/SKILL.md +16 -0
- package/plugins/maestro/skills/seo-audit/SKILL.md +16 -0
- package/plugins/maestro/skills/session-management/SKILL.md +6 -0
- package/plugins/maestro/skills/status/SKILL.md +14 -0
- package/plugins/maestro/skills/validation/SKILL.md +6 -0
- package/plugins/maestro/src/agents/accessibility-specialist.md +163 -0
- package/plugins/maestro/src/agents/analytics-engineer.md +182 -0
- package/plugins/maestro/src/agents/api-designer.md +124 -0
- package/plugins/maestro/src/agents/architect.md +120 -0
- package/plugins/maestro/src/agents/cloud-architect.md +134 -0
- package/plugins/maestro/src/agents/cobol-engineer.md +127 -0
- package/plugins/maestro/src/agents/code-reviewer.md +123 -0
- package/plugins/maestro/src/agents/coder.md +132 -0
- package/plugins/maestro/src/agents/compliance-reviewer.md +219 -0
- package/plugins/maestro/src/agents/content-strategist.md +111 -0
- package/plugins/maestro/src/agents/copywriter.md +113 -0
- package/plugins/maestro/src/agents/data-engineer.md +130 -0
- package/plugins/maestro/src/agents/database-administrator.md +126 -0
- package/plugins/maestro/src/agents/db2-dba.md +124 -0
- package/plugins/maestro/src/agents/debugger.md +133 -0
- package/plugins/maestro/src/agents/design-system-engineer.md +258 -0
- package/plugins/maestro/src/agents/devops-engineer.md +138 -0
- package/plugins/maestro/src/agents/hlasm-assembler-specialist.md +134 -0
- package/plugins/maestro/src/agents/i18n-specialist.md +241 -0
- package/plugins/maestro/src/agents/ibm-i-specialist.md +132 -0
- package/plugins/maestro/src/agents/integration-engineer.md +133 -0
- package/plugins/maestro/src/agents/ml-engineer.md +115 -0
- package/plugins/maestro/src/agents/mlops-engineer.md +116 -0
- package/plugins/maestro/src/agents/mobile-engineer.md +115 -0
- package/plugins/maestro/src/agents/observability-engineer.md +133 -0
- package/plugins/maestro/src/agents/performance-engineer.md +139 -0
- package/plugins/maestro/src/agents/platform-engineer.md +129 -0
- package/plugins/maestro/src/agents/product-manager.md +170 -0
- package/plugins/maestro/src/agents/prompt-engineer.md +129 -0
- package/plugins/maestro/src/agents/refactor.md +138 -0
- package/plugins/maestro/src/agents/release-manager.md +132 -0
- package/plugins/maestro/src/agents/security-engineer.md +143 -0
- package/plugins/maestro/src/agents/seo-specialist.md +129 -0
- package/plugins/maestro/src/agents/site-reliability-engineer.md +131 -0
- package/plugins/maestro/src/agents/solutions-architect.md +137 -0
- package/plugins/maestro/src/agents/technical-writer.md +129 -0
- package/plugins/maestro/src/agents/tester.md +135 -0
- package/plugins/maestro/src/agents/ux-designer.md +168 -0
- package/plugins/maestro/src/agents/zos-sysprog.md +134 -0
- package/plugins/maestro/src/config/setting-resolver.js +32 -0
- package/plugins/maestro/src/core/agent-registry.js +67 -0
- package/plugins/maestro/src/core/canonical-source.js +39 -0
- package/plugins/maestro/src/core/env-file-parser.js +82 -0
- package/plugins/maestro/src/core/feature-blocks.js +34 -0
- package/plugins/maestro/src/core/logger.js +12 -0
- package/plugins/maestro/src/core/markdown-state.js +36 -0
- package/plugins/maestro/src/core/policy-rules.js +32 -0
- package/plugins/maestro/src/core/project-root-resolver.js +184 -0
- package/plugins/maestro/src/core/stdin-reader.js +77 -0
- package/plugins/maestro/src/core/version.js +50 -0
- package/plugins/maestro/src/entry-points/core-command-registry.js +37 -0
- package/plugins/maestro/src/entry-points/preamble-builders.js +54 -0
- package/plugins/maestro/src/entry-points/registry.js +199 -0
- package/plugins/maestro/src/entry-points/templates/claude-core-command.md.tmpl +38 -0
- package/plugins/maestro/src/entry-points/templates/claude-skill.md.tmpl +18 -0
- package/plugins/maestro/src/entry-points/templates/codex-core-command.md.tmpl +16 -0
- package/plugins/maestro/src/entry-points/templates/codex-skill.md.tmpl +11 -0
- package/plugins/maestro/src/entry-points/templates/gemini-command.toml.tmpl +17 -0
- package/plugins/maestro/src/entry-points/templates/gemini-core-command.toml.tmpl +30 -0
- package/plugins/maestro/src/generated/agent-registry.json +630 -0
- package/plugins/maestro/src/generated/hook-registry.json +18 -0
- package/plugins/maestro/src/generated/resource-registry.json +16 -0
- package/plugins/maestro/src/hooks/logic/after-agent-logic.js +54 -0
- package/plugins/maestro/src/hooks/logic/before-agent-logic.js +57 -0
- package/plugins/maestro/src/hooks/logic/hook-state.js +127 -0
- package/plugins/maestro/src/hooks/logic/session-end-logic.js +17 -0
- package/plugins/maestro/src/hooks/logic/session-start-logic.js +25 -0
- package/plugins/maestro/src/lib/discovery/index.js +172 -0
- package/plugins/maestro/src/lib/errors/index.js +104 -0
- package/plugins/maestro/src/lib/framework-detection.js +50 -0
- package/plugins/maestro/src/lib/frontmatter/index.js +262 -0
- package/plugins/maestro/src/lib/io/index.js +96 -0
- package/plugins/maestro/src/lib/naming/index.js +94 -0
- package/plugins/maestro/src/lib/validation/index.js +124 -0
- package/plugins/maestro/src/lib/yaml-emit.js +38 -0
- package/plugins/maestro/src/mcp/content/provider.js +68 -0
- package/plugins/maestro/src/mcp/content/runtime-content.js +188 -0
- package/plugins/maestro/src/mcp/contracts/cache-path-rejector.js +39 -0
- package/plugins/maestro/src/mcp/contracts/downstream-context.js +106 -0
- package/plugins/maestro/src/mcp/contracts/plan-schema.js +148 -0
- package/plugins/maestro/src/mcp/contracts/workspace-marker.js +61 -0
- package/plugins/maestro/src/mcp/core/create-server.js +76 -0
- package/plugins/maestro/src/mcp/core/line-reader.js +35 -0
- package/plugins/maestro/src/mcp/core/project-root-cache.js +120 -0
- package/plugins/maestro/src/mcp/core/protocol-dispatcher.js +274 -0
- package/plugins/maestro/src/mcp/core/recovery-hints.js +43 -0
- package/plugins/maestro/src/mcp/core/tool-outcome.js +77 -0
- package/plugins/maestro/src/mcp/core/tool-registry.js +82 -0
- package/plugins/maestro/src/mcp/handlers/assess-task-complexity.js +108 -0
- package/plugins/maestro/src/mcp/handlers/blocker-parser.js +34 -0
- package/plugins/maestro/src/mcp/handlers/design-gate.js +393 -0
- package/plugins/maestro/src/mcp/handlers/get-agent.js +54 -0
- package/plugins/maestro/src/mcp/handlers/get-runtime-context.js +49 -0
- package/plugins/maestro/src/mcp/handlers/get-skill-content.js +51 -0
- package/plugins/maestro/src/mcp/handlers/initialize-workspace.js +45 -0
- package/plugins/maestro/src/mcp/handlers/reconciliation.js +224 -0
- package/plugins/maestro/src/mcp/handlers/resolve-settings.js +39 -0
- package/plugins/maestro/src/mcp/handlers/session-state-core.js +108 -0
- package/plugins/maestro/src/mcp/handlers/session-state-tools.js +562 -0
- package/plugins/maestro/src/mcp/handlers/validate-plan.js +76 -0
- package/plugins/maestro/src/mcp/maestro-server.js +122 -0
- package/plugins/maestro/src/mcp/runtime/runtime-config-map.js +70 -0
- package/plugins/maestro/src/mcp/tool-packs/content/index.js +80 -0
- package/plugins/maestro/src/mcp/tool-packs/contracts.js +30 -0
- package/plugins/maestro/src/mcp/tool-packs/index.js +15 -0
- package/plugins/maestro/src/mcp/tool-packs/session/index.js +243 -0
- package/plugins/maestro/src/mcp/tool-packs/workspace/index.js +98 -0
- package/plugins/maestro/src/mcp/utils/extension-root.js +31 -0
- package/plugins/maestro/src/mcp/validation/agent-checker.js +81 -0
- package/plugins/maestro/src/mcp/validation/dag-checker.js +214 -0
- package/plugins/maestro/src/mcp/validation/file-overlap-checker.js +63 -0
- package/plugins/maestro/src/mcp/validation/schema-checker.js +108 -0
- package/plugins/maestro/src/platforms/codex/runtime-config.js +58 -0
- package/plugins/maestro/src/platforms/shared/adapters/conventions.js +29 -0
- package/plugins/maestro/src/platforms/shared/adapters/exit-codes.js +6 -0
- package/plugins/maestro/src/platforms/shared/adapters/factory.js +40 -0
- package/plugins/maestro/src/platforms/shared/agent-names.js +10 -0
- package/plugins/maestro/src/platforms/shared/hook-runner.js +52 -0
- package/plugins/maestro/src/references/architecture.md +139 -0
- package/plugins/maestro/src/references/orchestration-steps.md +193 -0
- package/plugins/maestro/src/skills/shared/code-review/SKILL.md +145 -0
- package/plugins/maestro/src/skills/shared/delegation/SKILL.md +370 -0
- package/plugins/maestro/src/skills/shared/delegation/protocols/agent-base-protocol.md +145 -0
- package/plugins/maestro/src/skills/shared/delegation/protocols/filesystem-safety-protocol.md +31 -0
- package/plugins/maestro/src/skills/shared/design-dialogue/SKILL.md +284 -0
- package/plugins/maestro/src/skills/shared/execution/SKILL.md +258 -0
- package/plugins/maestro/src/skills/shared/implementation-planning/SKILL.md +303 -0
- package/plugins/maestro/src/skills/shared/session-management/SKILL.md +314 -0
- package/plugins/maestro/src/skills/shared/validation/SKILL.md +204 -0
- package/plugins/maestro/src/state/session-state.js +113 -0
- package/plugins/maestro/src/templates/design-document.md +95 -0
- package/plugins/maestro/src/templates/implementation-plan.md +86 -0
- package/plugins/maestro/src/templates/session-state.md +68 -0
- package/plugins/maestro/src/version.json +3 -0
- package/policies/maestro.toml +44 -0
- package/qwen/agents/accessibility_specialist.md +18 -0
- package/qwen/agents/analytics_engineer.md +20 -0
- package/qwen/agents/api_designer.md +17 -0
- package/qwen/agents/architect.md +17 -0
- package/qwen/agents/cloud_architect.md +17 -0
- package/qwen/agents/cobol_engineer.md +20 -0
- package/qwen/agents/code_reviewer.md +15 -0
- package/qwen/agents/coder.md +20 -0
- package/qwen/agents/compliance_reviewer.md +17 -0
- package/qwen/agents/content_strategist.md +17 -0
- package/qwen/agents/copywriter.md +17 -0
- package/qwen/agents/data_engineer.md +20 -0
- package/qwen/agents/database_administrator.md +19 -0
- package/qwen/agents/db2_dba.md +19 -0
- package/qwen/agents/debugger.md +17 -0
- package/qwen/agents/design_system_engineer.md +20 -0
- package/qwen/agents/devops_engineer.md +21 -0
- package/qwen/agents/hlasm_assembler_specialist.md +20 -0
- package/qwen/agents/i18n_specialist.md +19 -0
- package/qwen/agents/ibm_i_specialist.md +20 -0
- package/qwen/agents/integration_engineer.md +21 -0
- package/qwen/agents/ml_engineer.md +21 -0
- package/qwen/agents/mlops_engineer.md +21 -0
- package/qwen/agents/mobile_engineer.md +21 -0
- package/qwen/agents/observability_engineer.md +21 -0
- package/qwen/agents/performance_engineer.md +19 -0
- package/qwen/agents/platform_engineer.md +22 -0
- package/qwen/agents/product_manager.md +18 -0
- package/qwen/agents/prompt_engineer.md +20 -0
- package/qwen/agents/refactor.md +20 -0
- package/qwen/agents/release_manager.md +20 -0
- package/qwen/agents/security_engineer.md +19 -0
- package/qwen/agents/seo_specialist.md +19 -0
- package/qwen/agents/site_reliability_engineer.md +19 -0
- package/qwen/agents/solutions_architect.md +17 -0
- package/qwen/agents/technical_writer.md +19 -0
- package/qwen/agents/tester.md +21 -0
- package/qwen/agents/ux_designer.md +18 -0
- package/qwen/agents/zos_sysprog.md +19 -0
- package/qwen/hooks.json +56 -0
- package/qwen-extension.json +55 -0
- package/scripts/check-layer-boundaries.js +74 -0
- package/scripts/generate.js +155 -0
- package/scripts/install-codex-plugin.js +167 -0
- package/scripts/install-git-hooks.js +43 -0
- package/scripts/npm-publish-idempotent.js +150 -0
- package/scripts/package-release-artifacts.js +156 -0
- package/scripts/release-artifact-manifest.js +378 -0
- package/scripts/release-version-metadata.js +129 -0
- package/scripts/update-versions.js +33 -0
- package/scripts/verify-npm-pack.js +85 -0
- package/scripts/verify-release-artifacts.js +95 -0
- package/src/agents/accessibility-specialist.md +163 -0
- package/src/agents/analytics-engineer.md +182 -0
- package/src/agents/api-designer.md +124 -0
- package/src/agents/architect.md +120 -0
- package/src/agents/cloud-architect.md +134 -0
- package/src/agents/cobol-engineer.md +127 -0
- package/src/agents/code-reviewer.md +123 -0
- package/src/agents/coder.md +132 -0
- package/src/agents/compliance-reviewer.md +219 -0
- package/src/agents/content-strategist.md +111 -0
- package/src/agents/copywriter.md +113 -0
- package/src/agents/data-engineer.md +130 -0
- package/src/agents/database-administrator.md +126 -0
- package/src/agents/db2-dba.md +124 -0
- package/src/agents/debugger.md +133 -0
- package/src/agents/design-system-engineer.md +258 -0
- package/src/agents/devops-engineer.md +138 -0
- package/src/agents/hlasm-assembler-specialist.md +134 -0
- package/src/agents/i18n-specialist.md +241 -0
- package/src/agents/ibm-i-specialist.md +132 -0
- package/src/agents/integration-engineer.md +133 -0
- package/src/agents/ml-engineer.md +115 -0
- package/src/agents/mlops-engineer.md +116 -0
- package/src/agents/mobile-engineer.md +115 -0
- package/src/agents/observability-engineer.md +133 -0
- package/src/agents/performance-engineer.md +139 -0
- package/src/agents/platform-engineer.md +129 -0
- package/src/agents/product-manager.md +170 -0
- package/src/agents/prompt-engineer.md +129 -0
- package/src/agents/refactor.md +138 -0
- package/src/agents/release-manager.md +132 -0
- package/src/agents/security-engineer.md +143 -0
- package/src/agents/seo-specialist.md +129 -0
- package/src/agents/site-reliability-engineer.md +131 -0
- package/src/agents/solutions-architect.md +137 -0
- package/src/agents/technical-writer.md +129 -0
- package/src/agents/tester.md +135 -0
- package/src/agents/ux-designer.md +168 -0
- package/src/agents/zos-sysprog.md +134 -0
- package/src/config/setting-resolver.js +32 -0
- package/src/core/agent-registry.js +67 -0
- package/src/core/canonical-source.js +39 -0
- package/src/core/env-file-parser.js +82 -0
- package/src/core/feature-blocks.js +34 -0
- package/src/core/logger.js +12 -0
- package/src/core/markdown-state.js +36 -0
- package/src/core/policy-rules.js +32 -0
- package/src/core/project-root-resolver.js +184 -0
- package/src/core/stdin-reader.js +77 -0
- package/src/core/version.js +50 -0
- package/src/entry-points/core-command-registry.js +37 -0
- package/src/entry-points/preamble-builders.js +54 -0
- package/src/entry-points/registry.js +199 -0
- package/src/entry-points/templates/claude-core-command.md.tmpl +38 -0
- package/src/entry-points/templates/claude-skill.md.tmpl +18 -0
- package/src/entry-points/templates/codex-core-command.md.tmpl +16 -0
- package/src/entry-points/templates/codex-skill.md.tmpl +11 -0
- package/src/entry-points/templates/gemini-command.toml.tmpl +17 -0
- package/src/entry-points/templates/gemini-core-command.toml.tmpl +30 -0
- package/src/generated/agent-registry.json +630 -0
- package/src/generated/hook-registry.json +18 -0
- package/src/generated/resource-registry.json +16 -0
- package/src/generator/entry-point-expander.js +182 -0
- package/src/generator/file-writer.js +167 -0
- package/src/generator/generation-session.js +62 -0
- package/src/generator/manifest-curator.js +31 -0
- package/src/generator/manifest-expander.js +256 -0
- package/src/generator/payload-builder.js +217 -0
- package/src/generator/registry-scanner.js +130 -0
- package/src/generator/stale-pruner.js +101 -0
- package/src/hooks/logic/after-agent-logic.js +54 -0
- package/src/hooks/logic/before-agent-logic.js +57 -0
- package/src/hooks/logic/hook-state.js +127 -0
- package/src/hooks/logic/session-end-logic.js +17 -0
- package/src/hooks/logic/session-start-logic.js +25 -0
- package/src/lib/discovery/index.js +172 -0
- package/src/lib/errors/index.js +104 -0
- package/src/lib/framework-detection.js +50 -0
- package/src/lib/frontmatter/index.js +262 -0
- package/src/lib/io/index.js +96 -0
- package/src/lib/naming/index.js +94 -0
- package/src/lib/validation/index.js +124 -0
- package/src/lib/yaml-emit.js +38 -0
- package/src/manifest.js +11 -0
- package/src/mcp/content/provider.js +68 -0
- package/src/mcp/content/runtime-content.js +188 -0
- package/src/mcp/contracts/cache-path-rejector.js +39 -0
- package/src/mcp/contracts/downstream-context.js +106 -0
- package/src/mcp/contracts/plan-schema.js +148 -0
- package/src/mcp/contracts/workspace-marker.js +61 -0
- package/src/mcp/core/create-server.js +76 -0
- package/src/mcp/core/line-reader.js +35 -0
- package/src/mcp/core/project-root-cache.js +120 -0
- package/src/mcp/core/protocol-dispatcher.js +274 -0
- package/src/mcp/core/recovery-hints.js +43 -0
- package/src/mcp/core/tool-outcome.js +77 -0
- package/src/mcp/core/tool-registry.js +82 -0
- package/src/mcp/handlers/assess-task-complexity.js +108 -0
- package/src/mcp/handlers/blocker-parser.js +34 -0
- package/src/mcp/handlers/design-gate.js +393 -0
- package/src/mcp/handlers/get-agent.js +54 -0
- package/src/mcp/handlers/get-runtime-context.js +49 -0
- package/src/mcp/handlers/get-skill-content.js +51 -0
- package/src/mcp/handlers/initialize-workspace.js +45 -0
- package/src/mcp/handlers/reconciliation.js +224 -0
- package/src/mcp/handlers/resolve-settings.js +39 -0
- package/src/mcp/handlers/session-state-core.js +108 -0
- package/src/mcp/handlers/session-state-tools.js +562 -0
- package/src/mcp/handlers/validate-plan.js +76 -0
- package/src/mcp/maestro-server.js +122 -0
- package/src/mcp/runtime/runtime-config-map.js +70 -0
- package/src/mcp/tool-packs/content/index.js +80 -0
- package/src/mcp/tool-packs/contracts.js +30 -0
- package/src/mcp/tool-packs/index.js +15 -0
- package/src/mcp/tool-packs/session/index.js +243 -0
- package/src/mcp/tool-packs/workspace/index.js +98 -0
- package/src/mcp/utils/extension-root.js +31 -0
- package/src/mcp/validation/agent-checker.js +81 -0
- package/src/mcp/validation/dag-checker.js +214 -0
- package/src/mcp/validation/file-overlap-checker.js +63 -0
- package/src/mcp/validation/schema-checker.js +108 -0
- package/src/platforms/claude/metadata.js +96 -0
- package/src/platforms/claude/runtime-config.js +60 -0
- package/src/platforms/codex/metadata.js +107 -0
- package/src/platforms/codex/runtime-config.js +58 -0
- package/src/platforms/gemini/metadata.js +27 -0
- package/src/platforms/gemini/runtime-config.js +62 -0
- package/src/platforms/metadata-shared.js +131 -0
- package/src/platforms/metadata.js +29 -0
- package/src/platforms/qwen/metadata.js +27 -0
- package/src/platforms/qwen/runtime-config.js +62 -0
- package/src/platforms/shared/adapters/claude-adapter.js +36 -0
- package/src/platforms/shared/adapters/conventions.js +29 -0
- package/src/platforms/shared/adapters/exit-codes.js +6 -0
- package/src/platforms/shared/adapters/factory.js +40 -0
- package/src/platforms/shared/adapters/gemini-adapter.js +34 -0
- package/src/platforms/shared/adapters/qwen-adapter.js +93 -0
- package/src/platforms/shared/agent-names.js +10 -0
- package/src/platforms/shared/hook-runner.js +52 -0
- package/src/references/architecture.md +139 -0
- package/src/references/orchestration-steps.md +193 -0
- package/src/scripts/ensure-workspace.js +14 -0
- package/src/scripts/read-active-session.js +26 -0
- package/src/scripts/read-setting.js +18 -0
- package/src/scripts/read-state.js +17 -0
- package/src/scripts/write-state.js +22 -0
- package/src/skills/shared/code-review/SKILL.md +145 -0
- package/src/skills/shared/delegation/SKILL.md +370 -0
- package/src/skills/shared/delegation/protocols/agent-base-protocol.md +145 -0
- package/src/skills/shared/delegation/protocols/filesystem-safety-protocol.md +31 -0
- package/src/skills/shared/design-dialogue/SKILL.md +284 -0
- package/src/skills/shared/execution/SKILL.md +258 -0
- package/src/skills/shared/implementation-planning/SKILL.md +303 -0
- package/src/skills/shared/session-management/SKILL.md +314 -0
- package/src/skills/shared/validation/SKILL.md +204 -0
- package/src/state/session-state.js +113 -0
- package/src/templates/design-document.md +95 -0
- package/src/templates/implementation-plan.md +86 -0
- package/src/templates/session-state.md +68 -0
- package/src/transforms/agent-stub.js +29 -0
- package/src/transforms/extract-examples.js +63 -0
- package/src/transforms/index.js +35 -0
- package/src/transforms/parse-frontmatter.js +23 -0
- package/src/transforms/rebuild-frontmatter.js +147 -0
- package/src/transforms/skill-discovery-stub.js +27 -0
- package/src/transforms/skill-metadata.js +14 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const TITLE_SPECIAL_CASES = {
|
|
4
|
+
'a11y-audit': 'Accessibility Audit',
|
|
5
|
+
'seo-audit': 'SEO Audit',
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Convert a kebab-case name to snake_case.
|
|
10
|
+
* @param {string} name - Name in kebab-case (e.g. 'api-designer')
|
|
11
|
+
* @returns {string} Name in snake_case (e.g. 'api_designer')
|
|
12
|
+
*/
|
|
13
|
+
function toSnakeCase(name) {
|
|
14
|
+
return name.replace(/-/g, '_');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Convert a snake_case name to kebab-case.
|
|
19
|
+
* @param {string} name - Name in snake_case (e.g. 'api_designer')
|
|
20
|
+
* @returns {string} Name in kebab-case (e.g. 'api-designer')
|
|
21
|
+
*/
|
|
22
|
+
function toKebabCase(name) {
|
|
23
|
+
return name.replace(/_/g, '-');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Convert a kebab-case name to PascalCase.
|
|
28
|
+
* @param {string} name - Name in kebab-case (e.g. 'session-start')
|
|
29
|
+
* @returns {string} Name in PascalCase (e.g. 'SessionStart')
|
|
30
|
+
*/
|
|
31
|
+
function toPascalCase(name) {
|
|
32
|
+
return name
|
|
33
|
+
.split('-')
|
|
34
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
35
|
+
.join('');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Convert a kebab-case name to title case for display.
|
|
40
|
+
* Includes special-case handling for abbreviations and accessibility terms.
|
|
41
|
+
*
|
|
42
|
+
* @param {string} name - Name in kebab-case (e.g. 'perf-check')
|
|
43
|
+
* @returns {string} Display-friendly title (e.g. 'Perf Check')
|
|
44
|
+
*/
|
|
45
|
+
function toTitleCase(name) {
|
|
46
|
+
if (TITLE_SPECIAL_CASES[name]) {
|
|
47
|
+
return TITLE_SPECIAL_CASES[name];
|
|
48
|
+
}
|
|
49
|
+
return name
|
|
50
|
+
.split('-')
|
|
51
|
+
.map((w) => w.charAt(0).toUpperCase() + w.slice(1))
|
|
52
|
+
.join(' ');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Replace all occurrences of canonical kebab-case names in content
|
|
57
|
+
* with the target naming convention.
|
|
58
|
+
*
|
|
59
|
+
* When targetCase is 'snake_case', each name in the provided list
|
|
60
|
+
* is matched using word-boundary regexes and replaced with its snake_case
|
|
61
|
+
* equivalent. When targetCase is 'kebab-case', content is returned unchanged
|
|
62
|
+
* since kebab-case is the canonical format.
|
|
63
|
+
*
|
|
64
|
+
* @param {string} content - Text content containing name references
|
|
65
|
+
* @param {string[]} names - Canonical kebab-case names to replace
|
|
66
|
+
* @param {string} targetCase - Target convention: 'snake_case' or 'kebab-case'
|
|
67
|
+
* @returns {string} Content with names converted to the target convention
|
|
68
|
+
*/
|
|
69
|
+
function replaceInContent(content, names, targetCase) {
|
|
70
|
+
if (targetCase !== 'snake_case') {
|
|
71
|
+
return content;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (!names || names.length === 0) {
|
|
75
|
+
return content;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
let result = content;
|
|
79
|
+
for (const name of names) {
|
|
80
|
+
const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
81
|
+
const pattern = new RegExp(`\\b${escaped}\\b`, 'g');
|
|
82
|
+
result = result.replace(pattern, toSnakeCase(name));
|
|
83
|
+
}
|
|
84
|
+
return result;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
module.exports = {
|
|
88
|
+
TITLE_SPECIAL_CASES,
|
|
89
|
+
toSnakeCase,
|
|
90
|
+
toKebabCase,
|
|
91
|
+
toPascalCase,
|
|
92
|
+
toTitleCase,
|
|
93
|
+
replaceInContent,
|
|
94
|
+
};
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('node:fs');
|
|
4
|
+
const path = require('node:path');
|
|
5
|
+
const { ValidationError } = require('../errors');
|
|
6
|
+
|
|
7
|
+
const SESSION_ID_PATTERN = /^[a-zA-Z0-9_-]+$/;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @param {*} value
|
|
11
|
+
* @param {string} label
|
|
12
|
+
* @throws {ValidationError}
|
|
13
|
+
*/
|
|
14
|
+
function assertNonEmptyArray(value, label) {
|
|
15
|
+
if (!Array.isArray(value) || value.length === 0) {
|
|
16
|
+
throw new ValidationError(`${label} must be a non-empty array`, {
|
|
17
|
+
details: { value, label },
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @param {*} id
|
|
24
|
+
* @throws {ValidationError}
|
|
25
|
+
*/
|
|
26
|
+
function assertSessionId(id) {
|
|
27
|
+
if (typeof id !== 'string' || !SESSION_ID_PATTERN.test(id)) {
|
|
28
|
+
throw new ValidationError(
|
|
29
|
+
'Invalid session_id: must match pattern [a-zA-Z0-9_-]+',
|
|
30
|
+
{ details: { value: id } }
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @param {string|string[]} value
|
|
37
|
+
* @param {string[]|Record<string, *>} allowlist
|
|
38
|
+
* @param {string} label
|
|
39
|
+
* @throws {ValidationError}
|
|
40
|
+
*/
|
|
41
|
+
function assertAllowlisted(value, allowlist, label) {
|
|
42
|
+
const entries = Array.isArray(value) ? value : [value];
|
|
43
|
+
const permitted = Array.isArray(allowlist) ? allowlist : Object.keys(allowlist);
|
|
44
|
+
const invalid = entries.filter((entry) => !permitted.includes(entry));
|
|
45
|
+
|
|
46
|
+
if (invalid.length > 0) {
|
|
47
|
+
throw new ValidationError(
|
|
48
|
+
`Unknown ${label}: ${invalid.map((v) => `"${v}"`).join(', ')}. Known identifiers: ${permitted.join(', ')}`,
|
|
49
|
+
{ details: { invalid, permitted, label } }
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* @param {string} p
|
|
56
|
+
* @throws {ValidationError}
|
|
57
|
+
*/
|
|
58
|
+
function assertRelativePath(p) {
|
|
59
|
+
if (typeof p !== 'string') {
|
|
60
|
+
throw new ValidationError('Path must be a string', {
|
|
61
|
+
details: { value: p },
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (p.includes('\0')) {
|
|
66
|
+
throw new ValidationError('Path contains null bytes', {
|
|
67
|
+
details: { value: p },
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (path.isAbsolute(p)) {
|
|
72
|
+
throw new ValidationError('Path must be relative', {
|
|
73
|
+
details: { value: p },
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const segments = p.split(/[/\\]/);
|
|
78
|
+
if (segments.includes('..')) {
|
|
79
|
+
throw new ValidationError('Path traversal not allowed', {
|
|
80
|
+
details: { value: p },
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* @param {string} p
|
|
87
|
+
* @param {string} base
|
|
88
|
+
* @throws {ValidationError}
|
|
89
|
+
*/
|
|
90
|
+
function assertContainedIn(p, base) {
|
|
91
|
+
let resolved = path.resolve(p);
|
|
92
|
+
let resolvedBase = path.resolve(base);
|
|
93
|
+
|
|
94
|
+
try { resolved = fs.realpathSync(resolved); } catch {}
|
|
95
|
+
try { resolvedBase = fs.realpathSync(resolvedBase); } catch {}
|
|
96
|
+
|
|
97
|
+
const basePrefix = resolvedBase + path.sep;
|
|
98
|
+
|
|
99
|
+
if (!resolved.startsWith(basePrefix) && resolved !== resolvedBase) {
|
|
100
|
+
throw new ValidationError('Path escapes base directory', {
|
|
101
|
+
details: { path: resolved, base: resolvedBase },
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* @param {*} value
|
|
108
|
+
* @returns {*}
|
|
109
|
+
*/
|
|
110
|
+
function coercePositiveInteger(value) {
|
|
111
|
+
if (value == null || typeof value === 'number') return value;
|
|
112
|
+
if (typeof value !== 'string') return value;
|
|
113
|
+
const num = Number(value);
|
|
114
|
+
return Number.isFinite(num) && Number.isInteger(num) && num > 0 ? num : value;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
module.exports = {
|
|
118
|
+
assertNonEmptyArray,
|
|
119
|
+
assertSessionId,
|
|
120
|
+
assertAllowlisted,
|
|
121
|
+
assertRelativePath,
|
|
122
|
+
assertContainedIn,
|
|
123
|
+
coercePositiveInteger,
|
|
124
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Minimal YAML fragment emitters used by the generator.
|
|
5
|
+
*
|
|
6
|
+
* Neither function escapes its inputs — callers MUST pass YAML-safe
|
|
7
|
+
* scalars (identifiers, numbers, or pre-escaped strings). Values
|
|
8
|
+
* containing `:`, `"`, `\`, or leading/trailing whitespace will
|
|
9
|
+
* produce invalid YAML.
|
|
10
|
+
*
|
|
11
|
+
* Current callers (entry-point-expander, preamble-builders) pass
|
|
12
|
+
* agent names, skill names, and reference names — all controlled
|
|
13
|
+
* inputs from the canonical source tree — so the raw interpolation
|
|
14
|
+
* is safe in practice.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Emit a block-style list under `key`. Returns [] when the list is
|
|
19
|
+
* empty so callers can append without producing an orphaned `key:`
|
|
20
|
+
* line.
|
|
21
|
+
*/
|
|
22
|
+
function emitBlockList(key, items) {
|
|
23
|
+
if (!items || items.length === 0) return [];
|
|
24
|
+
return [`${key}:`, ...items.map((item) => ` - ${item}`)];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Emit an inline comma-separated list of double-quoted scalars.
|
|
29
|
+
* Intended for embedding inside flow-style arrays like `[...]`.
|
|
30
|
+
*/
|
|
31
|
+
function emitInlineQuotedList(items) {
|
|
32
|
+
return items.map((item) => `"${item}"`).join(', ');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
module.exports = {
|
|
36
|
+
emitBlockList,
|
|
37
|
+
emitInlineQuotedList,
|
|
38
|
+
};
|
package/src/manifest.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
module.exports = [
|
|
2
|
+
// ── Agent discovery stubs — Gemini, Claude, and Qwen ───────────────
|
|
3
|
+
{ glob: 'agents/*.md',
|
|
4
|
+
transforms: ['parse-frontmatter', 'extract-examples', 'rebuild-frontmatter', 'agent-stub'],
|
|
5
|
+
runtimes: ['gemini', 'claude', 'qwen'] },
|
|
6
|
+
|
|
7
|
+
// ── Shared skill discovery stubs — Claude + Codex only ─────────────
|
|
8
|
+
{ glob: 'skills/shared/**/SKILL.md',
|
|
9
|
+
transforms: ['skill-discovery-stub'],
|
|
10
|
+
runtimes: ['claude', 'codex'] },
|
|
11
|
+
];
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { resolveCanonicalSrcFromExtensionRoot } = require('../utils/extension-root');
|
|
4
|
+
const {
|
|
5
|
+
readResourceFromFilesystem,
|
|
6
|
+
readAgentFromFilesystem,
|
|
7
|
+
} = require('./runtime-content');
|
|
8
|
+
|
|
9
|
+
const CONTENT_SOURCES = Object.freeze({
|
|
10
|
+
FILESYSTEM: 'filesystem',
|
|
11
|
+
NONE: 'none',
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
function createFilesystemProvider(runtimeConfig, canonicalSrcRoot = resolveCanonicalSrcFromExtensionRoot()) {
|
|
15
|
+
const srcRoot = canonicalSrcRoot;
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
readResource(id) {
|
|
19
|
+
return readResourceFromFilesystem(id, runtimeConfig, srcRoot);
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
readAgent(agentName) {
|
|
23
|
+
return readAgentFromFilesystem(agentName, runtimeConfig, srcRoot);
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function normalizeContentPolicy(runtimeConfig) {
|
|
29
|
+
const content = runtimeConfig && runtimeConfig.content;
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
primary: content && content.primary ? content.primary : CONTENT_SOURCES.FILESYSTEM,
|
|
33
|
+
fallback: content && content.fallback ? content.fallback : CONTENT_SOURCES.NONE,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Every runtime configures `primary=filesystem, fallback=none`, so the
|
|
39
|
+
* chain collapses to the filesystem provider with a shaped error for
|
|
40
|
+
* `none`. If a future source is introduced, reintroduce chaining here.
|
|
41
|
+
*/
|
|
42
|
+
function createContentProvider(runtimeConfig, canonicalSrcRoot = resolveCanonicalSrcFromExtensionRoot()) {
|
|
43
|
+
const { primary } = normalizeContentPolicy(runtimeConfig);
|
|
44
|
+
|
|
45
|
+
if (primary === CONTENT_SOURCES.NONE) {
|
|
46
|
+
return {
|
|
47
|
+
readResource(id) {
|
|
48
|
+
return { error: `No content provider could read resource "${id}"` };
|
|
49
|
+
},
|
|
50
|
+
readAgent(agentName) {
|
|
51
|
+
return { error: `No content provider could read agent "${agentName}"` };
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (primary !== CONTENT_SOURCES.FILESYSTEM) {
|
|
57
|
+
throw new Error(`Unknown content source: "${primary}"`);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return createFilesystemProvider(runtimeConfig, canonicalSrcRoot);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
module.exports = {
|
|
64
|
+
CONTENT_SOURCES,
|
|
65
|
+
createContentProvider,
|
|
66
|
+
createFilesystemProvider,
|
|
67
|
+
normalizeContentPolicy,
|
|
68
|
+
};
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { parseFrontmatterOnly, splitAtBoundary } = require('../../lib/frontmatter');
|
|
6
|
+
const { replaceInContent } = require('../../lib/naming');
|
|
7
|
+
const { stripFeatureBlocks: stripFeatureBlocksCore } = require('../../core/feature-blocks');
|
|
8
|
+
|
|
9
|
+
const agentRegistry = require('../../generated/agent-registry.json');
|
|
10
|
+
|
|
11
|
+
const DEFAULT_RUNTIME_NAME = 'gemini';
|
|
12
|
+
|
|
13
|
+
const RESOURCE_ALLOWLIST = Object.freeze(require('../../generated/resource-registry.json'));
|
|
14
|
+
|
|
15
|
+
const AGENT_ALLOWLIST = Object.freeze(agentRegistry.map((entry) => entry.name));
|
|
16
|
+
|
|
17
|
+
function applyReplacePaths(content, runtimeConfig) {
|
|
18
|
+
let result = content;
|
|
19
|
+
const env = runtimeConfig.env || {};
|
|
20
|
+
|
|
21
|
+
if (env.extensionPath) {
|
|
22
|
+
const replacement = env.extensionPath.startsWith('${')
|
|
23
|
+
? env.extensionPath
|
|
24
|
+
: '${' + env.extensionPath + '}';
|
|
25
|
+
result = result.replace(/\$\{extensionPath\}/g, replacement);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (env.workspacePath) {
|
|
29
|
+
result = result.replace(/\$\{workspacePath\}/g, '${' + env.workspacePath + '}');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return result;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function applySkillMetadata(content, runtimeConfig, resourcePath) {
|
|
36
|
+
if (runtimeConfig.name !== 'claude' || !resourcePath.endsWith('SKILL.md')) {
|
|
37
|
+
return content;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return content.replace(
|
|
41
|
+
/^(---\n[\s\S]*?)(^---)/m,
|
|
42
|
+
'$1user-invocable: false\n$2'
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function applyReplaceAgentNames(content, runtimeConfig) {
|
|
47
|
+
return replaceInContent(
|
|
48
|
+
content,
|
|
49
|
+
AGENT_ALLOWLIST.filter((n) => n.includes('-')),
|
|
50
|
+
runtimeConfig.agentNaming
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function applyStripFeature(content, runtimeConfig) {
|
|
55
|
+
return stripFeatureBlocksCore(content, runtimeConfig.features || {});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const AGENT_NAME_RESOURCES = new Set([
|
|
59
|
+
'references/architecture.md',
|
|
60
|
+
'skills/shared/delegation/SKILL.md',
|
|
61
|
+
'skills/shared/execution/SKILL.md',
|
|
62
|
+
'skills/shared/validation/SKILL.md',
|
|
63
|
+
'skills/shared/code-review/SKILL.md',
|
|
64
|
+
]);
|
|
65
|
+
|
|
66
|
+
function applyRuntimeTransforms(content, runtimeConfig, resourcePath) {
|
|
67
|
+
let result = content;
|
|
68
|
+
|
|
69
|
+
if (resourcePath === 'references/architecture.md') {
|
|
70
|
+
result = applyStripFeature(result, runtimeConfig);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (AGENT_NAME_RESOURCES.has(resourcePath)) {
|
|
74
|
+
result = applyReplaceAgentNames(result, runtimeConfig);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
result = applyReplacePaths(result, runtimeConfig);
|
|
78
|
+
result = applySkillMetadata(result, runtimeConfig, resourcePath);
|
|
79
|
+
|
|
80
|
+
return result;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function stripFrontmatter(content) {
|
|
84
|
+
const { raw, body } = splitAtBoundary(content);
|
|
85
|
+
if (!raw) {
|
|
86
|
+
return content;
|
|
87
|
+
}
|
|
88
|
+
return body;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function stripFeatureBlocks(content, runtimeConfig) {
|
|
92
|
+
return stripFeatureBlocksCore(content, runtimeConfig.features || {}, { mode: 'lenient' });
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function parseInlineArray(raw) {
|
|
96
|
+
if (!raw || !raw.startsWith('[') || !raw.endsWith(']')) {
|
|
97
|
+
return [];
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return raw
|
|
101
|
+
.slice(1, -1)
|
|
102
|
+
.split(',')
|
|
103
|
+
.map((item) => item.trim())
|
|
104
|
+
.filter(Boolean);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function parseFrontmatter(content) {
|
|
108
|
+
return parseFrontmatterOnly(content).frontmatter;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function mapTools(frontmatter, runtimeConfig) {
|
|
112
|
+
const runtimeName = runtimeConfig.name || DEFAULT_RUNTIME_NAME;
|
|
113
|
+
const overrideKey = `tools.${runtimeName}`;
|
|
114
|
+
const configuredTools = frontmatter[overrideKey]
|
|
115
|
+
? parseInlineArray(frontmatter[overrideKey])
|
|
116
|
+
: parseInlineArray(frontmatter.tools);
|
|
117
|
+
|
|
118
|
+
return configuredTools.flatMap((toolName) => {
|
|
119
|
+
const mapped = runtimeConfig.tools && runtimeConfig.tools[toolName];
|
|
120
|
+
if (Array.isArray(mapped)) {
|
|
121
|
+
return mapped;
|
|
122
|
+
}
|
|
123
|
+
return mapped || toolName;
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function readResourceFromFilesystem(id, runtimeConfig, srcRoot) {
|
|
128
|
+
const relativePath = RESOURCE_ALLOWLIST[id];
|
|
129
|
+
if (!relativePath) {
|
|
130
|
+
return {
|
|
131
|
+
error: `Unknown resource identifier: "${id}". Known identifiers: ${Object.keys(RESOURCE_ALLOWLIST).join(', ')}`,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const absolutePath = path.join(srcRoot, relativePath);
|
|
136
|
+
try {
|
|
137
|
+
const content = fs.readFileSync(absolutePath, 'utf8');
|
|
138
|
+
return {
|
|
139
|
+
content: applyRuntimeTransforms(content, runtimeConfig, relativePath),
|
|
140
|
+
};
|
|
141
|
+
} catch (err) {
|
|
142
|
+
return {
|
|
143
|
+
error: `Failed to read resource "${id}": ${err.code || 'UNKNOWN'}`,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function readAgentFromFilesystem(agentName, runtimeConfig, srcRoot) {
|
|
149
|
+
if (!AGENT_ALLOWLIST.includes(agentName)) {
|
|
150
|
+
return {
|
|
151
|
+
error: `Unknown agent identifier: "${agentName}". Known identifiers: ${AGENT_ALLOWLIST.join(', ')}`,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const absolutePath = path.join(srcRoot, 'agents', `${agentName}.md`);
|
|
156
|
+
try {
|
|
157
|
+
const content = fs.readFileSync(absolutePath, 'utf8');
|
|
158
|
+
const frontmatter = parseFrontmatter(content);
|
|
159
|
+
return {
|
|
160
|
+
agent: {
|
|
161
|
+
body: stripFrontmatter(stripFeatureBlocks(content, runtimeConfig)),
|
|
162
|
+
tools: mapTools(frontmatter, runtimeConfig),
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
} catch (err) {
|
|
166
|
+
return {
|
|
167
|
+
error: `Failed to read agent "${agentName}": ${err.code || 'UNKNOWN'}`,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
module.exports = {
|
|
173
|
+
DEFAULT_RUNTIME_NAME,
|
|
174
|
+
RESOURCE_ALLOWLIST,
|
|
175
|
+
AGENT_ALLOWLIST,
|
|
176
|
+
applyReplacePaths,
|
|
177
|
+
applySkillMetadata,
|
|
178
|
+
applyReplaceAgentNames,
|
|
179
|
+
applyStripFeature,
|
|
180
|
+
applyRuntimeTransforms,
|
|
181
|
+
stripFrontmatter,
|
|
182
|
+
stripFeatureBlocks,
|
|
183
|
+
parseInlineArray,
|
|
184
|
+
parseFrontmatter,
|
|
185
|
+
mapTools,
|
|
186
|
+
readResourceFromFilesystem,
|
|
187
|
+
readAgentFromFilesystem,
|
|
188
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
|
|
5
|
+
const CACHE_PATH_SEGMENTS = [
|
|
6
|
+
path.join('.codex', 'plugins'),
|
|
7
|
+
path.join('.claude', 'plugins'),
|
|
8
|
+
path.join('.gemini', 'extensions'),
|
|
9
|
+
];
|
|
10
|
+
|
|
11
|
+
function segmentWindows(segments, size) {
|
|
12
|
+
const windows = [];
|
|
13
|
+
for (let i = 0; i <= segments.length - size; i += 1) {
|
|
14
|
+
windows.push(segments.slice(i, i + size).join(path.sep));
|
|
15
|
+
}
|
|
16
|
+
return windows;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Returns true when the given path falls inside a host extension cache directory.
|
|
21
|
+
* Matches on contiguous two-segment windows so that substring-only matches
|
|
22
|
+
* (e.g. `.codex-plugins-research`) are correctly distinguished from genuine cache directories and not misclassified as cache paths.
|
|
23
|
+
*
|
|
24
|
+
* @param {string} candidate - Filesystem path. Absolute paths are used as-is; relative paths are resolved against process.cwd(), so callers should pass absolute paths for deterministic behavior.
|
|
25
|
+
* @returns {boolean}
|
|
26
|
+
*/
|
|
27
|
+
function isExtensionCachePath(candidate) {
|
|
28
|
+
if (typeof candidate !== 'string' || candidate.length === 0) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
const segments = path
|
|
32
|
+
.resolve(candidate)
|
|
33
|
+
.split(path.sep)
|
|
34
|
+
.filter((segment) => segment.length > 0);
|
|
35
|
+
const windows = segmentWindows(segments, 2);
|
|
36
|
+
return CACHE_PATH_SEGMENTS.some((cacheSegment) => windows.includes(cacheSegment));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
module.exports = { CACHE_PATH_SEGMENTS, isExtensionCachePath };
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Canonical downstream-context contract.
|
|
5
|
+
*
|
|
6
|
+
* The handoff between orchestrator and child agents is documented (in
|
|
7
|
+
* agent-base-protocol) as a five-field structure. Agents may emit each field as
|
|
8
|
+
* either a string (`"none"`, `"X uses Y"`) or an array of strings. The canonical
|
|
9
|
+
* storage shape is an array of strings; normalization here is the single source
|
|
10
|
+
* of truth used by every handler that reads, writes, or validates the context.
|
|
11
|
+
*
|
|
12
|
+
* Strings and the tokens `"none"` / `"n/a"` / empty strings are all treated as
|
|
13
|
+
* absent so agent protocol examples like `"or none"` don't produce phantom
|
|
14
|
+
* entries in session state.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
const CANONICAL_FIELDS = Object.freeze([
|
|
18
|
+
'key_interfaces_introduced',
|
|
19
|
+
'patterns_established',
|
|
20
|
+
'integration_points',
|
|
21
|
+
'assumptions',
|
|
22
|
+
'warnings',
|
|
23
|
+
]);
|
|
24
|
+
|
|
25
|
+
const EMPTY_VALUE_TOKENS = new Set(['', 'none', 'n/a', 'not applicable']);
|
|
26
|
+
|
|
27
|
+
function isEmptyValueToken(value) {
|
|
28
|
+
return EMPTY_VALUE_TOKENS.has(String(value).trim().toLowerCase());
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function normalizeFieldValue(value) {
|
|
32
|
+
if (value == null) return [];
|
|
33
|
+
if (Array.isArray(value)) {
|
|
34
|
+
return value
|
|
35
|
+
.filter((item) => typeof item === 'string')
|
|
36
|
+
.map((item) => item.trim())
|
|
37
|
+
.filter((item) => item.length > 0 && !isEmptyValueToken(item));
|
|
38
|
+
}
|
|
39
|
+
if (typeof value === 'string') {
|
|
40
|
+
const trimmed = value.trim();
|
|
41
|
+
if (trimmed.length === 0 || isEmptyValueToken(trimmed)) return [];
|
|
42
|
+
return [trimmed];
|
|
43
|
+
}
|
|
44
|
+
return [];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @returns {Object<string, string[]>} a fresh empty canonical context.
|
|
49
|
+
*/
|
|
50
|
+
function createEmptyDownstreamContext() {
|
|
51
|
+
const empty = {};
|
|
52
|
+
for (const field of CANONICAL_FIELDS) {
|
|
53
|
+
empty[field] = [];
|
|
54
|
+
}
|
|
55
|
+
return empty;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Normalize any input to the canonical `{ field: string[] }` shape.
|
|
60
|
+
* Accepts null, arrays-of-strings, strings, and unknown keys are dropped.
|
|
61
|
+
*
|
|
62
|
+
* @param {unknown} input
|
|
63
|
+
* @returns {Object<string, string[]>}
|
|
64
|
+
*/
|
|
65
|
+
function normalizeDownstreamContext(input) {
|
|
66
|
+
const normalized = createEmptyDownstreamContext();
|
|
67
|
+
if (!input || typeof input !== 'object' || Array.isArray(input)) {
|
|
68
|
+
return normalized;
|
|
69
|
+
}
|
|
70
|
+
for (const field of CANONICAL_FIELDS) {
|
|
71
|
+
normalized[field] = normalizeFieldValue(input[field]);
|
|
72
|
+
}
|
|
73
|
+
return normalized;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* True when the normalized context has at least one non-empty field.
|
|
78
|
+
* @param {unknown} input
|
|
79
|
+
* @returns {boolean}
|
|
80
|
+
*/
|
|
81
|
+
function isDownstreamContextPopulated(input) {
|
|
82
|
+
const normalized = normalizeDownstreamContext(input);
|
|
83
|
+
return CANONICAL_FIELDS.some((field) => normalized[field].length > 0);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Human-readable description of the contract, suitable for embedding in error
|
|
88
|
+
* messages so callers can adapt without reading source.
|
|
89
|
+
* @returns {string}
|
|
90
|
+
*/
|
|
91
|
+
function describeShape() {
|
|
92
|
+
return (
|
|
93
|
+
'downstream_context must contain at least one of: ' +
|
|
94
|
+
CANONICAL_FIELDS.join(', ') +
|
|
95
|
+
'. Each field accepts a non-empty string or a non-empty array of strings. ' +
|
|
96
|
+
'Empty strings and the tokens "none" / "n/a" / "not applicable" are treated as absent.'
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
module.exports = {
|
|
101
|
+
CANONICAL_FIELDS,
|
|
102
|
+
createEmptyDownstreamContext,
|
|
103
|
+
normalizeDownstreamContext,
|
|
104
|
+
isDownstreamContextPopulated,
|
|
105
|
+
describeShape,
|
|
106
|
+
};
|