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,132 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* forge-admin — the *mutating* maintenance CLI for forged Agent Packages.
|
|
4
|
+
* Every subcommand here CHANGES state, so each is dry-run by default; pass
|
|
5
|
+
* `--write` to actually apply.
|
|
6
|
+
*
|
|
7
|
+
* Subcommands:
|
|
8
|
+
* refresh-matrix — bumps `router/capability-matrix.json` `updated` + reports drift
|
|
9
|
+
* killswitch <agent> [on|off] — toggles `kill_switch.enabled` in quality.policy.yaml
|
|
10
|
+
* deprecate <agent> — stamps `metadata.deprecated_at` into manifest + writes an ADR stub
|
|
11
|
+
*
|
|
12
|
+
* All mutations are atomic (tmp-file + rename) per the kit's safe-io discipline.
|
|
13
|
+
*/
|
|
14
|
+
import { mkdir, readFile, rename, writeFile } from 'node:fs/promises';
|
|
15
|
+
import { dirname, join, resolve } from 'node:path';
|
|
16
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
17
|
+
import { discoverPackages } from '../lib/package-ops.mjs';
|
|
18
|
+
|
|
19
|
+
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
20
|
+
const MATRIX_PATH = resolve(HERE, '..', 'router', 'capability-matrix.json');
|
|
21
|
+
|
|
22
|
+
function parseArgs(argv) {
|
|
23
|
+
const args = { sub: argv[0], target: null, mode: null, root: 'agent-packages', write: false, json: false };
|
|
24
|
+
for (let i = 1; i < argv.length; i++) {
|
|
25
|
+
const flag = argv[i];
|
|
26
|
+
if (flag === '--root') args.root = argv[++i];
|
|
27
|
+
else if (flag === '--write') args.write = true;
|
|
28
|
+
else if (flag === '--json') args.json = true;
|
|
29
|
+
else if (!args.target) args.target = flag;
|
|
30
|
+
else if (!args.mode) args.mode = flag;
|
|
31
|
+
}
|
|
32
|
+
return args;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function findOne(pkgs, target) {
|
|
36
|
+
if (!target) throw new Error('this subcommand requires <agent> (or <agent>@<version>)');
|
|
37
|
+
const [name, version] = target.includes('@') ? target.split('@') : [target, null];
|
|
38
|
+
const match = pkgs.find((p) => p.name === name && (!version || p.version === version));
|
|
39
|
+
if (!match) throw new Error(`no package matches "${target}"`);
|
|
40
|
+
return match;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function atomicWrite(path, body) {
|
|
44
|
+
await mkdir(dirname(path), { recursive: true });
|
|
45
|
+
const tmp = path + '.tmp-' + process.pid + '-' + Date.now();
|
|
46
|
+
await writeFile(tmp, body);
|
|
47
|
+
await rename(tmp, path);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async function cmdRefreshMatrix(args) {
|
|
51
|
+
const raw = await readFile(MATRIX_PATH, 'utf-8');
|
|
52
|
+
const matrix = JSON.parse(raw.replace(/^/, ''));
|
|
53
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
54
|
+
const previous = matrix.updated;
|
|
55
|
+
matrix.updated = today;
|
|
56
|
+
const body = JSON.stringify(matrix, null, 2) + '\n';
|
|
57
|
+
if (args.json) return console.log(JSON.stringify({ previous, next: today, models: matrix.models.length, write: args.write }, null, 2));
|
|
58
|
+
console.log(`# Refresh capability-matrix`);
|
|
59
|
+
console.log(`previous : ${previous}`);
|
|
60
|
+
console.log(`next : ${today}`);
|
|
61
|
+
console.log(`models : ${matrix.models.length}`);
|
|
62
|
+
if (!args.write) {
|
|
63
|
+
console.log('\n(dry-run; pass --write to apply. Prices/strengths must be reviewed by hand under an ADR.)');
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
await atomicWrite(MATRIX_PATH, body);
|
|
67
|
+
console.log('✅ matrix.updated stamped. Open an ADR before changing model entries.');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function cmdKillSwitch(args) {
|
|
71
|
+
if (!args.mode || !['on', 'off'].includes(args.mode)) throw new Error('killswitch: pass `on` or `off` after <agent>');
|
|
72
|
+
const pkg = findOne(await discoverPackages(resolve(process.cwd(), args.root)), args.target);
|
|
73
|
+
const path = join(pkg.path, 'governance/quality.policy.yaml');
|
|
74
|
+
const text = await readFile(path, 'utf-8');
|
|
75
|
+
const target = args.mode === 'on' ? 'true' : 'false';
|
|
76
|
+
if (/kill_switch:\s*\n\s*enabled:\s*(true|false)/.test(text)) {
|
|
77
|
+
var next = text.replace(/(kill_switch:\s*\n\s*enabled:\s*)(true|false)/, `$1${target}`);
|
|
78
|
+
} else {
|
|
79
|
+
next = text + `\n# auto-appended by /forge-killswitch\nkill_switch:\n enabled: ${target}\n`;
|
|
80
|
+
}
|
|
81
|
+
if (args.json) return console.log(JSON.stringify({ pkg: pkg.name, mode: args.mode, write: args.write }, null, 2));
|
|
82
|
+
console.log(`# Kill-switch — ${pkg.name}@${pkg.version} → ${args.mode}`);
|
|
83
|
+
if (!args.write) {
|
|
84
|
+
console.log('(dry-run; pass --write to apply.)');
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
await atomicWrite(path, next);
|
|
88
|
+
console.log('✅ kill_switch.enabled = ' + target + ' in ' + path);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async function cmdDeprecate(args) {
|
|
92
|
+
const pkg = findOne(await discoverPackages(resolve(process.cwd(), args.root)), args.target);
|
|
93
|
+
const path = join(pkg.path, 'manifest.yaml');
|
|
94
|
+
const text = await readFile(path, 'utf-8');
|
|
95
|
+
const stamp = new Date().toISOString();
|
|
96
|
+
const marker = ` deprecated_at: '${stamp}'\n`;
|
|
97
|
+
const next = /deprecated_at:/.test(text)
|
|
98
|
+
? text.replace(/(\s*deprecated_at:\s*)['"]?[\d:.TZ+-]+['"]?\n/, `$1'${stamp}'\n`)
|
|
99
|
+
: text.replace(/(metadata:\n)/, `$1${marker}`);
|
|
100
|
+
if (args.json) return console.log(JSON.stringify({ pkg: pkg.name, stamp, write: args.write }, null, 2));
|
|
101
|
+
console.log(`# Deprecate — ${pkg.name}@${pkg.version}`);
|
|
102
|
+
console.log(`stamp : ${stamp}`);
|
|
103
|
+
if (!args.write) {
|
|
104
|
+
console.log('(dry-run; pass --write to apply. /new-adr is recommended to record WHY.)');
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
await atomicWrite(path, next);
|
|
108
|
+
console.log('✅ metadata.deprecated_at stamped. Now run /new-adr to record the reason.');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const HANDLERS = { 'refresh-matrix': cmdRefreshMatrix, killswitch: cmdKillSwitch, deprecate: cmdDeprecate };
|
|
112
|
+
|
|
113
|
+
async function main(argv) {
|
|
114
|
+
const args = parseArgs(argv);
|
|
115
|
+
const handler = HANDLERS[args.sub];
|
|
116
|
+
if (!handler) {
|
|
117
|
+
console.error(`forge-admin: unknown subcommand "${args.sub}". Allowed: ${Object.keys(HANDLERS).join(', ')}`);
|
|
118
|
+
process.exit(1);
|
|
119
|
+
}
|
|
120
|
+
await handler(args);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const HERE_URL = fileURLToPath(import.meta.url);
|
|
124
|
+
const ENTRY = process.argv[1] ? pathToFileURL(resolve(process.argv[1])).href : '';
|
|
125
|
+
if (ENTRY === pathToFileURL(HERE_URL).href) {
|
|
126
|
+
main(process.argv.slice(2)).catch((err) => {
|
|
127
|
+
console.error('forge-admin: ' + (err?.message ?? err));
|
|
128
|
+
process.exit(1);
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export { cmdRefreshMatrix, cmdKillSwitch, cmdDeprecate };
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* forge-eval — runs the eval gate, red-team only, re-routes, or chaos-tests the
|
|
4
|
+
* fallback chain for an existing Agent Package. Requires the optional `yaml` dep
|
|
5
|
+
* to read the package manifest (ADR-0013).
|
|
6
|
+
*
|
|
7
|
+
* Subcommands:
|
|
8
|
+
* eval <agent> — run golden + red-team against the manifest's thresholds
|
|
9
|
+
* redteam <agent> — red-team only (the PII / injection / jailbreak gate)
|
|
10
|
+
* route <agent> — re-execute model-router and diff vs the current manifest
|
|
11
|
+
* fallback-test <agent> — force the fallback chain end-to-end (chaos)
|
|
12
|
+
*
|
|
13
|
+
* Providers come from `--provider <mock|adapter>` — `mock` returns a deterministic
|
|
14
|
+
* always-pass output for CI; `adapter` loads the package's Node runtime adapter
|
|
15
|
+
* and calls the real provider chain (needs credentials).
|
|
16
|
+
*/
|
|
17
|
+
import { resolve } from 'node:path';
|
|
18
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
19
|
+
import { designEvalSet } from '../lib/eval-designer.mjs';
|
|
20
|
+
import { runEvalSuite, runRedTeam } from '../lib/eval-runner.mjs';
|
|
21
|
+
import { routeAgent } from '../lib/router.mjs';
|
|
22
|
+
import { discoverPackages, loadManifest } from '../lib/package-ops.mjs';
|
|
23
|
+
|
|
24
|
+
const MOCK_PROVIDER = (input) => {
|
|
25
|
+
if (input?.text && /CPF|IGNORE|DAN/i.test(input.text)) return { redacted: '[REDACTED]' };
|
|
26
|
+
if (input?.text) return { ok: true };
|
|
27
|
+
return { label: '<class-label>', '<field>': '<value>', answer: '<expected answer>', summary: '<expected summary>', output: '<expected output>', y: 'ok' };
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const CHAOS_PROVIDER_FACTORY = () => {
|
|
31
|
+
let calls = 0;
|
|
32
|
+
return (input) => {
|
|
33
|
+
calls += 1;
|
|
34
|
+
if (calls === 1) throw Object.assign(new Error('simulated 503'), { code: '503' });
|
|
35
|
+
return MOCK_PROVIDER(input);
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
function parseArgs(argv) {
|
|
40
|
+
const args = { sub: argv[0], target: null, root: 'agent-packages', provider: 'mock', json: false };
|
|
41
|
+
for (let i = 1; i < argv.length; i++) {
|
|
42
|
+
const flag = argv[i];
|
|
43
|
+
if (flag === '--root') args.root = argv[++i];
|
|
44
|
+
else if (flag === '--provider') args.provider = argv[++i];
|
|
45
|
+
else if (flag === '--json') args.json = true;
|
|
46
|
+
else if (!args.target) args.target = flag;
|
|
47
|
+
}
|
|
48
|
+
return args;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function findOne(pkgs, target) {
|
|
52
|
+
if (!target) throw new Error('this subcommand requires <agent> (or <agent>@<version>)');
|
|
53
|
+
const [name, version] = target.includes('@') ? target.split('@') : [target, null];
|
|
54
|
+
const match = pkgs.find((p) => p.name === name && (!version || p.version === version));
|
|
55
|
+
if (!match) throw new Error(`no package matches "${target}"`);
|
|
56
|
+
return match;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function resolveProvider(kind) {
|
|
60
|
+
if (kind === 'mock') return { provider: MOCK_PROVIDER };
|
|
61
|
+
if (kind === 'chaos') return { provider: CHAOS_PROVIDER_FACTORY() };
|
|
62
|
+
throw new Error(`unsupported --provider ${kind} (Fase 4 ships mock + chaos; real adapters require credentials and are out of scope here)`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function blueprintFromManifest(manifest) {
|
|
66
|
+
const spec = manifest?.spec ?? {};
|
|
67
|
+
return {
|
|
68
|
+
agent_name: manifest?.metadata?.name,
|
|
69
|
+
intent: spec.intent ?? {},
|
|
70
|
+
sla: spec.sla ?? {},
|
|
71
|
+
cost: spec.cost ?? {},
|
|
72
|
+
privacy: spec.privacy ?? {},
|
|
73
|
+
capabilities: spec.capabilities ?? {},
|
|
74
|
+
runtime_adapters: spec.runtime_adapters ?? ['node'],
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async function cmdEval(args) {
|
|
79
|
+
const pkg = findOne(await discoverPackages(resolve(process.cwd(), args.root)), args.target);
|
|
80
|
+
const manifest = await loadManifest(pkg.path);
|
|
81
|
+
const blueprint = blueprintFromManifest(manifest);
|
|
82
|
+
const evalSet = designEvalSet(blueprint);
|
|
83
|
+
const opts = resolveProvider(args.provider);
|
|
84
|
+
const result = await runEvalSuite(evalSet, opts);
|
|
85
|
+
if (args.json) return console.log(JSON.stringify(result, null, 2));
|
|
86
|
+
console.log(`# Eval — ${pkg.name}@${pkg.version} (provider=${args.provider})`);
|
|
87
|
+
console.log(`verdict : ${result.verdict.toUpperCase()}`);
|
|
88
|
+
console.log(`accuracy : ${result.golden.accuracy.toFixed(2)} on ${result.golden.evaluated}/${result.golden.count} cases`);
|
|
89
|
+
console.log(`red-team : ${JSON.stringify(result.redTeam.rates)}`);
|
|
90
|
+
console.log(`p95 lat : ${result.golden.p95_latency_ms} ms`);
|
|
91
|
+
if (result.verdict === 'fail') {
|
|
92
|
+
console.log('\nfailures:'); for (const reason of result.failures) console.log(` - ${reason}`);
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async function cmdRedTeam(args) {
|
|
98
|
+
const pkg = findOne(await discoverPackages(resolve(process.cwd(), args.root)), args.target);
|
|
99
|
+
const manifest = await loadManifest(pkg.path);
|
|
100
|
+
const evalSet = designEvalSet(blueprintFromManifest(manifest));
|
|
101
|
+
const opts = resolveProvider(args.provider);
|
|
102
|
+
const result = await runRedTeam(evalSet.redTeam, opts);
|
|
103
|
+
if (args.json) return console.log(JSON.stringify(result, null, 2));
|
|
104
|
+
console.log(`# Red-team — ${pkg.name}@${pkg.version} (provider=${args.provider})`);
|
|
105
|
+
for (const [category, rate] of Object.entries(result.rates)) console.log(` ${category} block rate: ${(rate * 100).toFixed(0)}%`);
|
|
106
|
+
if (result.failures.length) {
|
|
107
|
+
console.log('\nleaks:'); for (const entry of result.failures) console.log(` - ${entry.id} (${entry.category}): ${JSON.stringify(entry.verdict)}`);
|
|
108
|
+
process.exit(1);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async function cmdRoute(args) {
|
|
113
|
+
const pkg = findOne(await discoverPackages(resolve(process.cwd(), args.root)), args.target);
|
|
114
|
+
const manifest = await loadManifest(pkg.path);
|
|
115
|
+
const blueprint = blueprintFromManifest(manifest);
|
|
116
|
+
const decision = await routeAgent(blueprint);
|
|
117
|
+
const current = manifest?.spec?.model_selection?.primary;
|
|
118
|
+
const currentId = current ? `${current.provider}/${current.model}` : '?';
|
|
119
|
+
const diff = decision.primary === currentId
|
|
120
|
+
? 'no change'
|
|
121
|
+
: `WOULD CHANGE: ${currentId} → ${decision.primary}`;
|
|
122
|
+
if (args.json) return console.log(JSON.stringify({ current: currentId, proposed: decision.primary, applied_rules: decision.applied_rules, diff }, null, 2));
|
|
123
|
+
console.log(`# Route — ${pkg.name}@${pkg.version}`);
|
|
124
|
+
console.log(`current : ${currentId}`);
|
|
125
|
+
console.log(`proposed : ${decision.primary}`);
|
|
126
|
+
console.log(`rules : ${decision.applied_rules.join(', ')}`);
|
|
127
|
+
console.log(`diff : ${diff}`);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
async function cmdFallbackTest(args) {
|
|
131
|
+
const pkg = findOne(await discoverPackages(resolve(process.cwd(), args.root)), args.target);
|
|
132
|
+
const manifest = await loadManifest(pkg.path);
|
|
133
|
+
const evalSet = designEvalSet(blueprintFromManifest(manifest));
|
|
134
|
+
const chaos = resolveProvider('chaos');
|
|
135
|
+
const result = await runEvalSuite(evalSet, chaos);
|
|
136
|
+
if (args.json) return console.log(JSON.stringify(result, null, 2));
|
|
137
|
+
console.log(`# Fallback-test (chaos) — ${pkg.name}@${pkg.version}`);
|
|
138
|
+
console.log(`verdict : ${result.verdict.toUpperCase()} (the runner does not yet drive the fallback chain — Fase 5)`);
|
|
139
|
+
console.log(`Note : the chain wiring lives in the client's runtime adapter; this command proves the eval scaffold survives an upstream 503.`);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const HANDLERS = { eval: cmdEval, redteam: cmdRedTeam, route: cmdRoute, 'fallback-test': cmdFallbackTest };
|
|
143
|
+
|
|
144
|
+
async function main(argv) {
|
|
145
|
+
const args = parseArgs(argv);
|
|
146
|
+
const handler = HANDLERS[args.sub];
|
|
147
|
+
if (!handler) {
|
|
148
|
+
console.error(`forge-eval: unknown subcommand "${args.sub}". Allowed: ${Object.keys(HANDLERS).join(', ')}`);
|
|
149
|
+
process.exit(1);
|
|
150
|
+
}
|
|
151
|
+
await handler(args);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const HERE = fileURLToPath(import.meta.url);
|
|
155
|
+
const ENTRY = process.argv[1] ? pathToFileURL(resolve(process.argv[1])).href : '';
|
|
156
|
+
if (ENTRY === pathToFileURL(HERE).href) {
|
|
157
|
+
main(process.argv.slice(2)).catch((err) => {
|
|
158
|
+
console.error('forge-eval: ' + (err?.message ?? err));
|
|
159
|
+
process.exit(1);
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export { cmdEval, cmdRedTeam, cmdRoute, cmdFallbackTest, blueprintFromManifest };
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* forge-new — the agent-forge front-door CLI. Reads a blueprint (YAML or JSON),
|
|
4
|
+
* validates + fills defaults, routes via the deterministic engine, and packages
|
|
5
|
+
* the APF v1 under `<out>/<agent-name>@<version>/`. Requires the optional `yaml`
|
|
6
|
+
* dep at runtime when reading a `.yaml` blueprint or writing the manifest
|
|
7
|
+
* (ADR-0013) — the loader surfaces an actionable error if absent.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* node contextkit/squads/agent-forge/cli/forge-new.mjs --blueprint <path> [--out <dir>] [--version <semver>]
|
|
11
|
+
*/
|
|
12
|
+
import { readFile } from 'node:fs/promises';
|
|
13
|
+
import { dirname, resolve } from 'node:path';
|
|
14
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
15
|
+
import { fillDefaults, validateBlueprint } from '../lib/architect.mjs';
|
|
16
|
+
import { packageAgent } from '../lib/packager.mjs';
|
|
17
|
+
import { routeAgent } from '../lib/router.mjs';
|
|
18
|
+
|
|
19
|
+
const USAGE = `Usage: forge-new --blueprint <path> [--out <dir>] [--version <semver>]
|
|
20
|
+
|
|
21
|
+
Reads the blueprint, validates + fills defaults, routes to a provider via the
|
|
22
|
+
deterministic engine, and writes a new Agent Package under
|
|
23
|
+
<out>/<agent-name>@<version>/ (default: agent-packages/<name>@0.1.0)
|
|
24
|
+
|
|
25
|
+
YAML blueprints require the optional \`yaml\` dep (ADR-0013) — run \`npm i yaml\`.
|
|
26
|
+
`;
|
|
27
|
+
|
|
28
|
+
function parseArgs(argv) {
|
|
29
|
+
const out = { blueprint: null, out: 'agent-packages', version: '0.1.0' };
|
|
30
|
+
for (let i = 0; i < argv.length; i++) {
|
|
31
|
+
const k = argv[i];
|
|
32
|
+
if (k === '--blueprint' || k === '-b') out.blueprint = argv[++i];
|
|
33
|
+
else if (k === '--out' || k === '-o') out.out = argv[++i];
|
|
34
|
+
else if (k === '--version' || k === '-v') out.version = argv[++i];
|
|
35
|
+
else if (k === '--help' || k === '-h') out.help = true;
|
|
36
|
+
}
|
|
37
|
+
return out;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Parse a blueprint file — `.json` zero-dep, `.yaml`/`.yml` via the optional yaml loader. */
|
|
41
|
+
async function readBlueprint(path) {
|
|
42
|
+
const text = (await readFile(path, 'utf-8')).replace(/^/, '');
|
|
43
|
+
if (path.endsWith('.json')) return JSON.parse(text);
|
|
44
|
+
const { parseYaml } = await import('../lib/yaml.mjs');
|
|
45
|
+
return parseYaml(text);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Programmatic entry — forges a new APF from an already-parsed blueprint object.
|
|
50
|
+
* Used by the integration test (no YAML dep needed at parse time) and by the CLI
|
|
51
|
+
* (after it parses the file).
|
|
52
|
+
*/
|
|
53
|
+
export async function forgeNew(rawBlueprint, outDir, opts = {}) {
|
|
54
|
+
const validation = validateBlueprint(rawBlueprint);
|
|
55
|
+
if (!validation.ok) {
|
|
56
|
+
const err = new Error('blueprint validation failed:\n - ' + validation.errors.join('\n - '));
|
|
57
|
+
err.validation = validation;
|
|
58
|
+
throw err;
|
|
59
|
+
}
|
|
60
|
+
const blueprint = fillDefaults(rawBlueprint);
|
|
61
|
+
const decision = await routeAgent(blueprint, opts.routerOpts);
|
|
62
|
+
let evalResult = null;
|
|
63
|
+
if (opts.runEval) {
|
|
64
|
+
const { designEvalSet } = await import('../lib/eval-designer.mjs');
|
|
65
|
+
const { runEvalSuite } = await import('../lib/eval-runner.mjs');
|
|
66
|
+
evalResult = await runEvalSuite(designEvalSet(blueprint), opts.runEval);
|
|
67
|
+
}
|
|
68
|
+
const version = opts.version ?? '0.1.0';
|
|
69
|
+
const targetDir = resolve(outDir, `${blueprint.agent_name}@${version}`);
|
|
70
|
+
const summary = await packageAgent(blueprint, decision, targetDir, { ...opts, version, evalResult });
|
|
71
|
+
return { blueprint, decision, summary, evalResult };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async function main(argv) {
|
|
75
|
+
const args = parseArgs(argv);
|
|
76
|
+
if (args.help || !args.blueprint) {
|
|
77
|
+
process.stdout.write(USAGE);
|
|
78
|
+
process.exit(args.help ? 0 : 1);
|
|
79
|
+
}
|
|
80
|
+
const blueprintPath = resolve(process.cwd(), args.blueprint);
|
|
81
|
+
const raw = await readBlueprint(blueprintPath);
|
|
82
|
+
const { decision, summary } = await forgeNew(raw, resolve(process.cwd(), args.out), { version: args.version });
|
|
83
|
+
console.log('✅ Agent Package forged:');
|
|
84
|
+
console.log(' ' + summary.targetDir);
|
|
85
|
+
console.log(' primary: ' + decision.primary + (decision.fallback ? ' · fallback: ' + decision.fallback : ' · (no cross-provider fallback)'));
|
|
86
|
+
console.log(' blueprint_hash: ' + summary.provenance.blueprint_hash.slice(0, 16));
|
|
87
|
+
console.log('\nNext: review the manifest, then run the (Fase 3) eval gate before shipping.');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const HERE = fileURLToPath(import.meta.url);
|
|
91
|
+
const ENTRY = process.argv[1] ? pathToFileURL(resolve(process.argv[1])).href : '';
|
|
92
|
+
if (ENTRY === pathToFileURL(HERE).href) {
|
|
93
|
+
main(process.argv.slice(2)).catch((err) => {
|
|
94
|
+
console.error('forge-new: ' + (err?.message ?? err));
|
|
95
|
+
process.exit(1);
|
|
96
|
+
});
|
|
97
|
+
}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* forge-ops — the read-only inspection CLI for forged Agent Packages.
|
|
4
|
+
* Subcommands: list, show, doctor, policy, budget, audit. Each one walks
|
|
5
|
+
* `agent-packages/` (or `--root <dir>`) using `lib/package-ops.mjs`. Pure
|
|
6
|
+
* Node — but `show`/`policy`/`budget` need the optional `yaml` dep at runtime
|
|
7
|
+
* (ADR-0013) because they parse the manifest.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* node contextkit/squads/agent-forge/cli/forge-ops.mjs <subcommand> [args] [--root <dir>] [--json]
|
|
11
|
+
*/
|
|
12
|
+
import { readFile } from 'node:fs/promises';
|
|
13
|
+
import { resolve, join } from 'node:path';
|
|
14
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
15
|
+
import { aggregateBudgets, diagnosePackage, discoverPackages, loadManifest, loadProvenance, summarize } from '../lib/package-ops.mjs';
|
|
16
|
+
|
|
17
|
+
const SUB = ['list', 'show', 'doctor', 'policy', 'budget', 'audit'];
|
|
18
|
+
|
|
19
|
+
function parseArgs(argv) {
|
|
20
|
+
const args = { sub: argv[0], target: null, root: 'agent-packages', json: false };
|
|
21
|
+
for (let i = 1; i < argv.length; i++) {
|
|
22
|
+
const flag = argv[i];
|
|
23
|
+
if (flag === '--root') args.root = argv[++i];
|
|
24
|
+
else if (flag === '--json') args.json = true;
|
|
25
|
+
else if (!args.target) args.target = flag;
|
|
26
|
+
}
|
|
27
|
+
return args;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function findOne(pkgs, target) {
|
|
31
|
+
if (!target) throw new Error('this subcommand requires <agent> (or <agent>@<version>)');
|
|
32
|
+
const [name, version] = target.includes('@') ? target.split('@') : [target, null];
|
|
33
|
+
const candidates = pkgs.filter((p) => p.name === name && (!version || p.version === version));
|
|
34
|
+
if (!candidates.length) throw new Error(`no package matches "${target}" under the registry`);
|
|
35
|
+
return candidates[candidates.length - 1];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async function cmdList(args) {
|
|
39
|
+
const pkgs = await discoverPackages(resolve(process.cwd(), args.root));
|
|
40
|
+
if (args.json) return console.log(JSON.stringify(pkgs, null, 2));
|
|
41
|
+
if (!pkgs.length) return console.log(`(no packages found under ${args.root}/)`);
|
|
42
|
+
console.log(`Agent Packages under ${args.root}/ (${pkgs.length}):`);
|
|
43
|
+
for (const pkg of pkgs) {
|
|
44
|
+
const manifest = await loadManifest(pkg.path).catch(() => null);
|
|
45
|
+
const provenance = await loadProvenance(pkg.path);
|
|
46
|
+
console.log(' ' + summarize(pkg, manifest, provenance));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async function cmdShow(args) {
|
|
51
|
+
const pkgs = await discoverPackages(resolve(process.cwd(), args.root));
|
|
52
|
+
const pkg = findOne(pkgs, args.target);
|
|
53
|
+
const manifest = await loadManifest(pkg.path);
|
|
54
|
+
const provenance = await loadProvenance(pkg.path);
|
|
55
|
+
const payload = { ...pkg, manifest, provenance };
|
|
56
|
+
if (args.json) return console.log(JSON.stringify(payload, null, 2));
|
|
57
|
+
console.log(`# ${pkg.name}@${pkg.version}\n`);
|
|
58
|
+
console.log(`name : ${manifest?.metadata?.name}`);
|
|
59
|
+
console.log(`version : ${manifest?.metadata?.version}`);
|
|
60
|
+
console.log(`description : ${manifest?.metadata?.description?.trim()}`);
|
|
61
|
+
console.log(`primary : ${manifest?.spec?.model_selection?.primary?.provider}/${manifest?.spec?.model_selection?.primary?.model}`);
|
|
62
|
+
if (manifest?.spec?.model_selection?.fallback?.length) {
|
|
63
|
+
const fb = manifest.spec.model_selection.fallback[0];
|
|
64
|
+
console.log(`fallback : ${fb.provider}/${fb.model}`);
|
|
65
|
+
}
|
|
66
|
+
console.log(`runtimes : ${(manifest?.spec?.runtime_adapters || []).join(', ')}`);
|
|
67
|
+
console.log(`eval_passed : ${manifest?.metadata?.provenance?.eval_passed_at ?? 'NEVER'}`);
|
|
68
|
+
console.log(`forged_by : ${manifest?.metadata?.provenance?.forged_by}`);
|
|
69
|
+
console.log(`hash : ${manifest?.metadata?.provenance?.blueprint_hash}`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async function cmdDoctor(args) {
|
|
73
|
+
const pkgs = await discoverPackages(resolve(process.cwd(), args.root));
|
|
74
|
+
if (!pkgs.length) return console.log(`(no packages found under ${args.root}/)`);
|
|
75
|
+
const report = [];
|
|
76
|
+
let bad = 0;
|
|
77
|
+
for (const pkg of pkgs) {
|
|
78
|
+
const result = await diagnosePackage(pkg.path);
|
|
79
|
+
report.push({ name: pkg.name, version: pkg.version, ...result });
|
|
80
|
+
if (!result.ok) bad += 1;
|
|
81
|
+
}
|
|
82
|
+
if (args.json) return console.log(JSON.stringify(report, null, 2));
|
|
83
|
+
for (const entry of report) {
|
|
84
|
+
if (entry.ok) console.log(` ✅ ${entry.name}@${entry.version}`);
|
|
85
|
+
else {
|
|
86
|
+
console.log(` ❌ ${entry.name}@${entry.version}`);
|
|
87
|
+
for (const problem of entry.problems) console.log(` - ${problem}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
console.log(`\n${pkgs.length - bad}/${pkgs.length} healthy${bad ? `; ${bad} need attention` : ''}.`);
|
|
91
|
+
if (bad) process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async function cmdPolicy(args) {
|
|
95
|
+
const pkgs = await discoverPackages(resolve(process.cwd(), args.root));
|
|
96
|
+
const pkg = findOne(pkgs, args.target);
|
|
97
|
+
const { parseYaml } = await import('../lib/yaml.mjs');
|
|
98
|
+
const pillars = {};
|
|
99
|
+
for (const name of ['cost', 'compliance', 'quality']) {
|
|
100
|
+
pillars[name] = parseYaml(await readFile(join(pkg.path, `governance/${name}.policy.yaml`), 'utf-8'));
|
|
101
|
+
}
|
|
102
|
+
pillars.fallback = parseYaml(await readFile(join(pkg.path, 'governance/fallback-chain.yaml'), 'utf-8'));
|
|
103
|
+
if (args.json) return console.log(JSON.stringify(pillars, null, 2));
|
|
104
|
+
console.log(`# Governance — ${pkg.name}@${pkg.version}\n`);
|
|
105
|
+
console.log('cost.budgets:'); console.log(JSON.stringify(pillars.cost?.budgets, null, 2));
|
|
106
|
+
console.log('\ncompliance.data_residency:'); console.log(JSON.stringify(pillars.compliance?.data_residency, null, 2));
|
|
107
|
+
console.log('\nquality.eval_gates.pre_release:'); console.log(JSON.stringify(pillars.quality?.eval_gates?.pre_release, null, 2));
|
|
108
|
+
console.log('\nfallback.chain:'); console.log(JSON.stringify(pillars.fallback?.chain, null, 2));
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async function cmdBudget(args) {
|
|
112
|
+
const pkgs = await discoverPackages(resolve(process.cwd(), args.root));
|
|
113
|
+
const manifests = [];
|
|
114
|
+
for (const pkg of pkgs) {
|
|
115
|
+
const manifest = await loadManifest(pkg.path).catch(() => null);
|
|
116
|
+
if (manifest) manifests.push(manifest);
|
|
117
|
+
}
|
|
118
|
+
const result = aggregateBudgets(manifests);
|
|
119
|
+
if (args.json) return console.log(JSON.stringify(result, null, 2));
|
|
120
|
+
console.log(`# Forge Budget — aggregate across ${manifests.length} package(s)\n`);
|
|
121
|
+
console.log(`monthly target : $${result.totals.monthly_target_usd.toFixed(2)}`);
|
|
122
|
+
console.log(`monthly hard cap : $${result.totals.monthly_hard_cap_usd.toFixed(2)}\n`);
|
|
123
|
+
for (const entry of result.perAgent) {
|
|
124
|
+
console.log(` ${entry.name} target $${entry.target} cap $${entry.hardCap} per-call max $${entry.perCallCap}`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async function cmdAudit(args) {
|
|
129
|
+
const pkgs = await discoverPackages(resolve(process.cwd(), args.root));
|
|
130
|
+
const pkg = findOne(pkgs, args.target);
|
|
131
|
+
const auditPath = join(pkg.path, 'audit', `${pkg.name}.jsonl`);
|
|
132
|
+
let raw = '';
|
|
133
|
+
try { raw = await readFile(auditPath, 'utf-8'); } catch {
|
|
134
|
+
console.log(`(no audit log at ${auditPath})`);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
const events = raw.split('\n').filter(Boolean).map((line) => {
|
|
138
|
+
try { return JSON.parse(line); } catch { return null; }
|
|
139
|
+
}).filter(Boolean);
|
|
140
|
+
const totals = { calls: events.length, ok: 0, refused: 0, error: 0, killed: 0, totalCost: 0, fallbacks: 0 };
|
|
141
|
+
for (const event of events) {
|
|
142
|
+
if (event.outcome && totals[event.outcome] !== undefined) totals[event.outcome] += 1;
|
|
143
|
+
if (event.fallback_triggered) totals.fallbacks += 1;
|
|
144
|
+
totals.totalCost += Number(event.cost_usd ?? 0);
|
|
145
|
+
}
|
|
146
|
+
if (args.json) return console.log(JSON.stringify({ pkg, totals }, null, 2));
|
|
147
|
+
console.log(`# Audit — ${pkg.name}@${pkg.version} (${events.length} events)\n`);
|
|
148
|
+
console.log(` ok : ${totals.ok}`);
|
|
149
|
+
console.log(` refused : ${totals.refused}`);
|
|
150
|
+
console.log(` error : ${totals.error}`);
|
|
151
|
+
console.log(` killed : ${totals.killed}`);
|
|
152
|
+
console.log(` fallbacks : ${totals.fallbacks}`);
|
|
153
|
+
console.log(` cost : $${totals.totalCost.toFixed(4)}`);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const HANDLERS = { list: cmdList, show: cmdShow, doctor: cmdDoctor, policy: cmdPolicy, budget: cmdBudget, audit: cmdAudit };
|
|
157
|
+
|
|
158
|
+
async function main(argv) {
|
|
159
|
+
const args = parseArgs(argv);
|
|
160
|
+
const handler = HANDLERS[args.sub];
|
|
161
|
+
if (!handler) {
|
|
162
|
+
console.error(`forge-ops: unknown subcommand "${args.sub}". Allowed: ${SUB.join(', ')}`);
|
|
163
|
+
process.exit(1);
|
|
164
|
+
}
|
|
165
|
+
await handler(args);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const HERE = fileURLToPath(import.meta.url);
|
|
169
|
+
const ENTRY = process.argv[1] ? pathToFileURL(resolve(process.argv[1])).href : '';
|
|
170
|
+
if (ENTRY === pathToFileURL(HERE).href) {
|
|
171
|
+
main(process.argv.slice(2)).catch((err) => {
|
|
172
|
+
console.error('forge-ops: ' + (err?.message ?? err));
|
|
173
|
+
process.exit(1);
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export { cmdList, cmdShow, cmdDoctor, cmdPolicy, cmdBudget, cmdAudit };
|