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,27 @@
|
|
|
1
|
+
<!-- ContextDevKit PR template — edit freely for your project. -->
|
|
2
|
+
|
|
3
|
+
## What & why
|
|
4
|
+
|
|
5
|
+
<!-- What does this change do, and why? Link the issue/ADR if any. -->
|
|
6
|
+
|
|
7
|
+
## Type
|
|
8
|
+
|
|
9
|
+
- [ ] feat
|
|
10
|
+
- [ ] fix
|
|
11
|
+
- [ ] refactor
|
|
12
|
+
- [ ] docs
|
|
13
|
+
- [ ] test
|
|
14
|
+
- [ ] chore
|
|
15
|
+
|
|
16
|
+
## Checklist
|
|
17
|
+
|
|
18
|
+
- [ ] Follows the constitution in `CLAUDE.md` (file size, SRP, naming, language policy)
|
|
19
|
+
- [ ] No new file over the line limit without a recorded coherence reason
|
|
20
|
+
- [ ] Tests added/updated for the change (and they would catch the bug)
|
|
21
|
+
- [ ] Architectural decision recorded with `/new-adr` (if applicable)
|
|
22
|
+
- [ ] Session registered with `/log-session`
|
|
23
|
+
- [ ] `CHANGELOG.md` `[Unreleased]` updated
|
|
24
|
+
|
|
25
|
+
## Notes for reviewers
|
|
26
|
+
|
|
27
|
+
<!-- Anything reviewers should focus on, risks, follow-ups. -->
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Dependabot — keep dependencies patched automatically.
|
|
2
|
+
# Docs: https://docs.github.com/code-security/dependabot/dependabot-version-updates
|
|
3
|
+
# Scaffolded by ContextDevKit (/security-setup). Uncomment / add the ecosystems your
|
|
4
|
+
# project uses (npm, pip, gomod, cargo, maven, bundler, composer, docker, ...).
|
|
5
|
+
version: 2
|
|
6
|
+
updates:
|
|
7
|
+
# GitHub Actions used by your workflows (valid in any repo; harmless if none).
|
|
8
|
+
- package-ecosystem: "github-actions"
|
|
9
|
+
directory: "/"
|
|
10
|
+
schedule:
|
|
11
|
+
interval: "weekly"
|
|
12
|
+
open-pull-requests-limit: 5
|
|
13
|
+
labels: ["dependencies", "security"]
|
|
14
|
+
|
|
15
|
+
# Node / npm — uncomment if the project has a package.json at the root.
|
|
16
|
+
# - package-ecosystem: "npm"
|
|
17
|
+
# directory: "/"
|
|
18
|
+
# schedule:
|
|
19
|
+
# interval: "weekly"
|
|
20
|
+
# open-pull-requests-limit: 10
|
|
21
|
+
# labels: ["dependencies", "security"]
|
|
22
|
+
|
|
23
|
+
# Python — uncomment for requirements.txt / pyproject.toml.
|
|
24
|
+
# - package-ecosystem: "pip"
|
|
25
|
+
# directory: "/"
|
|
26
|
+
# schedule:
|
|
27
|
+
# interval: "weekly"
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Quality gates — contract drift + tech-debt RED zone.
|
|
2
|
+
# Scaffolded by ContextDevKit. Each job FAILS the run on a regression; to make it
|
|
3
|
+
# BLOCK merges, add it as a required status check in branch protection.
|
|
4
|
+
name: quality
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
pull_request:
|
|
8
|
+
push:
|
|
9
|
+
branches: [main, master]
|
|
10
|
+
workflow_dispatch:
|
|
11
|
+
|
|
12
|
+
permissions:
|
|
13
|
+
contents: read
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
contract-drift:
|
|
17
|
+
# Fails if a public export was removed/renamed since the committed baseline
|
|
18
|
+
# (contextkit/memory/contract-baseline.json). No-op until you set `l5.contractGlobs`
|
|
19
|
+
# and save a baseline (`contract-scan.mjs --save`).
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
|
23
|
+
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
|
|
24
|
+
with:
|
|
25
|
+
node-version: 20
|
|
26
|
+
- run: node contextkit/tools/scripts/contract-scan.mjs
|
|
27
|
+
|
|
28
|
+
tech-debt:
|
|
29
|
+
# Fails on any RED-zone finding (a file over the hard line-budget limit).
|
|
30
|
+
runs-on: ubuntu-latest
|
|
31
|
+
steps:
|
|
32
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
|
33
|
+
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
|
|
34
|
+
with:
|
|
35
|
+
node-version: 20
|
|
36
|
+
- run: node contextkit/tools/scripts/tech-debt-scan.mjs --ci
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Security checks — ADVISORY by default (they report, they don't block the merge).
|
|
2
|
+
# Scaffolded by ContextDevKit (/security-setup). To ENFORCE: mark a job a required
|
|
3
|
+
# status check in branch protection, or remove its `continue-on-error`.
|
|
4
|
+
name: security
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
pull_request:
|
|
8
|
+
push:
|
|
9
|
+
branches: [main, master]
|
|
10
|
+
workflow_dispatch:
|
|
11
|
+
|
|
12
|
+
permissions:
|
|
13
|
+
contents: read
|
|
14
|
+
security-events: write # CodeQL uploads results here
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
dependency-review:
|
|
18
|
+
# GitHub's native diff of dependency changes on a PR (CVEs + license).
|
|
19
|
+
if: github.event_name == 'pull_request'
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
continue-on-error: true # advisory — remove to block on a vulnerable bump
|
|
22
|
+
steps:
|
|
23
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
|
24
|
+
- uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5
|
|
25
|
+
with:
|
|
26
|
+
fail-on-severity: high
|
|
27
|
+
|
|
28
|
+
deps-audit:
|
|
29
|
+
# ContextDevKit's deterministic supply-chain check (lockfile, pinning, license, CVEs).
|
|
30
|
+
runs-on: ubuntu-latest
|
|
31
|
+
continue-on-error: true # advisory — remove to block
|
|
32
|
+
steps:
|
|
33
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
|
34
|
+
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
|
|
35
|
+
with:
|
|
36
|
+
node-version: 20
|
|
37
|
+
- run: node contextkit/tools/scripts/deps-audit.mjs
|
|
38
|
+
|
|
39
|
+
codeql:
|
|
40
|
+
# SAST. Set `language` to your stack: c-cpp, csharp, go, java-kotlin,
|
|
41
|
+
# javascript-typescript, python, ruby, swift. Remove this job if you enable
|
|
42
|
+
# CodeQL "default setup" in repository settings instead.
|
|
43
|
+
runs-on: ubuntu-latest
|
|
44
|
+
continue-on-error: true
|
|
45
|
+
strategy:
|
|
46
|
+
matrix:
|
|
47
|
+
language: ["javascript-typescript"]
|
|
48
|
+
steps:
|
|
49
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
|
50
|
+
- uses: github/codeql-action/init@03e4368ac7daa2bd82b3e85262f3bf87ee112f57 # v3
|
|
51
|
+
with:
|
|
52
|
+
languages: ${{ matrix.language }}
|
|
53
|
+
- uses: github/codeql-action/autobuild@03e4368ac7daa2bd82b3e85262f3bf87ee112f57 # v3
|
|
54
|
+
- uses: github/codeql-action/analyze@03e4368ac7daa2bd82b3e85262f3bf87ee112f57 # v3
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI surface for the installer: argument parsing, the `--help` text, the
|
|
3
|
+
* interactive prompt helper, and the human-readable level labels.
|
|
4
|
+
*/
|
|
5
|
+
export { LEVEL_LABELS } from '../../templates/contextkit/runtime/config/levels.mjs';
|
|
6
|
+
|
|
7
|
+
export function parseArgs(argv) {
|
|
8
|
+
const args = { yes: false, rewire: false, force: false, uninstall: false, help: false, version: false, purge: false, update: false };
|
|
9
|
+
for (let i = 0; i < argv.length; i++) {
|
|
10
|
+
const a = argv[i];
|
|
11
|
+
if (a === '--yes' || a === '-y') args.yes = true;
|
|
12
|
+
else if (a === '--update') { args.update = true; args.yes = true; }
|
|
13
|
+
else if (a === '--rewire') args.rewire = true;
|
|
14
|
+
else if (a === '--force') args.force = true;
|
|
15
|
+
else if (a === '--uninstall') args.uninstall = true;
|
|
16
|
+
else if (a === '--purge') args.purge = true;
|
|
17
|
+
else if (a === '--help' || a === '-h') args.help = true;
|
|
18
|
+
else if (a === '--version' || a === '-v') args.version = true;
|
|
19
|
+
else if (a === '--target') args.target = argv[++i];
|
|
20
|
+
else if (a === '--level') args.level = Number(argv[++i]);
|
|
21
|
+
else if (a === '--name') args.name = argv[++i];
|
|
22
|
+
else if (a === '--mode') args.mode = argv[++i];
|
|
23
|
+
else if (a === '--preset') args.preset = argv[++i];
|
|
24
|
+
}
|
|
25
|
+
return args;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const HELP = `
|
|
29
|
+
🌀 ContextDevKit installer
|
|
30
|
+
|
|
31
|
+
Usage:
|
|
32
|
+
node install.mjs [--target <path>] [--level <1-7>] [--name <str>]
|
|
33
|
+
[--mode greenfield|existing] [--yes] [--force]
|
|
34
|
+
node install.mjs --update safe update: refresh engine + commands,
|
|
35
|
+
keep your level/config/memory/CLAUDE.md
|
|
36
|
+
node install.mjs --rewire --level <1-7> only recompose .claude/settings.json
|
|
37
|
+
node install.mjs --uninstall [--purge] unwire hooks (--purge also removes engine)
|
|
38
|
+
node install.mjs --help | --version
|
|
39
|
+
|
|
40
|
+
Flags:
|
|
41
|
+
--target <path> destination project root (default: current directory)
|
|
42
|
+
--level <1-7> activation level (default: prompt, else 2)
|
|
43
|
+
--name <string> project name for the CLAUDE.md header
|
|
44
|
+
--mode <m> greenfield | existing (default: auto-detect)
|
|
45
|
+
--preset <name> stack preset to merge into config: next | go | python
|
|
46
|
+
--yes, -y non-interactive (use flags/defaults, no prompts)
|
|
47
|
+
--force overwrite CLAUDE.md / memory seeds if they exist
|
|
48
|
+
--update safe update: refresh engine/commands/agents + re-wire hooks for
|
|
49
|
+
the CURRENT level; never touches CLAUDE.md, config, or memory
|
|
50
|
+
--rewire only recompose settings.json for the given --level
|
|
51
|
+
--uninstall remove ContextDevKit hook wiring + git hooks (keeps memory)
|
|
52
|
+
--purge with --uninstall, also delete contextkit/ engine + commands/agents
|
|
53
|
+
--help, -h show this help
|
|
54
|
+
--version, -v print the kit version
|
|
55
|
+
|
|
56
|
+
After installing, open the project in Claude Code and run /setupcontextdevkit.
|
|
57
|
+
`;
|
|
58
|
+
|
|
59
|
+
export async function prompt(rl, q, def) {
|
|
60
|
+
const a = (await rl.question(`${q}${def ? ` (${def})` : ''}: `)).trim();
|
|
61
|
+
return a || def || '';
|
|
62
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File-system helpers for the ContextDevKit installer.
|
|
3
|
+
*
|
|
4
|
+
* Thin wrappers over `node:fs`: idempotent writes, BOM-stripped reads
|
|
5
|
+
* (Windows-safe), recursive copies (clobbering vs write-if-missing), and
|
|
6
|
+
* `{{var}}` template rendering. Zero third-party deps — the installer must run
|
|
7
|
+
* via `npx` on a machine with nothing else installed.
|
|
8
|
+
*/
|
|
9
|
+
import { cp, mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
10
|
+
import { existsSync, readdirSync } from 'node:fs';
|
|
11
|
+
import { dirname, join } from 'node:path';
|
|
12
|
+
|
|
13
|
+
export async function ensureDir(p) {
|
|
14
|
+
await mkdir(p, { recursive: true });
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Reads a file, stripping a leading UTF-8 BOM so `JSON.parse` never trips. */
|
|
18
|
+
export async function read(path) {
|
|
19
|
+
return (await readFile(path, 'utf-8')).replace(/^/, '');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Writes `content` only if `path` is absent (or `force`). Returns whether it wrote. */
|
|
23
|
+
export async function writeIfMissing(path, content, force) {
|
|
24
|
+
if (existsSync(path) && !force) return false;
|
|
25
|
+
await ensureDir(dirname(path));
|
|
26
|
+
await writeFile(path, content, 'utf-8');
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export async function overwrite(path, content) {
|
|
31
|
+
await ensureDir(dirname(path));
|
|
32
|
+
await writeFile(path, content, 'utf-8');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export async function copyTree(src, dest) {
|
|
36
|
+
if (!existsSync(src)) return;
|
|
37
|
+
await cp(src, dest, { recursive: true, force: true });
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Recursively copies `src` into `dest`, writing each file ONLY if absent. */
|
|
41
|
+
export async function copyTreeIfMissing(src, dest) {
|
|
42
|
+
if (!existsSync(src)) return 0;
|
|
43
|
+
let count = 0;
|
|
44
|
+
for (const entry of readdirSync(src, { withFileTypes: true })) {
|
|
45
|
+
const from = join(src, entry.name);
|
|
46
|
+
const to = join(dest, entry.name);
|
|
47
|
+
if (entry.isDirectory()) count += await copyTreeIfMissing(from, to);
|
|
48
|
+
else if (await writeIfMissing(to, await readFile(from, 'utf-8'), false)) count++;
|
|
49
|
+
}
|
|
50
|
+
return count;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Replaces `{{var}}` placeholders from `vars`; leaves unknown ones intact. */
|
|
54
|
+
export function render(tpl, vars) {
|
|
55
|
+
return tpl.replace(/\{\{(\w+)\}\}/g, (_, k) => (k in vars ? vars[k] : `{{${k}}}`));
|
|
56
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git integration for the installer: drop the L≥3 git-hook wrappers, and patch
|
|
3
|
+
* `.gitignore` / `.gitattributes` idempotently (never double-append).
|
|
4
|
+
*/
|
|
5
|
+
import { writeFile, chmod, rename, stat } from 'node:fs/promises';
|
|
6
|
+
import { existsSync } from 'node:fs';
|
|
7
|
+
import { isAbsolute, join, resolve } from 'node:path';
|
|
8
|
+
import { ensureDir, read } from './fs.mjs';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Resolves a `.git` path to the *actual* git directory.
|
|
12
|
+
*
|
|
13
|
+
* In a regular repo, `.git` is a directory — return it as-is. In a git
|
|
14
|
+
* worktree (or a submodule), `.git` is a regular **file** containing
|
|
15
|
+
* `gitdir: <absolute-or-relative-path>`. We follow that pointer so hooks
|
|
16
|
+
* land in the worktree-specific git dir (`<main>/.git/worktrees/<name>/hooks/`),
|
|
17
|
+
* which is what git actually looks at when running hooks for a worktree.
|
|
18
|
+
*
|
|
19
|
+
* Returns `null` when the pointer is malformed — the installer treats that
|
|
20
|
+
* as "no git" and skips hook installation (rule 2: never break real work).
|
|
21
|
+
*
|
|
22
|
+
* @param {string} dotGit — path to the project's `.git` (file or dir)
|
|
23
|
+
* @param {string} target — project root, for resolving relative gitdir pointers
|
|
24
|
+
* @returns {Promise<string | null>}
|
|
25
|
+
*/
|
|
26
|
+
export async function resolveGitDir(dotGit, target) {
|
|
27
|
+
try {
|
|
28
|
+
const st = await stat(dotGit);
|
|
29
|
+
if (st.isDirectory()) return dotGit;
|
|
30
|
+
if (!st.isFile()) return null;
|
|
31
|
+
const text = (await read(dotGit)).trim();
|
|
32
|
+
const match = text.match(/^gitdir:\s*(.+)$/m);
|
|
33
|
+
if (!match) return null;
|
|
34
|
+
const pointer = match[1].trim();
|
|
35
|
+
return isAbsolute(pointer) ? pointer : resolve(target, pointer);
|
|
36
|
+
} catch {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Installs thin git-hook wrappers that call the engine scripts. Needs a `.git`.
|
|
43
|
+
*
|
|
44
|
+
* If a hook file already exists and is NOT one of ours (e.g. a husky/lint-staged
|
|
45
|
+
* hook), it is backed up to `<name>.bak` before being replaced — so the user's
|
|
46
|
+
* own hook is never silently clobbered. An existing `.bak` is preserved (the
|
|
47
|
+
* first backup wins) so re-running the installer can't overwrite the original.
|
|
48
|
+
*
|
|
49
|
+
* @returns {Promise<{ installed: boolean, backedUp: string[] }>}
|
|
50
|
+
*/
|
|
51
|
+
export async function installGitHooks(target) {
|
|
52
|
+
const dotGit = join(target, '.git');
|
|
53
|
+
if (!existsSync(dotGit)) return { installed: false, backedUp: [] };
|
|
54
|
+
// Worktrees + submodules have `.git` as a FILE pointing at the real gitdir.
|
|
55
|
+
// Follow the pointer so hooks land where git will actually invoke them
|
|
56
|
+
// (and so `ensureDir` doesn't trip on ENOTDIR — bug 038, ADR-0015 session).
|
|
57
|
+
const gitDir = await resolveGitDir(dotGit, target);
|
|
58
|
+
if (!gitDir) return { installed: false, backedUp: [] };
|
|
59
|
+
const hooksDir = join(gitDir, 'hooks');
|
|
60
|
+
await ensureDir(hooksDir);
|
|
61
|
+
const wrappers = {
|
|
62
|
+
'pre-commit': '#!/bin/sh\nnode contextkit/runtime/git-hooks/pre-commit.mjs\n',
|
|
63
|
+
'commit-msg': '#!/bin/sh\nnode contextkit/runtime/git-hooks/commit-msg.mjs "$1"\n',
|
|
64
|
+
'pre-push': '#!/bin/sh\nnode contextkit/runtime/git-hooks/pre-push.mjs\n',
|
|
65
|
+
};
|
|
66
|
+
const backedUp = [];
|
|
67
|
+
for (const [name, body] of Object.entries(wrappers)) {
|
|
68
|
+
const p = join(hooksDir, name);
|
|
69
|
+
if (existsSync(p) && !(await read(p)).includes('contextkit/runtime/git-hooks')) {
|
|
70
|
+
const backup = `${p}.bak`;
|
|
71
|
+
if (!existsSync(backup)) {
|
|
72
|
+
await rename(p, backup);
|
|
73
|
+
backedUp.push(name);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
await writeFile(p, body, 'utf-8');
|
|
77
|
+
await chmod(p, 0o755).catch(() => {});
|
|
78
|
+
}
|
|
79
|
+
return { installed: true, backedUp };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const GITIGNORE_BLOCK = [
|
|
83
|
+
'',
|
|
84
|
+
'# ContextDevKit — local runtime state (do not commit)',
|
|
85
|
+
'.claude/.sessions/',
|
|
86
|
+
'.claude/.workspace/',
|
|
87
|
+
'.context-snapshot.md',
|
|
88
|
+
'.distillation-proposal.md',
|
|
89
|
+
'.agent-tuning-proposal.md',
|
|
90
|
+
'contextkit/memory/tech-debt-findings.json',
|
|
91
|
+
'contextkit/memory/deps-findings.json',
|
|
92
|
+
'contextkit/memory/deep-analysis-findings.json',
|
|
93
|
+
].join('\n');
|
|
94
|
+
|
|
95
|
+
export async function patchGitignore(target) {
|
|
96
|
+
const p = join(target, '.gitignore');
|
|
97
|
+
let current = '';
|
|
98
|
+
if (existsSync(p)) current = await read(p);
|
|
99
|
+
if (current.includes('ContextDevKit — local runtime state')) return false;
|
|
100
|
+
await writeFile(p, current + (current.endsWith('\n') || current === '' ? '' : '\n') + GITIGNORE_BLOCK + '\n', 'utf-8');
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export async function patchGitattributes(target, tplDir) {
|
|
105
|
+
const tplPath = join(tplDir, 'gitattributes');
|
|
106
|
+
if (!existsSync(tplPath)) return false;
|
|
107
|
+
const block = await read(tplPath);
|
|
108
|
+
const p = join(target, '.gitattributes');
|
|
109
|
+
let current = '';
|
|
110
|
+
if (existsSync(p)) current = await read(p);
|
|
111
|
+
if (current.includes('ContextDevKit — keep engine scripts')) return false;
|
|
112
|
+
await writeFile(p, current + (current.endsWith('\n') || current === '' ? '' : '\n') + block, 'utf-8');
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Target-project inspection for the installer: detect the stack (for the
|
|
3
|
+
* CLAUDE.md header on existing projects), decide whether a folder looks
|
|
4
|
+
* greenfield, and derive a safe project basename.
|
|
5
|
+
*/
|
|
6
|
+
import { existsSync, readdirSync } from 'node:fs';
|
|
7
|
+
import { join } from 'node:path';
|
|
8
|
+
import { read } from './fs.mjs';
|
|
9
|
+
|
|
10
|
+
/** Best-effort, human-readable stack summary for the CLAUDE.md header. */
|
|
11
|
+
export async function detectStack(target) {
|
|
12
|
+
const hints = [];
|
|
13
|
+
const pkgPath = join(target, 'package.json');
|
|
14
|
+
if (existsSync(pkgPath)) {
|
|
15
|
+
try {
|
|
16
|
+
const pkg = JSON.parse(await read(pkgPath));
|
|
17
|
+
const deps = Object.keys({ ...(pkg.dependencies ?? {}), ...(pkg.devDependencies ?? {}) });
|
|
18
|
+
const known = ['react', 'next', 'expo', 'react-native', 'vue', 'svelte', 'hono', 'express', 'fastify', 'nestjs', 'vite', 'astro', 'drizzle-orm', 'prisma', 'typescript'];
|
|
19
|
+
const found = known.filter((k) => deps.includes(k));
|
|
20
|
+
hints.push(`Node/TypeScript project. Detected: ${found.length ? found.join(', ') : 'no well-known frameworks'}.`);
|
|
21
|
+
} catch {
|
|
22
|
+
hints.push('Node project (package.json present).');
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
for (const [f, label] of [['pyproject.toml', 'Python'], ['go.mod', 'Go'], ['Cargo.toml', 'Rust'], ['pom.xml', 'Java/Maven'], ['Gemfile', 'Ruby']]) {
|
|
26
|
+
if (existsSync(join(target, f))) hints.push(`${label} (${f}).`);
|
|
27
|
+
}
|
|
28
|
+
return hints.length ? hints.join(' ') : '_TBD — fill in your stack._';
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function requireBasename(p) {
|
|
32
|
+
return p.replace(/[\\/]+$/, '').split(/[\\/]/).pop() || 'project';
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function looksGreenfield(target) {
|
|
36
|
+
try {
|
|
37
|
+
const entries = existsSync(target) ? readdirSyncSafe(target) : [];
|
|
38
|
+
const meaningful = entries.filter((e) => !['.git', '.gitignore', 'README.md', 'LICENSE', '.claude', 'contextkit'].includes(e));
|
|
39
|
+
return meaningful.length === 0;
|
|
40
|
+
} catch {
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function readdirSyncSafe(p) {
|
|
46
|
+
try {
|
|
47
|
+
return readdirSync(p);
|
|
48
|
+
} catch {
|
|
49
|
+
return [];
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `--uninstall` [`--purge`]: remove ContextDevKit's hook wiring + git hooks (and,
|
|
3
|
+
* with purge, the engine/commands/agents) while ALWAYS keeping the user's
|
|
4
|
+
* memory (ADRs/sessions) and CLAUDE.md.
|
|
5
|
+
*/
|
|
6
|
+
import { rm } from 'node:fs/promises';
|
|
7
|
+
import { existsSync } from 'node:fs';
|
|
8
|
+
import { join } from 'node:path';
|
|
9
|
+
import { read, overwrite } from './fs.mjs';
|
|
10
|
+
|
|
11
|
+
export async function uninstall(target, purge) {
|
|
12
|
+
const report = [];
|
|
13
|
+
// 1. Strip ContextDevKit hook entries from settings.json (keep the user's own).
|
|
14
|
+
const settingsPath = join(target, '.claude', 'settings.json');
|
|
15
|
+
if (existsSync(settingsPath)) {
|
|
16
|
+
try {
|
|
17
|
+
const settings = JSON.parse(await read(settingsPath));
|
|
18
|
+
const hooks = settings.hooks || {};
|
|
19
|
+
for (const evt of Object.keys(hooks)) {
|
|
20
|
+
if (!Array.isArray(hooks[evt])) continue;
|
|
21
|
+
hooks[evt] = hooks[evt]
|
|
22
|
+
.map((g) => ({ ...g, hooks: (g.hooks || []).filter((h) => !String(h.command || '').includes('contextkit/runtime/hooks')) }))
|
|
23
|
+
.filter((g) => (g.hooks || []).length > 0);
|
|
24
|
+
if (hooks[evt].length === 0) delete hooks[evt];
|
|
25
|
+
}
|
|
26
|
+
settings.hooks = hooks;
|
|
27
|
+
await overwrite(settingsPath, JSON.stringify(settings, null, 2) + '\n');
|
|
28
|
+
report.push('✓ removed ContextDevKit hook wiring from .claude/settings.json');
|
|
29
|
+
} catch {
|
|
30
|
+
report.push('⚠️ could not parse .claude/settings.json — left untouched');
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// 2. Remove the git hook wrappers we installed.
|
|
34
|
+
for (const h of ['pre-commit', 'commit-msg', 'pre-push']) {
|
|
35
|
+
const p = join(target, '.git', 'hooks', h);
|
|
36
|
+
if (existsSync(p)) {
|
|
37
|
+
await rm(p, { force: true });
|
|
38
|
+
report.push(`✓ removed git hook ${h}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// 3. With --purge, delete the engine + commands/agents (KEEP memory).
|
|
42
|
+
if (purge) {
|
|
43
|
+
for (const rel of ['contextkit/runtime', 'contextkit/tools', '.claude/commands', '.claude/agents']) {
|
|
44
|
+
const p = join(target, rel);
|
|
45
|
+
if (existsSync(p)) {
|
|
46
|
+
await rm(p, { recursive: true, force: true });
|
|
47
|
+
report.push(`✓ purged ${rel}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
report.push('ℹ️ kept contextkit/memory/ (your ADRs + session history) and CLAUDE.md');
|
|
51
|
+
}
|
|
52
|
+
console.log('\n' + report.join('\n'));
|
|
53
|
+
console.log('\n✅ ContextDevKit uninstalled.' + (purge ? '' : ' Engine files kept; re-run without --uninstall to re-enable.'));
|
|
54
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* ContextDevKit integration test — COMPOZY follow-through features.
|
|
4
|
+
*
|
|
5
|
+
* Sibling of `integration-test-guards.mjs`. Extracted as a responsibility seam
|
|
6
|
+
* (guards is for input-rejection safety nets; the Compozy follow-throughs are
|
|
7
|
+
* positive-path lifecycle tests of new features). Mirrors the
|
|
8
|
+
* ADR-0016/ticket-047 split pattern.
|
|
9
|
+
*
|
|
10
|
+
* Tickets covered: 041 (/workflow macro), 043 (distill-detect), 046 (/resume).
|
|
11
|
+
*
|
|
12
|
+
* Run: node tools/integration-test-compozy.mjs (exit 0 = healthy)
|
|
13
|
+
*/
|
|
14
|
+
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
15
|
+
import { tmpdir } from 'node:os';
|
|
16
|
+
import { join } from 'node:path';
|
|
17
|
+
import { KIT, run, reporter } from './it-helpers.mjs';
|
|
18
|
+
|
|
19
|
+
const rep = reporter();
|
|
20
|
+
const { ok, bad } = rep;
|
|
21
|
+
console.log('\n🌀 ContextDevKit integration test — Compozy follow-throughs\n');
|
|
22
|
+
|
|
23
|
+
const importKit = (rel) => import('file://' + join(KIT, rel).replaceAll('\\', '/'));
|
|
24
|
+
const tmp = (tag) => mkdtempSync(join(tmpdir(), `contextkit-${tag}-`));
|
|
25
|
+
|
|
26
|
+
/** 041 — /workflow macro lifecycle: new → 3× advance → completion → status. */
|
|
27
|
+
function testWorkflowMacro() {
|
|
28
|
+
const proj = tmp('wf');
|
|
29
|
+
run([join(KIT, 'install.mjs'), '--target', proj, '--level', '5', '--name', 'WF', '--yes']);
|
|
30
|
+
const cli = (...a) => run([join(proj, 'contextkit', 'tools', 'scripts', 'workflow.mjs'), ...a], { cwd: proj });
|
|
31
|
+
cli('new', 'BAD!!').status === 1 ? ok('/workflow refuses invalid slug (ticket 041)') : bad('bad slug accepted');
|
|
32
|
+
cli('new', 'demo').status === 0 && existsSync(join(proj, 'contextkit/memory/workflows/demo.md')) ? ok('/workflow new creates breadcrumb (ticket 041)') : bad('breadcrumb missing');
|
|
33
|
+
cli('new', 'demo').status === 1 ? ok('/workflow refuses duplicate slug') : bad('duplicate accepted');
|
|
34
|
+
['r1', 'ADR-0023', '[052]'].forEach((r) => cli('advance', 'demo', r));
|
|
35
|
+
/complete/i.test(cli('advance', 'demo', 'merged').stdout) ? ok('/workflow lifecycle completes after 4 phases (ticket 041)') : bad('final advance missing complete');
|
|
36
|
+
const data = JSON.parse(cli('status', '--json').stdout || '[]');
|
|
37
|
+
data[0]?.slug === 'demo' && data[0].phases.roadmap.ref === 'r1' && data[0].phases.adr.ref === 'ADR-0023' ? ok('/workflow status surfaces phases + refs (ticket 041)') : bad(`status wrong: ${JSON.stringify(data[0])}`);
|
|
38
|
+
rmSync(proj, { recursive: true, force: true });
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** 043 — distill-detect surfaces rule-like phrases (positive + negative + skip-headers). */
|
|
42
|
+
async function testDistillDetect() {
|
|
43
|
+
const mod = await importKit('templates/contextkit/tools/scripts/distill-detect.mjs');
|
|
44
|
+
mod.detect('We decided that all auth flows must use refresh tokens. From now on, always validate JWTs.').length >= 2
|
|
45
|
+
? ok('distill-detect surfaces multiple rule-like phrases (ticket 043)') : bad('seeded sentence produced no candidates');
|
|
46
|
+
mod.detect('Today we fixed a minor bug in the login flow.').length === 0
|
|
47
|
+
? ok('distill-detect is quiet on neutral narrative (ticket 043 false-positive guard)') : bad('neutral paragraph triggered a candidate');
|
|
48
|
+
mod.detect('# We decided X\n> from now on Y').length === 0
|
|
49
|
+
? ok('distill-detect skips headings + blockquotes (ticket 043)') : bad('heading/blockquote triggered');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** 046 — /resume lifecycle: list, refuse unknown, refuse claim conflict, happy path. */
|
|
53
|
+
function testResumeCommand() {
|
|
54
|
+
const proj = tmp('resume');
|
|
55
|
+
run([join(KIT, 'install.mjs'), '--target', proj, '--level', '5', '--name', 'ResumeIT', '--yes']);
|
|
56
|
+
mkdirSync(join(proj, '.claude', '.sessions'), { recursive: true });
|
|
57
|
+
mkdirSync(join(proj, '.claude', '.workspace'), { recursive: true });
|
|
58
|
+
const sess = (id, extra) => JSON.stringify({ sessionId: id, startedAt: Date.now() - 3600000, modifications: [{ path: 'src/a.js', tool: 'Edit', at: Date.now() }], registered: false, stopWarnedAt: null, simulations: [], ...extra });
|
|
59
|
+
const ws = (id, claims) => JSON.stringify({ sessionId: id, branch: 'main', user: 'rt', startedAt: Date.now() - 3600000, lastHeartbeat: Date.now(), claims });
|
|
60
|
+
writeFileSync(join(proj, '.claude', '.sessions', 'sess-target.json'), sess('sess-target'));
|
|
61
|
+
writeFileSync(join(proj, '.claude', '.workspace', 'sess-target.json'), ws('sess-target', [{ path: 'src/a.js', claimedAt: Date.now() }]));
|
|
62
|
+
writeFileSync(join(proj, '.claude', '.sessions', 'sess-other.json'), sess('sess-other'));
|
|
63
|
+
const cli = (...args) => run([join(proj, 'contextkit', 'tools', 'scripts', 'resume.mjs'), ...args], { cwd: proj });
|
|
64
|
+
const listOut = cli();
|
|
65
|
+
listOut.stdout.includes('sess-target') && listOut.stdout.includes('sess-other') ? ok('/resume lists unregistered drift candidates (ticket 046)') : bad(`list: ${listOut.stdout}`);
|
|
66
|
+
const badId = cli('nope-not-real');
|
|
67
|
+
badId.status === 1 && /not found among unregistered/.test(badId.stderr + badId.stdout) ? ok('/resume refuses unknown session id (rule 8)') : bad(`unknown-id: ${badId.stderr}`);
|
|
68
|
+
writeFileSync(join(proj, '.claude', '.workspace', 'sess-active.json'), ws('sess-active', [{ path: 'src/a.js', claimedAt: Date.now() }]));
|
|
69
|
+
const conflict = cli('sess-target');
|
|
70
|
+
conflict.status === 1 && /claimed by another active session/.test(conflict.stderr + conflict.stdout) ? ok('/resume refuses cross-session claim conflict (ticket 046)') : bad(`conflict: ${conflict.stderr}`);
|
|
71
|
+
writeFileSync(join(proj, '.claude', '.workspace', 'sess-active.json'), ws('sess-active', []));
|
|
72
|
+
const happy = cli('sess-target');
|
|
73
|
+
const pointer = existsSync(join(proj, '.claude', '.sessions', '.last-touched')) ? JSON.parse(readFileSync(join(proj, '.claude', '.sessions', '.last-touched'), 'utf-8')) : {};
|
|
74
|
+
happy.status === 0 && pointer.sessionId === 'sess-target' ? ok('/resume rewrites .last-touched on success') : bad(`happy: status=${happy.status}, pointer=${JSON.stringify(pointer)}`);
|
|
75
|
+
rmSync(proj, { recursive: true, force: true });
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async function main() {
|
|
79
|
+
testWorkflowMacro();
|
|
80
|
+
await testDistillDetect();
|
|
81
|
+
testResumeCommand();
|
|
82
|
+
rep.finish('Integration (Compozy)');
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
main().catch((err) => {
|
|
86
|
+
bad(`Compozy crashed: ${err?.stack || err}`);
|
|
87
|
+
rep.finish('Integration (Compozy)');
|
|
88
|
+
});
|