contextdevkit 1.8.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/CHANGELOG.md +592 -0
- package/LICENSE +21 -0
- package/README.md +401 -0
- package/docs/AGENT-PACKAGE-FORMAT.md +140 -0
- package/docs/ARCHITECTURE.md +258 -0
- package/docs/CHANGELOG.md +559 -0
- package/docs/CUSTOMIZING.md +211 -0
- package/docs/LEVELS.md +151 -0
- package/docs/ROADMAP.md +385 -0
- package/docs/SQUAD-PIPELINE-FORMAT.md +258 -0
- package/docs/SQUADS/agent-forge.md +65 -0
- package/docs/SQUADS/design-team.md +161 -0
- package/docs/token-economy-plan.md +135 -0
- package/install.mjs +273 -0
- package/instrucoes.md +274 -0
- package/package.json +46 -0
- package/templates/CLAUDE.md.tpl +133 -0
- package/templates/claude/agents/_TEMPLATE.md +52 -0
- package/templates/claude/agents/accessibility.md +36 -0
- package/templates/claude/agents/agent-architect.md +37 -0
- package/templates/claude/agents/architect.md +39 -0
- package/templates/claude/agents/code-reviewer.md +43 -0
- package/templates/claude/agents/code-security.md +59 -0
- package/templates/claude/agents/context-keeper.md +40 -0
- package/templates/claude/agents/devops.md +40 -0
- package/templates/claude/agents/eval-designer.md +40 -0
- package/templates/claude/agents/forge-orchestrator.md +42 -0
- package/templates/claude/agents/governance-officer.md +45 -0
- package/templates/claude/agents/growth.md +92 -0
- package/templates/claude/agents/infra-security.md +53 -0
- package/templates/claude/agents/landing-architect.md +154 -0
- package/templates/claude/agents/model-router.md +34 -0
- package/templates/claude/agents/packager.md +38 -0
- package/templates/claude/agents/privacy-lgpd.md +64 -0
- package/templates/claude/agents/product-owner.md +51 -0
- package/templates/claude/agents/prompt-engineer.md +33 -0
- package/templates/claude/agents/qa-e2e.md +52 -0
- package/templates/claude/agents/qa-fuzzer.md +24 -0
- package/templates/claude/agents/qa-integration.md +21 -0
- package/templates/claude/agents/qa-orchestrator.md +40 -0
- package/templates/claude/agents/qa-perf.md +40 -0
- package/templates/claude/agents/qa-unit.md +39 -0
- package/templates/claude/agents/rag-designer.md +54 -0
- package/templates/claude/agents/retention.md +85 -0
- package/templates/claude/agents/security.md +48 -0
- package/templates/claude/agents/seo-specialist.md +106 -0
- package/templates/claude/agents/test-engineer.md +48 -0
- package/templates/claude/agents/tool-designer.md +32 -0
- package/templates/claude/agents/ui-designer.md +37 -0
- package/templates/claude/agents/ux-designer.md +38 -0
- package/templates/claude/commands/README.md +95 -0
- package/templates/claude/commands/advise.md +80 -0
- package/templates/claude/commands/audit/analyze-code-ia-practices.md +75 -0
- package/templates/claude/commands/audit/audit.md +35 -0
- package/templates/claude/commands/audit/contract-check.md +21 -0
- package/templates/claude/commands/audit/deep-analysis.md +48 -0
- package/templates/claude/commands/audit/deps-audit.md +49 -0
- package/templates/claude/commands/audit/security-setup.md +35 -0
- package/templates/claude/commands/audit/seo-audit.md +63 -0
- package/templates/claude/commands/audit/tech-debt-sweep.md +35 -0
- package/templates/claude/commands/bug-hunt.md +42 -0
- package/templates/claude/commands/claude-md.md +36 -0
- package/templates/claude/commands/close-version.md +25 -0
- package/templates/claude/commands/context-refresh.md +19 -0
- package/templates/claude/commands/context-stats.md +15 -0
- package/templates/claude/commands/dashboard.md +66 -0
- package/templates/claude/commands/distill-apply.md +19 -0
- package/templates/claude/commands/distill-sessions.md +26 -0
- package/templates/claude/commands/fleet.md +47 -0
- package/templates/claude/commands/forge/forge-audit.md +16 -0
- package/templates/claude/commands/forge/forge-budget.md +16 -0
- package/templates/claude/commands/forge/forge-deprecate.md +16 -0
- package/templates/claude/commands/forge/forge-doctor.md +17 -0
- package/templates/claude/commands/forge/forge-eval.md +16 -0
- package/templates/claude/commands/forge/forge-fallback-test.md +17 -0
- package/templates/claude/commands/forge/forge-killswitch.md +17 -0
- package/templates/claude/commands/forge/forge-list.md +17 -0
- package/templates/claude/commands/forge/forge-new.md +41 -0
- package/templates/claude/commands/forge/forge-policy.md +16 -0
- package/templates/claude/commands/forge/forge-redteam.md +17 -0
- package/templates/claude/commands/forge/forge-refresh-matrix.md +20 -0
- package/templates/claude/commands/forge/forge-route.md +17 -0
- package/templates/claude/commands/forge/forge-show.md +16 -0
- package/templates/claude/commands/landing-page.md +71 -0
- package/templates/claude/commands/log-session.md +59 -0
- package/templates/claude/commands/media-gen.md +93 -0
- package/templates/claude/commands/new-adr.md +30 -0
- package/templates/claude/commands/pipeline/dev-start.md +64 -0
- package/templates/claude/commands/pipeline/pipeline.md +36 -0
- package/templates/claude/commands/pipeline/resume.md +70 -0
- package/templates/claude/commands/pipeline/retro.md +34 -0
- package/templates/claude/commands/pipeline/runs.md +63 -0
- package/templates/claude/commands/pipeline/ship.md +54 -0
- package/templates/claude/commands/pipeline/workflow.md +85 -0
- package/templates/claude/commands/playbook.md +27 -0
- package/templates/claude/commands/predictions-review.md +28 -0
- package/templates/claude/commands/qa/qa-signoff.md +24 -0
- package/templates/claude/commands/qa/scaffold-tests.md +27 -0
- package/templates/claude/commands/qa/test-plan.md +26 -0
- package/templates/claude/commands/qa/visual-test.md +42 -0
- package/templates/claude/commands/roadmap.md +48 -0
- package/templates/claude/commands/setup/aidevtool-from0.md +104 -0
- package/templates/claude/commands/setup/context-config.md +25 -0
- package/templates/claude/commands/setup/context-doctor.md +21 -0
- package/templates/claude/commands/setup/context-level.md +17 -0
- package/templates/claude/commands/setup/setupcontextdevkit.md +121 -0
- package/templates/claude/commands/simulate-impact.md +32 -0
- package/templates/claude/commands/squad.md +44 -0
- package/templates/claude/commands/state.md +21 -0
- package/templates/claude/commands/token-report.md +29 -0
- package/templates/claude/commands/tune-agents.md +35 -0
- package/templates/claude/commands/vcs/claim.md +18 -0
- package/templates/claude/commands/vcs/git.md +83 -0
- package/templates/claude/commands/vcs/release.md +15 -0
- package/templates/claude/commands/vcs/worktree-new.md +18 -0
- package/templates/claude/commands/watch.md +47 -0
- package/templates/contextkit/.env.example +36 -0
- package/templates/contextkit/CLAUDE.child.md.tpl +38 -0
- package/templates/contextkit/README.md +74 -0
- package/templates/contextkit/behaviors-examples.md +183 -0
- package/templates/contextkit/behaviors.md +116 -0
- package/templates/contextkit/best-practices.md +323 -0
- package/templates/contextkit/config.json +66 -0
- package/templates/contextkit/detectors/README.md +45 -0
- package/templates/contextkit/detectors/example-detector.mjs.example +25 -0
- package/templates/contextkit/instrucoes.md +114 -0
- package/templates/contextkit/memory/GLOSSARY.md +13 -0
- package/templates/contextkit/memory/SESSIONS.md +9 -0
- package/templates/contextkit/memory/WORKSPACE.md +7 -0
- package/templates/contextkit/memory/business-rules/_TEMPLATE.md +33 -0
- package/templates/contextkit/memory/decisions/0000-record-architecture-decisions.md +34 -0
- package/templates/contextkit/memory/decisions/_TEMPLATE.md +25 -0
- package/templates/contextkit/memory/predictions/.gitkeep +0 -0
- package/templates/contextkit/memory/roadmap.md +28 -0
- package/templates/contextkit/memory/sessions/.gitkeep +0 -0
- package/templates/contextkit/memory/workflows/.gitkeep +0 -0
- package/templates/contextkit/pipeline/backlog/.gitkeep +0 -0
- package/templates/contextkit/pipeline/conclusion/.gitkeep +0 -0
- package/templates/contextkit/pipeline/devpipeline.md +9 -0
- package/templates/contextkit/pipeline/testing/.gitkeep +0 -0
- package/templates/contextkit/pipeline/working/.gitkeep +0 -0
- package/templates/contextkit/review-protocol.md +214 -0
- package/templates/contextkit/runtime/config/defaults.mjs +215 -0
- package/templates/contextkit/runtime/config/levels.mjs +42 -0
- package/templates/contextkit/runtime/config/load.mjs +105 -0
- package/templates/contextkit/runtime/config/paths.mjs +92 -0
- package/templates/contextkit/runtime/config/presets.mjs +47 -0
- package/templates/contextkit/runtime/config/schema.mjs +88 -0
- package/templates/contextkit/runtime/config/settings-compose.mjs +55 -0
- package/templates/contextkit/runtime/git-hooks/commit-msg.mjs +55 -0
- package/templates/contextkit/runtime/git-hooks/pre-commit.mjs +47 -0
- package/templates/contextkit/runtime/git-hooks/pre-push.mjs +102 -0
- package/templates/contextkit/runtime/hooks/boot-context-readers.mjs +111 -0
- package/templates/contextkit/runtime/hooks/boot-signals.mjs +135 -0
- package/templates/contextkit/runtime/hooks/check-registration.mjs +228 -0
- package/templates/contextkit/runtime/hooks/concurrency-guard.mjs +110 -0
- package/templates/contextkit/runtime/hooks/ledger.mjs +231 -0
- package/templates/contextkit/runtime/hooks/md-extract.mjs +65 -0
- package/templates/contextkit/runtime/hooks/path-classification.mjs +62 -0
- package/templates/contextkit/runtime/hooks/safe-io.mjs +84 -0
- package/templates/contextkit/runtime/hooks/session-digest-core.mjs +85 -0
- package/templates/contextkit/runtime/hooks/session-start.mjs +248 -0
- package/templates/contextkit/runtime/hooks/simulate-gate.mjs +108 -0
- package/templates/contextkit/runtime/hooks/track-edits.mjs +154 -0
- package/templates/contextkit/runtime/providers/media/_adapter.mjs +120 -0
- package/templates/contextkit/runtime/providers/media/nano-banana.mjs +110 -0
- package/templates/contextkit/runtime/providers/media/veo.mjs +162 -0
- package/templates/contextkit/runtime/providers/review/_adapter.mjs +71 -0
- package/templates/contextkit/runtime/providers/review/detect.mjs +115 -0
- package/templates/contextkit/runtime/providers/review/gh.mjs +103 -0
- package/templates/contextkit/runtime/state/state-io.mjs +172 -0
- package/templates/contextkit/runtime/statusline.mjs +51 -0
- package/templates/contextkit/squads/README.md +115 -0
- package/templates/contextkit/squads/_BRIEFING.md.tpl +27 -0
- package/templates/contextkit/squads/agent-forge/README.md +69 -0
- package/templates/contextkit/squads/agent-forge/ROADMAP.md +108 -0
- package/templates/contextkit/squads/agent-forge/best-practices.md +89 -0
- package/templates/contextkit/squads/agent-forge/cli/forge-admin.mjs +132 -0
- package/templates/contextkit/squads/agent-forge/cli/forge-eval-cli.mjs +163 -0
- package/templates/contextkit/squads/agent-forge/cli/forge-new.mjs +97 -0
- package/templates/contextkit/squads/agent-forge/cli/forge-ops.mjs +177 -0
- package/templates/contextkit/squads/agent-forge/lib/architect.mjs +112 -0
- package/templates/contextkit/squads/agent-forge/lib/eval-designer.mjs +133 -0
- package/templates/contextkit/squads/agent-forge/lib/eval-runner.mjs +167 -0
- package/templates/contextkit/squads/agent-forge/lib/governance-officer.mjs +178 -0
- package/templates/contextkit/squads/agent-forge/lib/package-ops.mjs +101 -0
- package/templates/contextkit/squads/agent-forge/lib/packager.mjs +219 -0
- package/templates/contextkit/squads/agent-forge/lib/prompt-gen.mjs +122 -0
- package/templates/contextkit/squads/agent-forge/lib/rag-designer.mjs +102 -0
- package/templates/contextkit/squads/agent-forge/lib/router.mjs +165 -0
- package/templates/contextkit/squads/agent-forge/lib/tool-gen.mjs +113 -0
- package/templates/contextkit/squads/agent-forge/lib/yaml.mjs +47 -0
- package/templates/contextkit/squads/agent-forge/pipeline.yaml +65 -0
- package/templates/contextkit/squads/agent-forge/router/capability-matrix.json +112 -0
- package/templates/contextkit/squads/agent-forge/router/decision-rules.json +120 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/.agentforgerc +12 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/CHANGELOG.md +13 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/LICENSE +5 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/README.md +39 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/adapters/go/README.md +10 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/adapters/go/agent.go +14 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/adapters/go/go.mod +3 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/adapters/node/README.md +11 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/adapters/node/index.js +53 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/adapters/node/package.json +9 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/adapters/python/README.md +10 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/adapters/python/agent.py +16 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/adapters/python/pyproject.toml +10 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/evals/golden.jsonl +1 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/evals/red-team.jsonl +3 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/evals/rubric.yaml +14 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/evals/run-eval.md +17 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/evals/thresholds.yaml +18 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/examples/basic.node.md +17 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/examples/with-fallback.node.md +24 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/examples/with-rag.python.md +20 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/governance/audit.schema.json +23 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/governance/compliance.policy.yaml +43 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/governance/cost.policy.yaml +36 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/governance/fallback-chain.yaml +16 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/governance/quality.policy.yaml +43 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/manifest.yaml +91 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/prompts/system.anthropic.md +19 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/prompts/system.canonical.md +25 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/prompts/system.deepseek.md +21 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/prompts/system.google.md +19 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/prompts/system.ollama.md +21 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/prompts/system.openai.md +20 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/rag/config.yaml +17 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/rag/index/.gitkeep +3 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/rag/ingestion/chunker.config.yaml +6 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/rag/ingestion/sources.yaml +8 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/rag/retrieval/query-template.md +16 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/rag/retrieval/rerank.config.yaml +6 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/tools/adapters/anthropic.tools.json +11 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/tools/adapters/deepseek.tools.json +14 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/tools/adapters/google.tools.json +11 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/tools/adapters/ollama.tools.json +14 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/tools/adapters/openai.tools.json +14 -0
- package/templates/contextkit/squads/agent-forge/templates/agent-package/tools/schemas.canonical.json +25 -0
- package/templates/contextkit/starters/tanstack/README.md +86 -0
- package/templates/contextkit/starters/tanstack/index.html +12 -0
- package/templates/contextkit/starters/tanstack/package.json +25 -0
- package/templates/contextkit/starters/tanstack/src/main.tsx +40 -0
- package/templates/contextkit/starters/tanstack/src/router.tsx +12 -0
- package/templates/contextkit/starters/tanstack/src/routes/__root.tsx +10 -0
- package/templates/contextkit/starters/tanstack/src/routes/index.tsx +17 -0
- package/templates/contextkit/starters/tanstack/tsconfig.json +19 -0
- package/templates/contextkit/starters/tanstack/vite.config.ts +10 -0
- package/templates/contextkit/tools/scripts/adr-digest-core.mjs +42 -0
- package/templates/contextkit/tools/scripts/adr-digest.mjs +78 -0
- package/templates/contextkit/tools/scripts/agent-tuning.mjs +74 -0
- package/templates/contextkit/tools/scripts/aiso-audit.mjs +174 -0
- package/templates/contextkit/tools/scripts/audit-shared.mjs +129 -0
- package/templates/contextkit/tools/scripts/claim.mjs +133 -0
- package/templates/contextkit/tools/scripts/claude-md.mjs +123 -0
- package/templates/contextkit/tools/scripts/clean-drive.mjs +78 -0
- package/templates/contextkit/tools/scripts/context-config.mjs +111 -0
- package/templates/contextkit/tools/scripts/context-level.mjs +98 -0
- package/templates/contextkit/tools/scripts/context-pack.mjs +120 -0
- package/templates/contextkit/tools/scripts/contract-scan.mjs +186 -0
- package/templates/contextkit/tools/scripts/dashboard-data.mjs +198 -0
- package/templates/contextkit/tools/scripts/dashboard-html.mjs +215 -0
- package/templates/contextkit/tools/scripts/dashboard-server.mjs +129 -0
- package/templates/contextkit/tools/scripts/dashboard.mjs +107 -0
- package/templates/contextkit/tools/scripts/deep-analysis.mjs +62 -0
- package/templates/contextkit/tools/scripts/deps-audit.mjs +201 -0
- package/templates/contextkit/tools/scripts/detect-stack.mjs +164 -0
- package/templates/contextkit/tools/scripts/distill-detect.mjs +90 -0
- package/templates/contextkit/tools/scripts/doctor.mjs +165 -0
- package/templates/contextkit/tools/scripts/fleet.mjs +170 -0
- package/templates/contextkit/tools/scripts/generate-context.mjs +142 -0
- package/templates/contextkit/tools/scripts/gh-alerts.mjs +117 -0
- package/templates/contextkit/tools/scripts/git.mjs +97 -0
- package/templates/contextkit/tools/scripts/home.mjs +106 -0
- package/templates/contextkit/tools/scripts/mark-simulation.mjs +78 -0
- package/templates/contextkit/tools/scripts/media-gen.mjs +154 -0
- package/templates/contextkit/tools/scripts/pipeline-board.mjs +74 -0
- package/templates/contextkit/tools/scripts/pipeline-prioritize.mjs +68 -0
- package/templates/contextkit/tools/scripts/pipeline-session.mjs +99 -0
- package/templates/contextkit/tools/scripts/pipeline-validate.mjs +136 -0
- package/templates/contextkit/tools/scripts/pipeline.mjs +302 -0
- package/templates/contextkit/tools/scripts/playbook.mjs +123 -0
- package/templates/contextkit/tools/scripts/predictions-review.mjs +113 -0
- package/templates/contextkit/tools/scripts/release.mjs +60 -0
- package/templates/contextkit/tools/scripts/resume.mjs +114 -0
- package/templates/contextkit/tools/scripts/roadmap.mjs +86 -0
- package/templates/contextkit/tools/scripts/runs.mjs +116 -0
- package/templates/contextkit/tools/scripts/seo-audit.mjs +150 -0
- package/templates/contextkit/tools/scripts/session-digest.mjs +89 -0
- package/templates/contextkit/tools/scripts/session-reindex.mjs +91 -0
- package/templates/contextkit/tools/scripts/setup-complete.mjs +69 -0
- package/templates/contextkit/tools/scripts/squad-meta.mjs +23 -0
- package/templates/contextkit/tools/scripts/squad-pipeline-condition.mjs +192 -0
- package/templates/contextkit/tools/scripts/squad-pipeline.mjs +301 -0
- package/templates/contextkit/tools/scripts/squad.mjs +80 -0
- package/templates/contextkit/tools/scripts/stats.mjs +138 -0
- package/templates/contextkit/tools/scripts/sync-check.mjs +235 -0
- package/templates/contextkit/tools/scripts/tech-debt-detectors.mjs +76 -0
- package/templates/contextkit/tools/scripts/tech-debt-scan.mjs +164 -0
- package/templates/contextkit/tools/scripts/token-report.mjs +153 -0
- package/templates/contextkit/tools/scripts/visual-test.mjs +132 -0
- package/templates/contextkit/tools/scripts/watch.mjs +106 -0
- package/templates/contextkit/tools/scripts/workflow.mjs +136 -0
- package/templates/contextkit/tools/scripts/workspace-sync.mjs +220 -0
- package/templates/contextkit/tools/scripts/worktree-new.mjs +50 -0
- package/templates/contextkit/workflows/L1-static-loading.md +59 -0
- package/templates/contextkit/workflows/L2-session-ledger.md +86 -0
- package/templates/contextkit/workflows/L3-multi-session.md +80 -0
- package/templates/contextkit/workflows/L4-squads.md +68 -0
- package/templates/contextkit/workflows/L5-proactive.md +88 -0
- package/templates/contextkit/workflows/README.md +47 -0
- package/templates/contextkit/workflows/playbooks/distillation-cycle.md +74 -0
- package/templates/contextkit/workflows/playbooks/landing-page.md +197 -0
- package/templates/contextkit/workflows/playbooks/security-batch.md +68 -0
- package/templates/contextkit/workflows/playbooks/seo-aiso.md +288 -0
- package/templates/contextkit/workflows/playbooks/simulate-impact.md +83 -0
- package/templates/contextkit/workflows/playbooks/tanstack.md +164 -0
- package/templates/contextkit/workflows/playbooks/tech-debt-sweep.md +77 -0
- package/templates/docs/CHANGELOG.md.tpl +11 -0
- package/templates/gitattributes +3 -0
- package/templates/github/ISSUE_TEMPLATE/bug_report.md +30 -0
- package/templates/github/ISSUE_TEMPLATE/feature_request.md +22 -0
- package/templates/github/PULL_REQUEST_TEMPLATE.md +27 -0
- package/templates/github/dependabot.yml +27 -0
- package/templates/github/workflows/quality.yml +36 -0
- package/templates/github/workflows/security.yml +54 -0
- package/tools/install/cli.mjs +62 -0
- package/tools/install/fs.mjs +56 -0
- package/tools/install/git.mjs +114 -0
- package/tools/install/project.mjs +51 -0
- package/tools/install/uninstall.mjs +54 -0
- package/tools/integration-test-compozy.mjs +88 -0
- package/tools/integration-test-guards.mjs +269 -0
- package/tools/integration-test-tooling-agent-forge.mjs +189 -0
- package/tools/integration-test-tooling-pipeline.mjs +164 -0
- package/tools/integration-test-tooling.mjs +172 -0
- package/tools/integration-test.mjs +228 -0
- package/tools/it-helpers.mjs +60 -0
- package/tools/selfcheck-agent-forge-ops.mjs +107 -0
- package/tools/selfcheck-agent-forge.mjs +304 -0
- package/tools/selfcheck-config.mjs +80 -0
- package/tools/selfcheck-runtime.mjs +135 -0
- package/tools/selfcheck-source.mjs +326 -0
- package/tools/selfcheck.mjs +268 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* package-ops — shared helpers for every `/forge-*` maintenance command.
|
|
3
|
+
* Pure + zero-dep on the JSON side; YAML reads are gated on `lib/yaml.mjs`
|
|
4
|
+
* (optional dep, ADR-0013). The `/forge-*` CLIs share these so the inspection
|
|
5
|
+
* + mutation surface stays consistent.
|
|
6
|
+
*
|
|
7
|
+
* The Agent Package directory convention: `<root>/<name>@<semver>/manifest.yaml`.
|
|
8
|
+
* `discoverPackages(root)` walks the registry without loading any YAML — it
|
|
9
|
+
* matches the directory shape — so a missing `yaml` dep does not break listing.
|
|
10
|
+
*/
|
|
11
|
+
import { readdir, readFile, stat } from 'node:fs/promises';
|
|
12
|
+
import { join } from 'node:path';
|
|
13
|
+
|
|
14
|
+
const PKG_RE = /^([a-z][a-z0-9-]*)@(\d+\.\d+\.\d+(?:-[\w.-]+)?)$/;
|
|
15
|
+
|
|
16
|
+
/** List every `<name>@<semver>` directory under `root`. Pure JSON, no YAML needed. */
|
|
17
|
+
export async function discoverPackages(root) {
|
|
18
|
+
const out = [];
|
|
19
|
+
let entries = [];
|
|
20
|
+
try {
|
|
21
|
+
entries = await readdir(root, { withFileTypes: true });
|
|
22
|
+
} catch {
|
|
23
|
+
return out;
|
|
24
|
+
}
|
|
25
|
+
for (const entry of entries) {
|
|
26
|
+
if (!entry.isDirectory()) continue;
|
|
27
|
+
const match = PKG_RE.exec(entry.name);
|
|
28
|
+
if (!match) continue;
|
|
29
|
+
out.push({ name: match[1], version: match[2], path: join(root, entry.name) });
|
|
30
|
+
}
|
|
31
|
+
return out.sort((a, b) => (a.name === b.name ? a.version.localeCompare(b.version) : a.name.localeCompare(b.name)));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Read `manifest.yaml` for one package via the optional yaml dep (ADR-0013). */
|
|
35
|
+
export async function loadManifest(pkgPath) {
|
|
36
|
+
const { parseYaml } = await import('./yaml.mjs');
|
|
37
|
+
const raw = await readFile(join(pkgPath, 'manifest.yaml'), 'utf-8');
|
|
38
|
+
return parseYaml(raw);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Read `.agentforgerc` (zero-dep JSON; reports `null` if the file is missing). */
|
|
42
|
+
export async function loadProvenance(pkgPath) {
|
|
43
|
+
try {
|
|
44
|
+
const raw = await readFile(join(pkgPath, '.agentforgerc'), 'utf-8');
|
|
45
|
+
return JSON.parse(raw.replace(/^/, ''));
|
|
46
|
+
} catch {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** One-line summary suitable for `/forge-list` output, derived from manifest + provenance. */
|
|
52
|
+
export function summarize(pkg, manifest, provenance) {
|
|
53
|
+
const primary = manifest?.spec?.model_selection?.primary;
|
|
54
|
+
const primaryId = primary ? `${primary.provider}/${primary.model}` : '?';
|
|
55
|
+
const evalStamped = manifest?.metadata?.provenance?.eval_passed_at;
|
|
56
|
+
const evalMark = evalStamped ? '✅ eval' : '⚠️ unevaluated';
|
|
57
|
+
return `${pkg.name}@${pkg.version} ${primaryId} ${evalMark}` + (provenance?.provenance?.eval_run ? ` (run ${provenance.provenance.eval_run})` : '');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Doctor: structural checks against an APF directory. Returns `{ ok, problems[] }`. */
|
|
61
|
+
export async function diagnosePackage(pkgPath) {
|
|
62
|
+
const problems = [];
|
|
63
|
+
const expectedFiles = ['manifest.yaml', 'README.md', '.agentforgerc',
|
|
64
|
+
'prompts/system.canonical.md', 'tools/schemas.canonical.json',
|
|
65
|
+
'governance/cost.policy.yaml', 'governance/compliance.policy.yaml',
|
|
66
|
+
'governance/quality.policy.yaml', 'governance/fallback-chain.yaml',
|
|
67
|
+
'evals/golden.jsonl', 'evals/thresholds.yaml'];
|
|
68
|
+
for (const rel of expectedFiles) {
|
|
69
|
+
try {
|
|
70
|
+
await stat(join(pkgPath, rel));
|
|
71
|
+
} catch {
|
|
72
|
+
problems.push(`missing: ${rel}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
for (const rel of ['governance/cost.policy.yaml', 'governance/compliance.policy.yaml', 'governance/quality.policy.yaml']) {
|
|
76
|
+
try {
|
|
77
|
+
const body = await readFile(join(pkgPath, rel), 'utf-8');
|
|
78
|
+
if (body.includes('{{') && body.includes('}}')) problems.push(`${rel} still carries {{TOKEN}} placeholders`);
|
|
79
|
+
} catch {
|
|
80
|
+
/* already reported above */
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return { ok: problems.length === 0, problems };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Compose the aggregate monthly budget across every package — for `/forge-budget`. */
|
|
87
|
+
export function aggregateBudgets(manifests) {
|
|
88
|
+
let target = 0;
|
|
89
|
+
let hardCap = 0;
|
|
90
|
+
const perAgent = [];
|
|
91
|
+
for (const manifest of manifests) {
|
|
92
|
+
const cost = manifest?.spec?.cost ?? {};
|
|
93
|
+
const monthlyTarget = Number(cost.monthly_budget_usd ?? 0);
|
|
94
|
+
const perCallCap = Number(cost.max_usd_per_call ?? 0);
|
|
95
|
+
const monthlyCap = Math.round(monthlyTarget * 1.5);
|
|
96
|
+
target += monthlyTarget;
|
|
97
|
+
hardCap += monthlyCap;
|
|
98
|
+
perAgent.push({ name: manifest?.metadata?.name, target: monthlyTarget, hardCap: monthlyCap, perCallCap });
|
|
99
|
+
}
|
|
100
|
+
return { totals: { monthly_target_usd: target, monthly_hard_cap_usd: hardCap }, perAgent };
|
|
101
|
+
}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* packager — assembles the Agent Package (APF v1) for a routed blueprint. Reads the
|
|
3
|
+
* APF template tree, writes a stamped copy to the target dir, generates per-provider
|
|
4
|
+
* prompts + tool adapters, and stamps provenance (blueprint hash, forge version,
|
|
5
|
+
* timestamp) into the manifest.
|
|
6
|
+
*
|
|
7
|
+
* Split:
|
|
8
|
+
* - `assembleManifest(blueprint, decision)` — pure, returns the in-memory manifest
|
|
9
|
+
* object. No I/O, no YAML dep — exercised by the unit tests.
|
|
10
|
+
* - `packageAgent(blueprint, decision, targetDir)` — full I/O: depends on the optional
|
|
11
|
+
* `yaml` dep via `lib/yaml.mjs` (ADR-0013) to serialize the manifest. Required at
|
|
12
|
+
* packaging time; not required to import this module.
|
|
13
|
+
*/
|
|
14
|
+
import { copyFile, mkdir, readdir, readFile, writeFile } from 'node:fs/promises';
|
|
15
|
+
import { dirname, join, resolve } from 'node:path';
|
|
16
|
+
import { fileURLToPath } from 'node:url';
|
|
17
|
+
import { blueprintHash } from './architect.mjs';
|
|
18
|
+
import { designEvalSet, toJsonl } from './eval-designer.mjs';
|
|
19
|
+
import { attachGovernance } from './governance-officer.mjs';
|
|
20
|
+
import { generatePrompts } from './prompt-gen.mjs';
|
|
21
|
+
import { designRagConfig } from './rag-designer.mjs';
|
|
22
|
+
import { generateAdapters } from './tool-gen.mjs';
|
|
23
|
+
|
|
24
|
+
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
25
|
+
const APF_TEMPLATE = resolve(HERE, '..', 'templates', 'agent-package');
|
|
26
|
+
const FORGE_VERSION = '0.1.0';
|
|
27
|
+
|
|
28
|
+
function splitId(fullId) {
|
|
29
|
+
const [provider, ...rest] = String(fullId).split('/');
|
|
30
|
+
return { provider, model: rest.join('/') };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Build the manifest object in memory. Pure, deterministic when `opts.now` is fixed.
|
|
35
|
+
* The YAML serializer is called by `packageAgent`; tests should call this directly
|
|
36
|
+
* to inspect structure without needing the `yaml` dep.
|
|
37
|
+
*/
|
|
38
|
+
export function assembleManifest(blueprint, decision, opts = {}) {
|
|
39
|
+
const now = opts.now ?? new Date().toISOString();
|
|
40
|
+
const today = now.slice(0, 10);
|
|
41
|
+
const primary = splitId(decision.primary);
|
|
42
|
+
const fallback = decision.fallback
|
|
43
|
+
? { ...splitId(decision.fallback), condition: 'primary_5xx OR primary_timeout' }
|
|
44
|
+
: null;
|
|
45
|
+
const cheap = decision.cheap_path ? splitId(decision.cheap_path) : null;
|
|
46
|
+
const premium = decision.premium_path ? splitId(decision.premium_path) : null;
|
|
47
|
+
return {
|
|
48
|
+
apiVersion: 'agentforge.contextdevkit.io/v1',
|
|
49
|
+
kind: 'Agent',
|
|
50
|
+
metadata: {
|
|
51
|
+
name: blueprint.agent_name,
|
|
52
|
+
version: opts.version ?? '0.1.0',
|
|
53
|
+
description: blueprint.role_one_line,
|
|
54
|
+
author: blueprint.author || 'unknown',
|
|
55
|
+
created: today,
|
|
56
|
+
provenance: {
|
|
57
|
+
forged_by: `agent-forge@${opts.forgeVersion ?? FORGE_VERSION}`,
|
|
58
|
+
blueprint_hash: blueprintHash(blueprint),
|
|
59
|
+
eval_passed_at: opts.evalResult?.verdict === 'pass' ? (opts.evalPassedAt ?? now) : null,
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
spec: {
|
|
63
|
+
intent: blueprint.intent,
|
|
64
|
+
sla: blueprint.sla,
|
|
65
|
+
cost: blueprint.cost,
|
|
66
|
+
volume: blueprint.volume,
|
|
67
|
+
privacy: blueprint.privacy,
|
|
68
|
+
capabilities: blueprint.capabilities,
|
|
69
|
+
model_selection: {
|
|
70
|
+
primary: { ...primary, temperature: 0, max_tokens: 4000 },
|
|
71
|
+
...(fallback ? { fallback: [fallback] } : {}),
|
|
72
|
+
...(cheap ? { cheap_path: cheap } : {}),
|
|
73
|
+
...(premium ? { premium_path: premium } : {}),
|
|
74
|
+
rules_applied: decision.applied_rules ?? [],
|
|
75
|
+
},
|
|
76
|
+
evals: { golden: 'evals/golden.jsonl', thresholds: 'evals/thresholds.yaml' },
|
|
77
|
+
governance: {
|
|
78
|
+
cost: 'governance/cost.policy.yaml',
|
|
79
|
+
compliance: 'governance/compliance.policy.yaml',
|
|
80
|
+
quality: 'governance/quality.policy.yaml',
|
|
81
|
+
fallback: 'governance/fallback-chain.yaml',
|
|
82
|
+
},
|
|
83
|
+
runtime_adapters: opts.runtimeAdapters ?? blueprint.runtime_adapters ?? ['node'],
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async function copyTree(src, dest) {
|
|
89
|
+
await mkdir(dest, { recursive: true });
|
|
90
|
+
for (const entry of await readdir(src, { withFileTypes: true })) {
|
|
91
|
+
const s = join(src, entry.name);
|
|
92
|
+
const d = join(dest, entry.name);
|
|
93
|
+
if (entry.isDirectory()) await copyTree(s, d);
|
|
94
|
+
else await copyFile(s, d);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async function writeText(p, body) {
|
|
99
|
+
await mkdir(dirname(p), { recursive: true });
|
|
100
|
+
await writeFile(p, body);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Replace the README's Model Selection Rationale section body with the router's output. */
|
|
104
|
+
function stampReadme(readme, decision) {
|
|
105
|
+
const sectionRe = /## Model Selection Rationale[\s\S]*?(?=\n## )/;
|
|
106
|
+
if (sectionRe.test(readme)) return readme.replace(sectionRe, decision.rationale.trim() + '\n\n');
|
|
107
|
+
return readme + '\n\n' + decision.rationale + '\n';
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Write a complete Agent Package to `targetDir`. Requires the `yaml` dep (ADR-0013)
|
|
112
|
+
* at runtime; throws a clear, actionable error via `loadYaml` if absent.
|
|
113
|
+
*/
|
|
114
|
+
export async function packageAgent(blueprint, decision, targetDir, opts = {}) {
|
|
115
|
+
const governance = attachGovernance(blueprint, decision);
|
|
116
|
+
const evalSet = designEvalSet(blueprint);
|
|
117
|
+
|
|
118
|
+
const { stringifyYaml } = await import('./yaml.mjs');
|
|
119
|
+
await copyTree(APF_TEMPLATE, targetDir);
|
|
120
|
+
|
|
121
|
+
const manifest = assembleManifest(blueprint, decision, opts);
|
|
122
|
+
await writeText(join(targetDir, 'manifest.yaml'), await stringifyYaml(manifest));
|
|
123
|
+
|
|
124
|
+
await writeText(join(targetDir, 'evals/golden.jsonl'), toJsonl(evalSet.golden));
|
|
125
|
+
await writeText(join(targetDir, 'evals/red-team.jsonl'), toJsonl(evalSet.redTeam));
|
|
126
|
+
await writeText(join(targetDir, 'evals/rubric.yaml'), await stringifyYaml(evalSet.rubric));
|
|
127
|
+
await writeText(join(targetDir, 'evals/thresholds.yaml'), await stringifyYaml(evalSet.thresholds));
|
|
128
|
+
|
|
129
|
+
await writeText(join(targetDir, 'governance/cost.policy.yaml'), await stringifyYaml(governance.cost));
|
|
130
|
+
await writeText(join(targetDir, 'governance/compliance.policy.yaml'), await stringifyYaml(governance.compliance));
|
|
131
|
+
await writeText(join(targetDir, 'governance/quality.policy.yaml'), await stringifyYaml(governance.quality));
|
|
132
|
+
await writeText(join(targetDir, 'governance/fallback-chain.yaml'), await stringifyYaml(governance.fallback));
|
|
133
|
+
|
|
134
|
+
let rag = null;
|
|
135
|
+
if (blueprint?.capabilities?.rag === true) {
|
|
136
|
+
rag = designRagConfig(blueprint);
|
|
137
|
+
await writeText(join(targetDir, 'rag/config.yaml'), await stringifyYaml(rag.config));
|
|
138
|
+
await writeText(join(targetDir, 'rag/ingestion/chunker.config.yaml'), await stringifyYaml(rag.chunker));
|
|
139
|
+
await writeText(join(targetDir, 'rag/ingestion/sources.yaml'), await stringifyYaml(rag.sources));
|
|
140
|
+
await writeText(join(targetDir, 'rag/retrieval/query-template.md'), rag.queryTemplate);
|
|
141
|
+
await writeText(join(targetDir, 'rag/retrieval/rerank.config.yaml'), await stringifyYaml(rag.rerank));
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const canonicalPrompt = await readFile(join(targetDir, 'prompts/system.canonical.md'), 'utf-8');
|
|
145
|
+
const prompts = generatePrompts(canonicalPrompt);
|
|
146
|
+
await writeText(join(targetDir, 'prompts/system.anthropic.md'), prompts.anthropic);
|
|
147
|
+
await writeText(join(targetDir, 'prompts/system.openai.md'), prompts.openai);
|
|
148
|
+
await writeText(join(targetDir, 'prompts/system.google.md'), prompts.google);
|
|
149
|
+
await writeText(join(targetDir, 'prompts/system.deepseek.md'), prompts.deepseek);
|
|
150
|
+
await writeText(join(targetDir, 'prompts/system.ollama.md'), prompts.ollama);
|
|
151
|
+
|
|
152
|
+
const canonicalTools = JSON.parse((await readFile(join(targetDir, 'tools/schemas.canonical.json'), 'utf-8')).replace(/^/, ''));
|
|
153
|
+
const adapters = generateAdapters(canonicalTools);
|
|
154
|
+
await writeText(join(targetDir, 'tools/adapters/anthropic.tools.json'), JSON.stringify(adapters.anthropic, null, 2) + '\n');
|
|
155
|
+
await writeText(join(targetDir, 'tools/adapters/openai.tools.json'), JSON.stringify(adapters.openai, null, 2) + '\n');
|
|
156
|
+
await writeText(join(targetDir, 'tools/adapters/google.tools.json'), JSON.stringify(adapters.google, null, 2) + '\n');
|
|
157
|
+
await writeText(join(targetDir, 'tools/adapters/deepseek.tools.json'), JSON.stringify(adapters.deepseek, null, 2) + '\n');
|
|
158
|
+
await writeText(join(targetDir, 'tools/adapters/ollama.tools.json'), JSON.stringify(adapters.ollama, null, 2) + '\n');
|
|
159
|
+
|
|
160
|
+
const readmePath = join(targetDir, 'README.md');
|
|
161
|
+
await writeText(readmePath, stampReadme(await readFile(readmePath, 'utf-8'), decision));
|
|
162
|
+
|
|
163
|
+
await stampRuntimeAdapters(targetDir, blueprint, manifest.spec.runtime_adapters);
|
|
164
|
+
|
|
165
|
+
return {
|
|
166
|
+
targetDir,
|
|
167
|
+
manifest,
|
|
168
|
+
files_written: ['manifest.yaml',
|
|
169
|
+
'prompts/system.anthropic.md', 'prompts/system.openai.md',
|
|
170
|
+
'prompts/system.google.md', 'prompts/system.deepseek.md', 'prompts/system.ollama.md',
|
|
171
|
+
'tools/adapters/anthropic.tools.json', 'tools/adapters/openai.tools.json',
|
|
172
|
+
'tools/adapters/google.tools.json', 'tools/adapters/deepseek.tools.json',
|
|
173
|
+
'tools/adapters/ollama.tools.json',
|
|
174
|
+
'evals/golden.jsonl', 'evals/red-team.jsonl', 'evals/rubric.yaml', 'evals/thresholds.yaml',
|
|
175
|
+
'governance/cost.policy.yaml', 'governance/compliance.policy.yaml',
|
|
176
|
+
'governance/quality.policy.yaml', 'governance/fallback-chain.yaml',
|
|
177
|
+
'README.md'],
|
|
178
|
+
provenance: manifest.metadata.provenance,
|
|
179
|
+
governance,
|
|
180
|
+
evalSet,
|
|
181
|
+
rag,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Replace `{{AGENT_NAME}}` (and the project version) in the Node + Python adapter
|
|
187
|
+
* manifests when those runtimes are requested. Pure I/O: no behavioural change to
|
|
188
|
+
* the adapter logic, just removes the literal placeholders so the package installs
|
|
189
|
+
* cleanly. Stays best-effort — a missing adapter dir is ignored.
|
|
190
|
+
*/
|
|
191
|
+
async function stampRuntimeAdapters(targetDir, blueprint, runtimes) {
|
|
192
|
+
const name = blueprint.agent_name;
|
|
193
|
+
const modulePath = blueprint?.go_module_path || 'example.com';
|
|
194
|
+
const subs = (text) => String(text)
|
|
195
|
+
.replaceAll('{{AGENT_NAME}}', name)
|
|
196
|
+
.replaceAll('{{SEE_LICENSE}}', 'UNLICENSED')
|
|
197
|
+
.replaceAll('{{MODULE_PATH}}', modulePath)
|
|
198
|
+
.replaceAll('{{1.22}}', '1.22')
|
|
199
|
+
.replaceAll('{{3.10}}', '3.10');
|
|
200
|
+
const safeStamp = async (path) => {
|
|
201
|
+
try {
|
|
202
|
+
await writeText(path, subs(await readFile(path, 'utf-8')));
|
|
203
|
+
} catch {
|
|
204
|
+
/* adapter dir absent or unreadable — ignore */
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
if (runtimes?.includes('node')) {
|
|
208
|
+
await safeStamp(join(targetDir, 'adapters/node/package.json'));
|
|
209
|
+
await safeStamp(join(targetDir, 'adapters/node/README.md'));
|
|
210
|
+
}
|
|
211
|
+
if (runtimes?.includes('python')) {
|
|
212
|
+
await safeStamp(join(targetDir, 'adapters/python/pyproject.toml'));
|
|
213
|
+
await safeStamp(join(targetDir, 'adapters/python/README.md'));
|
|
214
|
+
}
|
|
215
|
+
if (runtimes?.includes('go')) {
|
|
216
|
+
await safeStamp(join(targetDir, 'adapters/go/go.mod'));
|
|
217
|
+
await safeStamp(join(targetDir, 'adapters/go/README.md'));
|
|
218
|
+
}
|
|
219
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* prompt-engineer — render the canonical system prompt to per-provider variants.
|
|
3
|
+
* Fase 1 shipped Anthropic + OpenAI; Fase 2 adds Gemini, DeepSeek, Ollama through
|
|
4
|
+
* the same section map. Pure + zero-dep — no LLM call at this layer.
|
|
5
|
+
*
|
|
6
|
+
* Canonical sections (the single source of truth) live in `prompts/system.canonical.md`:
|
|
7
|
+
* `# Role` · `# Context` · `# Rules` · `# Output` · `# Examples`
|
|
8
|
+
*
|
|
9
|
+
* - Anthropic: separate `system` param, XML sections, `cache_control: ephemeral` on
|
|
10
|
+
* the stable Context block.
|
|
11
|
+
* - OpenAI: first `system` message, Markdown headings (`# Role` then `## Section`).
|
|
12
|
+
* o-series models take no system message — the runtime adapter folds it into the
|
|
13
|
+
* first user turn (out of scope for the prompt renderer).
|
|
14
|
+
* - Google (Gemini): `systemInstruction` body, Markdown + few-shot. safetySettings
|
|
15
|
+
* are a REQUEST-level concern, not embedded here.
|
|
16
|
+
* - DeepSeek: OpenAI-compatible body that prepends an explicit CoT cue to Rules
|
|
17
|
+
* ("Think step by step before answering") — reasoner variants return
|
|
18
|
+
* `reasoning_content` separately.
|
|
19
|
+
* - Ollama / vLLM (self-hosted): plain Markdown body; the per-model chat_template
|
|
20
|
+
* (Llama 3 / Mistral / Qwen) is applied by the runtime, not here.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
const SECTION_RE = /^#\s+(\w[\w-]*)\s*$/;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Split canonical Markdown into a `{ role, context, rules, output, examples }` map.
|
|
27
|
+
* Comment blocks at the very top (HTML comments before the first `# Section`) are
|
|
28
|
+
* dropped — they're authoring notes, not part of the prompt.
|
|
29
|
+
*/
|
|
30
|
+
export function extractSections(canonical) {
|
|
31
|
+
const lines = String(canonical).split('\n');
|
|
32
|
+
const sections = {};
|
|
33
|
+
let current = null;
|
|
34
|
+
let buf = [];
|
|
35
|
+
const flush = () => {
|
|
36
|
+
if (current) sections[current] = (sections[current] ? sections[current] + '\n' : '') + buf.join('\n').trim();
|
|
37
|
+
buf = [];
|
|
38
|
+
};
|
|
39
|
+
for (const line of lines) {
|
|
40
|
+
const match = SECTION_RE.exec(line);
|
|
41
|
+
if (match) {
|
|
42
|
+
flush();
|
|
43
|
+
current = match[1].toLowerCase();
|
|
44
|
+
} else if (current) {
|
|
45
|
+
buf.push(line);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
flush();
|
|
49
|
+
return sections;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Anthropic system-prompt form: XML sections, ephemeral cache on Context. */
|
|
53
|
+
export function renderAnthropic(sections) {
|
|
54
|
+
const lines = ['<!-- Generated by agent-forge prompt-engineer (Fase 1) from system.canonical.md. Do not hand-edit. -->'];
|
|
55
|
+
if (sections.role) lines.push(`<role>${sections.role}</role>`);
|
|
56
|
+
if (sections.context) lines.push('', '<context cache="ephemeral">', sections.context, '</context>');
|
|
57
|
+
if (sections.rules) lines.push('', '<rules>', sections.rules, '</rules>');
|
|
58
|
+
if (sections.output) lines.push('', '<output>', sections.output, '</output>');
|
|
59
|
+
if (sections.examples) lines.push('', '<examples>', sections.examples, '</examples>');
|
|
60
|
+
return lines.join('\n') + '\n';
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** OpenAI system-message form: Markdown with `# Role` then `## Sections`. */
|
|
64
|
+
export function renderOpenAI(sections) {
|
|
65
|
+
const lines = ['<!-- Generated by agent-forge prompt-engineer (Fase 1) from system.canonical.md. Do not hand-edit. -->'];
|
|
66
|
+
if (sections.role) lines.push('# Role', sections.role);
|
|
67
|
+
if (sections.context) lines.push('', '## Context', sections.context);
|
|
68
|
+
if (sections.rules) lines.push('', '## Rules', sections.rules);
|
|
69
|
+
if (sections.output) lines.push('', '## Output', sections.output);
|
|
70
|
+
if (sections.examples) lines.push('', '## Examples', sections.examples);
|
|
71
|
+
return lines.join('\n') + '\n';
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Google (Gemini): Markdown body for `systemInstruction`. */
|
|
75
|
+
export function renderGoogle(sections) {
|
|
76
|
+
const lines = ['<!-- Generated by agent-forge prompt-engineer (Fase 2) from system.canonical.md. Do not hand-edit. -->'];
|
|
77
|
+
lines.push('<!-- NOTE: safetySettings are configured on the REQUEST; this is the systemInstruction body only. -->');
|
|
78
|
+
if (sections.role) lines.push('# Role', sections.role);
|
|
79
|
+
if (sections.context) lines.push('', '## Context', sections.context);
|
|
80
|
+
if (sections.rules) lines.push('', '## Rules', sections.rules);
|
|
81
|
+
if (sections.output) lines.push('', '## Output', sections.output);
|
|
82
|
+
if (sections.examples) lines.push('', '## Examples (few-shot)', sections.examples);
|
|
83
|
+
return lines.join('\n') + '\n';
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** DeepSeek: OpenAI-compatible body that prepends an explicit CoT cue to Rules. */
|
|
87
|
+
export function renderDeepSeek(sections) {
|
|
88
|
+
const lines = ['<!-- Generated by agent-forge prompt-engineer (Fase 2) from system.canonical.md. Do not hand-edit. -->'];
|
|
89
|
+
if (sections.role) lines.push('# Role', sections.role);
|
|
90
|
+
if (sections.context) lines.push('', '## Context', sections.context);
|
|
91
|
+
const cot = '- Think step by step before answering.';
|
|
92
|
+
const rulesBody = sections.rules ? cot + '\n' + sections.rules : cot;
|
|
93
|
+
lines.push('', '## Rules', rulesBody);
|
|
94
|
+
if (sections.output) lines.push('', '## Output', sections.output);
|
|
95
|
+
if (sections.examples) lines.push('', '## Examples', sections.examples);
|
|
96
|
+
return lines.join('\n') + '\n';
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** Self-hosted (Ollama/vLLM): plain Markdown; chat_template applied by the runtime. */
|
|
100
|
+
export function renderOllama(sections) {
|
|
101
|
+
const lines = ['<!-- Generated by agent-forge prompt-engineer (Fase 2) from system.canonical.md. Do not hand-edit. -->'];
|
|
102
|
+
lines.push('<!-- NOTE: the per-model chat_template (Llama 3 / Mistral / Qwen) is applied by the runtime, not here. -->');
|
|
103
|
+
if (sections.role) lines.push('# Role', sections.role);
|
|
104
|
+
if (sections.context) lines.push('', '## Context', sections.context);
|
|
105
|
+
if (sections.rules) lines.push('', '## Rules', sections.rules);
|
|
106
|
+
if (sections.output) lines.push('', '## Output', sections.output);
|
|
107
|
+
if (sections.examples) lines.push('', '## Examples', sections.examples);
|
|
108
|
+
return lines.join('\n') + '\n';
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** One-stop renderer; returns `{ sections, anthropic, openai, google, deepseek, ollama }`. */
|
|
112
|
+
export function generatePrompts(canonical) {
|
|
113
|
+
const sections = extractSections(canonical);
|
|
114
|
+
return {
|
|
115
|
+
sections,
|
|
116
|
+
anthropic: renderAnthropic(sections),
|
|
117
|
+
openai: renderOpenAI(sections),
|
|
118
|
+
google: renderGoogle(sections),
|
|
119
|
+
deepseek: renderDeepSeek(sections),
|
|
120
|
+
ollama: renderOllama(sections),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* rag-designer — produces the `rag/` config bundle (chunker, embedding, index,
|
|
3
|
+
* retrieval, optional reranker) when the blueprint declares `capabilities.rag`.
|
|
4
|
+
* Pure + zero-dep (rule 1). Deterministic heuristics shaped by the blueprint:
|
|
5
|
+
*
|
|
6
|
+
* - **Embedding model.** Multilingual (`multilingual-e5`) by default; switched to
|
|
7
|
+
* English-only (`text-embedding-3-large`) when `intent.domain` ends in `-en`.
|
|
8
|
+
* - **Index backend.** `pgvector` when `privacy.data_residency: on-prem` /
|
|
9
|
+
* `allow_cloud_providers: false`; `qdrant` otherwise — both are commodity, dev
|
|
10
|
+
* swaps via `manifest.yaml` if a different backend is already in place.
|
|
11
|
+
* - **Chunking.** Recursive 512/64 by default; tightened to 256/32 for `extraction`
|
|
12
|
+
* where boundary precision matters more than context width.
|
|
13
|
+
* - **Hybrid search + reranker** on by default — the cost is small at retrieval-time
|
|
14
|
+
* and the precision lift is large; can be flipped off in the manifest later.
|
|
15
|
+
* - **`top_k` and `min_score`.** Derived from `intent.complexity` — higher complexity
|
|
16
|
+
* keeps more candidates and lowers the score floor.
|
|
17
|
+
*
|
|
18
|
+
* The packager calls `designRagConfig(blueprint)` only when `capabilities.rag === true`;
|
|
19
|
+
* it serializes the four returned objects into the RAG template files.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
const MULTILINGUAL = 'multilingual-e5';
|
|
23
|
+
const ENGLISH = 'text-embedding-3-large';
|
|
24
|
+
|
|
25
|
+
function pickEmbedding(blueprint) {
|
|
26
|
+
const domain = String(blueprint?.intent?.domain || '').toLowerCase();
|
|
27
|
+
return domain.endsWith('-en') ? { model: ENGLISH, dimensions: 3072 } : { model: MULTILINGUAL, dimensions: 1024 };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function pickIndexBackend(blueprint) {
|
|
31
|
+
const allowsCloud = blueprint?.privacy?.allow_cloud_providers !== false;
|
|
32
|
+
const residency = blueprint?.privacy?.data_residency;
|
|
33
|
+
if (!allowsCloud || residency === 'on-prem') return 'pgvector';
|
|
34
|
+
return 'qdrant';
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function pickChunking(blueprint) {
|
|
38
|
+
const category = blueprint?.intent?.category;
|
|
39
|
+
if (category === 'extraction') return { strategy: 'recursive', chunk_size_tokens: 256, chunk_overlap_tokens: 32, respect_boundaries: ['heading', 'paragraph'], keep_metadata: ['source', 'section', 'page'] };
|
|
40
|
+
return { strategy: 'recursive', chunk_size_tokens: 512, chunk_overlap_tokens: 64, respect_boundaries: ['heading', 'paragraph'], keep_metadata: ['source', 'section', 'page'] };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function pickRetrieval(blueprint) {
|
|
44
|
+
const complexity = blueprint?.intent?.complexity || 'medium';
|
|
45
|
+
const topK = complexity === 'high' ? 12 : complexity === 'low' ? 6 : 8;
|
|
46
|
+
const minScore = complexity === 'high' ? 0.25 : 0.30;
|
|
47
|
+
return { top_k: topK, min_score: minScore, hybrid_search: true, rerank: true };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function buildSources(blueprint) {
|
|
51
|
+
return {
|
|
52
|
+
sources: [{
|
|
53
|
+
id: `${blueprint?.agent_name || 'agent'}-knowledge`,
|
|
54
|
+
type: 'filesystem',
|
|
55
|
+
location: './knowledge',
|
|
56
|
+
include: ['**/*.{md,pdf,txt}'],
|
|
57
|
+
refresh: 'manual',
|
|
58
|
+
}],
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function buildRerank() {
|
|
63
|
+
return { enabled: true, model: 'bge-reranker-v2-m3', top_n_after_rerank: 4, min_score: 0.50 };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function buildQueryTemplate() {
|
|
67
|
+
return [
|
|
68
|
+
'<!-- How the user query is turned into a retrieval query + how context is injected. -->',
|
|
69
|
+
'',
|
|
70
|
+
'## Retrieval query',
|
|
71
|
+
'Strip PII, expand acronyms, and keep the original wording. The architect can override',
|
|
72
|
+
'this by hand-editing the file — the runtime adapter reads it verbatim.',
|
|
73
|
+
'',
|
|
74
|
+
'## Context injection',
|
|
75
|
+
'Inject the top-k chunks as:',
|
|
76
|
+
'',
|
|
77
|
+
'```',
|
|
78
|
+
'<context>',
|
|
79
|
+
'{{retrieved_chunks}}',
|
|
80
|
+
'</context>',
|
|
81
|
+
'```',
|
|
82
|
+
'',
|
|
83
|
+
'Instruct the model to answer ONLY from `<context>` and to say when the answer is not',
|
|
84
|
+
'present (faithfulness > fluency).',
|
|
85
|
+
'',
|
|
86
|
+
].join('\n');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** One-stop designer for the RAG bundle. Returns the four artefacts the packager writes. */
|
|
90
|
+
export function designRagConfig(blueprint) {
|
|
91
|
+
return {
|
|
92
|
+
config: {
|
|
93
|
+
embedding: pickEmbedding(blueprint),
|
|
94
|
+
index: { backend: pickIndexBackend(blueprint), metric: 'cosine' },
|
|
95
|
+
retrieval: pickRetrieval(blueprint),
|
|
96
|
+
},
|
|
97
|
+
chunker: pickChunking(blueprint),
|
|
98
|
+
sources: buildSources(blueprint),
|
|
99
|
+
rerank: buildRerank(),
|
|
100
|
+
queryTemplate: buildQueryTemplate(),
|
|
101
|
+
};
|
|
102
|
+
}
|