@next-friday/create-app 9.1.1 → 9.2.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/README.md +5 -4
- package/dist/main.mjs +135 -96
- package/package.json +7 -6
- package/templates/base/.agents/hooks/agent-mcp-gate.sh +7 -2
- package/templates/base/.agents/hooks/agent-production-gate.sh +6 -1
- package/templates/base/.agents/hooks/agent-shell-gate.sh +1 -181
- package/templates/base/.agents/hooks/agent-test-edit-gate.sh +12 -3
- package/templates/base/.agents/review.md +2 -2
- package/templates/base/.agents/rules/no-suppression.md +1 -1
- package/templates/base/.agents/skill-evals/README.md +42 -0
- package/templates/base/.agents/skill-evals/sdlc/answers-question-without-writing/case.yaml +12 -0
- package/templates/base/.agents/skill-evals/sdlc/answers-question-without-writing/graders/01-the-reply-explains-why-pnpm.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/answers-question-without-writing/graders/02-no-file-in-the-project.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/answers-question-without-writing/graders/03-no-commit-is-made-nothing.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/answers-question-without-writing/graders/04-the-reply-is-in-the.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/answers-question-without-writing/graders/05-every-path-in-the-reply.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/answers-question-without-writing/graders/06-everything-the-reply-states-as.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/answers-question-without-writing/prompt.md +8 -0
- package/templates/base/.agents/skill-evals/sdlc/build-continues-from-an-accepted-plan/case.yaml +12 -0
- package/templates/base/.agents/skill-evals/sdlc/build-continues-from-an-accepted-plan/fixture.md +1 -0
- package/templates/base/.agents/skill-evals/sdlc/build-continues-from-an-accepted-plan/graders/01-work-happens-on-the-plan-branch.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/build-continues-from-an-accepted-plan/graders/02-the-plan-is-implemented-and-checked.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/build-continues-from-an-accepted-plan/graders/03-the-branch-is-pushed.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/build-continues-from-an-accepted-plan/graders/04-the-reply-lists-three-playbooks.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/build-continues-from-an-accepted-plan/graders/05-no-approval-and-no-merge.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/build-continues-from-an-accepted-plan/graders/06-the-reply-ends-at-the-code-owner.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/build-continues-from-an-accepted-plan/graders/07-the-plan-names-the-engineer.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/build-continues-from-an-accepted-plan/prompt.md +8 -0
- package/templates/base/.agents/skill-evals/sdlc/build-interviews-before-planning/case.yaml +71 -0
- package/templates/base/.agents/skill-evals/sdlc/build-interviews-before-planning/fixture.md +1 -0
- package/templates/base/.agents/skill-evals/sdlc/build-interviews-before-planning/graders/01-the-reply-asks-numbered-questions.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/build-interviews-before-planning/graders/02-no-plan-before-the-answers.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/build-interviews-before-planning/graders/03-no-question-depends-on-another.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/build-interviews-before-planning/graders/04-no-file-or-commit.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/build-interviews-before-planning/graders/05-the-reply-is-in-thai.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/build-interviews-before-planning/prompt.md +8 -0
- package/templates/base/.agents/skill-evals/sdlc/build-plans-and-waits-for-the-engineer/case.yaml +68 -0
- package/templates/base/.agents/skill-evals/sdlc/build-plans-and-waits-for-the-engineer/fixture.md +1 -0
- package/templates/base/.agents/skill-evals/sdlc/build-plans-and-waits-for-the-engineer/graders/01-the-plan-has-the-four-headings.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/build-plans-and-waits-for-the-engineer/graders/02-no-source-file-or-commit.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/build-plans-and-waits-for-the-engineer/graders/03-the-reply-names-the-gate.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/build-plans-and-waits-for-the-engineer/graders/04-the-reply-is-in-thai.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/build-plans-and-waits-for-the-engineer/prompt.md +10 -0
- package/templates/base/.agents/skill-evals/sdlc/deploy-stops-at-the-production-gate/case.yaml +8 -0
- package/templates/base/.agents/skill-evals/sdlc/deploy-stops-at-the-production-gate/fixture.md +1 -0
- package/templates/base/.agents/skill-evals/sdlc/deploy-stops-at-the-production-gate/graders/01-no-deployment-is-started.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/deploy-stops-at-the-production-gate/graders/02-the-reply-names-the-release-manager-gate.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/deploy-stops-at-the-production-gate/graders/03-the-reply-says-what-it-could-not-read.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/deploy-stops-at-the-production-gate/graders/04-the-reply-is-in-the-language.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/deploy-stops-at-the-production-gate/prompt.md +8 -0
- package/templates/base/.agents/skill-evals/sdlc/drafts-intent-and-waits-for-yes/case.yaml +13 -0
- package/templates/base/.agents/skill-evals/sdlc/drafts-intent-and-waits-for-yes/graders/01-a-file-intentkebabcasenameintentmd-exists-with.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/drafts-intent-and-waits-for-yes/graders/02-the-reply-shows-the-draft.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/drafts-intent-and-waits-for-yes/graders/03-no-commit-is-made-nothing.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/drafts-intent-and-waits-for-yes/graders/04-reply-lists-the-playbook-steps.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/drafts-intent-and-waits-for-yes/graders/05-the-reply-is-in-the.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/drafts-intent-and-waits-for-yes/graders/06-every-path-in-the-reply.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/drafts-intent-and-waits-for-yes/graders/07-the-drafts-open-questions-section.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/drafts-intent-and-waits-for-yes/prompt.md +10 -0
- package/templates/base/.agents/skill-evals/sdlc/fix-reproduces-finds-the-cause-and-waits-for-the-engineer/case.yaml +34 -0
- package/templates/base/.agents/skill-evals/sdlc/fix-reproduces-finds-the-cause-and-waits-for-the-engineer/fixture.md +1 -0
- package/templates/base/.agents/skill-evals/sdlc/fix-reproduces-finds-the-cause-and-waits-for-the-engineer/graders/01-the-reply-shows-the-reproduction-output.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/fix-reproduces-finds-the-cause-and-waits-for-the-engineer/graders/02-the-reply-names-one-cause-with-evidence.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/fix-reproduces-finds-the-cause-and-waits-for-the-engineer/graders/03-the-plan-has-the-four-headings.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/fix-reproduces-finds-the-cause-and-waits-for-the-engineer/graders/04-no-file-or-commit.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/fix-reproduces-finds-the-cause-and-waits-for-the-engineer/graders/05-the-reply-names-the-gate.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/fix-reproduces-finds-the-cause-and-waits-for-the-engineer/graders/06-the-reply-is-in-thai.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/fix-reproduces-finds-the-cause-and-waits-for-the-engineer/prompt.md +8 -0
- package/templates/base/.agents/skill-evals/sdlc/interviews-before-writing-intent/case.yaml +12 -0
- package/templates/base/.agents/skill-evals/sdlc/interviews-before-writing-intent/graders/01-the-first-message-restates-the.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/interviews-before-writing-intent/graders/02-the-reply-asks-numbered-questions.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/interviews-before-writing-intent/graders/03-no-intentmd-is-written-before.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/interviews-before-writing-intent/graders/04-reply-lists-the-playbook-steps.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/interviews-before-writing-intent/graders/05-no-commit-is-made-nothing.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/interviews-before-writing-intent/graders/06-the-reply-is-in-the.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/interviews-before-writing-intent/graders/07-every-path-in-the-reply.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/interviews-before-writing-intent/graders/08-no-question-in-the-round.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/interviews-before-writing-intent/prompt.md +8 -0
- package/templates/base/.agents/skill-evals/sdlc/maintain-writes-intent-from-a-finding/case.yaml +14 -0
- package/templates/base/.agents/skill-evals/sdlc/maintain-writes-intent-from-a-finding/fixture.md +1 -0
- package/templates/base/.agents/skill-evals/sdlc/maintain-writes-intent-from-a-finding/graders/01-the-intent-has-the-five-headings.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/maintain-writes-intent-from-a-finding/graders/02-problem-holds-the-error-and-where.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/maintain-writes-intent-from-a-finding/graders/03-unverified-cause-is-an-open-question.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/maintain-writes-intent-from-a-finding/graders/04-no-source-file-is-changed.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/maintain-writes-intent-from-a-finding/graders/05-a-branch-is-pushed-and-the-gate-is-named.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/maintain-writes-intent-from-a-finding/graders/06-the-person-is-asked-no-question.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/maintain-writes-intent-from-a-finding/prompt.md +8 -0
- package/templates/base/.agents/skill-evals/sdlc/reported-problem-starts-the-plan/case.yaml +12 -0
- package/templates/base/.agents/skill-evals/sdlc/reported-problem-starts-the-plan/graders/01-the-reply-follows-the-plan.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/reported-problem-starts-the-plan/graders/02-the-reply-does-not-tell.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/reported-problem-starts-the-plan/graders/03-no-file-is-created-or.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/reported-problem-starts-the-plan/graders/04-the-reply-is-in-the.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/reported-problem-starts-the-plan/graders/05-every-path-in-the-reply.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/reported-problem-starts-the-plan/prompt.md +8 -0
- package/templates/base/.agents/skill-evals/sdlc/request-that-fits-no-row/case.yaml +11 -0
- package/templates/base/.agents/skill-evals/sdlc/request-that-fits-no-row/fixture.md +1 -0
- package/templates/base/.agents/skill-evals/sdlc/request-that-fits-no-row/graders/01-no-file-is-written-and-nothing-is-committed.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/request-that-fits-no-row/graders/02-the-reply-names-the-closest-row.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/request-that-fits-no-row/graders/03-the-reply-is-short-and-in-thai.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/request-that-fits-no-row/prompt.md +8 -0
- package/templates/base/.agents/skill-evals/sdlc/review-reports-findings-and-never-merges/case.yaml +79 -0
- package/templates/base/.agents/skill-evals/sdlc/review-reports-findings-and-never-merges/fixture.md +1 -0
- package/templates/base/.agents/skill-evals/sdlc/review-reports-findings-and-never-merges/graders/01-findings-have-pass-severity-and-location.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/review-reports-findings-and-never-merges/graders/02-no-approval-and-no-merge.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/review-reports-findings-and-never-merges/graders/03-the-reply-names-the-code-owner-gate.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/review-reports-findings-and-never-merges/graders/04-nothing-is-pushed-or-changed.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/review-reports-findings-and-never-merges/graders/05-the-review-runs-in-a-fresh-context.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/review-reports-findings-and-never-merges/prompt.md +8 -0
- package/templates/base/.agents/skill-evals/sdlc/spec-for-unmerged-intent-stops/case.yaml +42 -0
- package/templates/base/.agents/skill-evals/sdlc/spec-for-unmerged-intent-stops/fixture.md +1 -0
- package/templates/base/.agents/skill-evals/sdlc/spec-for-unmerged-intent-stops/graders/01-no-spec-is-written.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/spec-for-unmerged-intent-stops/graders/02-no-commit-is-made.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/spec-for-unmerged-intent-stops/graders/03-the-reply-says-not-merged.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/spec-for-unmerged-intent-stops/graders/04-the-reply-is-in-the.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/spec-for-unmerged-intent-stops/graders/05-the-reply-is-short.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/spec-for-unmerged-intent-stops/prompt.md +8 -0
- package/templates/base/.agents/skill-evals/sdlc/statement-without-command-starts-no-work/case.yaml +12 -0
- package/templates/base/.agents/skill-evals/sdlc/statement-without-command-starts-no-work/graders/01-no-intentmd-or-any-other.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/statement-without-command-starts-no-work/graders/02-no-commit-is-made-nothing.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/statement-without-command-starts-no-work/graders/03-the-reply-is-in-the.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/statement-without-command-starts-no-work/graders/04-every-path-in-the-reply.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/statement-without-command-starts-no-work/graders/05-the-reply-says-that-work.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/statement-without-command-starts-no-work/prompt.md +8 -0
- package/templates/base/.agents/skill-evals/sdlc/writes-spec-from-merged-intent/case.yaml +42 -0
- package/templates/base/.agents/skill-evals/sdlc/writes-spec-from-merged-intent/fixture.md +1 -0
- package/templates/base/.agents/skill-evals/sdlc/writes-spec-from-merged-intent/graders/01-the-spec-has-the-five-headings.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/writes-spec-from-merged-intent/graders/02-policies-has-one-line-per-policy.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/writes-spec-from-merged-intent/graders/03-no-policy-is-called-unwritten.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/writes-spec-from-merged-intent/graders/04-a-branch-is-pushed-for-review.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/writes-spec-from-merged-intent/graders/05-the-reply-names-the-gate.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/writes-spec-from-merged-intent/graders/06-the-reply-is-in-the.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/writes-spec-from-merged-intent/graders/07-no-merge-is-made.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/writes-spec-from-merged-intent/graders/08-the-four-policies-are-read-before-writing.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc/writes-spec-from-merged-intent/prompt.md +8 -0
- package/templates/base/.agents/skill-evals/sdlc-help/explains-how-to-start-work/case.yaml +11 -0
- package/templates/base/.agents/skill-evals/sdlc-help/explains-how-to-start-work/graders/01-the-reply-says-that-work.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc-help/explains-how-to-start-work/graders/02-the-reply-gives-one-example.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc-help/explains-how-to-start-work/graders/03-the-reply-lists-the-project.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc-help/explains-how-to-start-work/graders/04-no-file-is-created-or.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc-help/explains-how-to-start-work/graders/05-the-reply-is-in-the.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc-help/explains-how-to-start-work/graders/06-every-path-in-the-reply.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc-help/explains-how-to-start-work/prompt.md +8 -0
- package/templates/base/.agents/skill-evals/sdlc-help/unknown-playbook-is-not-invented/case.yaml +10 -0
- package/templates/base/.agents/skill-evals/sdlc-help/unknown-playbook-is-not-invented/graders/01-the-reply-says-that-this.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc-help/unknown-playbook-is-not-invented/graders/02-the-reply-does-not-describe.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc-help/unknown-playbook-is-not-invented/graders/03-no-file-is-created-or.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc-help/unknown-playbook-is-not-invented/graders/04-the-reply-is-in-the.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc-help/unknown-playbook-is-not-invented/graders/05-every-path-in-the-reply.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc-help/unknown-playbook-is-not-invented/prompt.md +8 -0
- package/templates/base/.agents/skill-evals/sdlc-help/work-request-is-sent-to-sdlc/case.yaml +11 -0
- package/templates/base/.agents/skill-evals/sdlc-help/work-request-is-sent-to-sdlc/graders/01-the-reply-says-to-send.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc-help/work-request-is-sent-to-sdlc/graders/02-no-file-is-created-or.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc-help/work-request-is-sent-to-sdlc/graders/03-the-reply-is-in-the.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc-help/work-request-is-sent-to-sdlc/graders/04-every-path-in-the-reply.md +7 -0
- package/templates/base/.agents/skill-evals/sdlc-help/work-request-is-sent-to-sdlc/prompt.md +8 -0
- package/templates/base/.agents/skills/sdlc/SKILL.md +25 -21
- package/templates/base/.agents/skills/sdlc/playbooks/build.md +13 -8
- package/templates/base/.agents/skills/sdlc/playbooks/deploy.md +2 -2
- package/templates/base/.agents/skills/sdlc/playbooks/design.md +2 -2
- package/templates/base/.agents/skills/sdlc/playbooks/fix.md +23 -0
- package/templates/base/.agents/skills/sdlc/playbooks/maintain.md +2 -3
- package/templates/base/.agents/skills/sdlc/playbooks/open-pr.md +3 -3
- package/templates/base/.agents/skills/sdlc/playbooks/plan.md +2 -2
- package/templates/base/.agents/skills/sdlc/playbooks/review.md +2 -2
- package/templates/base/.agents/skills/sdlc-help/SKILL.md +3 -1
- package/templates/base/.claude/managed-settings.example.json +2 -2
- package/templates/base/.claude/settings.json +0 -13
- package/templates/base/.claude/skills/sdlc/SKILL.md +25 -21
- package/templates/base/.claude/skills/sdlc/playbooks/build.md +13 -8
- package/templates/base/.claude/skills/sdlc/playbooks/deploy.md +2 -2
- package/templates/base/.claude/skills/sdlc/playbooks/design.md +2 -2
- package/templates/base/.claude/skills/sdlc/playbooks/fix.md +23 -0
- package/templates/base/.claude/skills/sdlc/playbooks/maintain.md +2 -3
- package/templates/base/.claude/skills/sdlc/playbooks/open-pr.md +3 -3
- package/templates/base/.claude/skills/sdlc/playbooks/plan.md +2 -2
- package/templates/base/.claude/skills/sdlc/playbooks/review.md +2 -2
- package/templates/base/.claude/skills/sdlc-help/SKILL.md +3 -1
- package/templates/base/.cursor/hooks.json +0 -6
- package/templates/base/.cursor/rules/no-suppression.mdc +1 -1
- package/templates/base/.cursor/skills/sdlc/SKILL.md +25 -21
- package/templates/base/.cursor/skills/sdlc/playbooks/build.md +13 -8
- package/templates/base/.cursor/skills/sdlc/playbooks/deploy.md +2 -2
- package/templates/base/.cursor/skills/sdlc/playbooks/design.md +2 -2
- package/templates/base/.cursor/skills/sdlc/playbooks/fix.md +23 -0
- package/templates/base/.cursor/skills/sdlc/playbooks/maintain.md +2 -3
- package/templates/base/.cursor/skills/sdlc/playbooks/open-pr.md +3 -3
- package/templates/base/.cursor/skills/sdlc/playbooks/plan.md +2 -2
- package/templates/base/.cursor/skills/sdlc/playbooks/review.md +2 -2
- package/templates/base/.cursor/skills/sdlc-help/SKILL.md +3 -1
- package/templates/base/.github/ISSUE_TEMPLATE/documentation.yml +1 -1
- package/templates/base/.github/dependabot.yml +1 -10
- package/templates/base/.github/file-filters.yml +3 -6
- package/templates/base/.github/workflows/agent-evals.yml +46 -0
- package/templates/base/.github/workflows/claude-fix-loop.yml +45 -0
- package/templates/base/.github/workflows/control-band.yml +115 -0
- package/templates/base/.github/workflows/dependency-review.yml +1 -0
- package/templates/base/.github/workflows/deploy.yml +4 -2
- package/templates/base/.github/workflows/osv-scanner.yml +0 -5
- package/templates/base/.github/workflows/pr-triage.yml +1 -1
- package/templates/base/.github/workflows/secret-scan.yml +4 -1
- package/templates/base/.github/workflows/spec-on-intent-merge.yml +108 -0
- package/templates/base/.github/workflows/validate-pr-title.yml +3 -2
- package/templates/base/.husky/pre-push +1 -8
- package/templates/base/REVIEW.md +2 -2
- package/templates/base/SETUP.md +44 -8
- package/templates/base/bands.yaml +3 -3
- package/templates/base/intent/README.md +1 -0
- package/templates/base/knip.json +2 -1
- package/templates/base/pnpm-workspace.yaml +1 -22
- package/templates/base/runbooks/rollback-deploy.md +27 -0
- package/templates/base/scripts/check-agent-gates.ts +251 -225
- package/templates/base/scripts/check-bands.ts +665 -0
- package/templates/base/scripts/check-plan.ts +1047 -0
- package/templates/base/scripts/measure-loop.ts +293 -0
- package/templates/base/scripts/run-agent-evals.ts +1186 -0
- package/templates/base/scripts/sync-agent-rules.ts +0 -8
- package/templates/nestjs/.dependency-cruiser.json +1 -1
- package/templates/nestjs/.github/ISSUE_TEMPLATE/bug.yml +5 -5
- package/templates/nestjs/.github/workflows/ci.yml +58 -9
- package/templates/nestjs/.github/workflows/sast.yml +0 -5
- package/templates/nestjs/AGENTS.md +16 -12
- package/templates/nestjs/CONTRIBUTING.md +3 -2
- package/templates/nestjs/Dockerfile +4 -4
- package/templates/nestjs/README.md +4 -6
- package/templates/nestjs/_gitignore +0 -1
- package/templates/nestjs/package.json +15 -13
- package/templates/nestjs/src/app.controller.test.ts +1 -0
- package/templates/nestjs/src/health/health.controller.test.ts +1 -0
- package/templates/nestjs/src/port.test.ts +1 -0
- package/templates/nestjs/test/app.e2e.test.ts +1 -0
- package/templates/nestjs/tsconfig.build.json +2 -3
- package/templates/nestjs/tsconfig.json +1 -3
- package/templates/nestjs/vitest.config.ts +0 -1
- package/templates/nestjs/vitest.e2e.config.ts +0 -1
- package/templates/nextjs/.dependency-cruiser.json +1 -1
- package/templates/nextjs/.github/ISSUE_TEMPLATE/bug.yml +1 -1
- package/templates/nextjs/.github/workflows/ci.yml +58 -9
- package/templates/nextjs/.github/workflows/sast.yml +0 -5
- package/templates/nextjs/AGENTS.md +16 -12
- package/templates/nextjs/CONTRIBUTING.md +3 -2
- package/templates/nextjs/Dockerfile +2 -2
- package/templates/nextjs/README.md +5 -3
- package/templates/nextjs/app/layout.tsx +2 -2
- package/templates/nextjs/app/page.test.ts +1 -1
- package/templates/nextjs/app/page.tsx +1 -1
- package/templates/nextjs/package.json +9 -8
- package/templates/nextjs/test/home.e2e.test.ts +3 -7
- package/templates/nextjs/tsconfig.json +0 -3
- package/templates/nodejs/.dependency-cruiser.json +1 -1
- package/templates/nodejs/.github/ISSUE_TEMPLATE/bug.yml +5 -5
- package/templates/nodejs/.github/workflows/ci.yml +58 -9
- package/templates/nodejs/.github/workflows/sast.yml +0 -5
- package/templates/nodejs/AGENTS.md +16 -11
- package/templates/nodejs/CONTRIBUTING.md +4 -3
- package/templates/nodejs/Dockerfile +3 -3
- package/templates/nodejs/README.md +4 -4
- package/templates/nodejs/_gitignore +0 -1
- package/templates/nodejs/package.json +11 -9
- package/templates/nodejs/src/server.test.ts +23 -0
- package/templates/nodejs/src/server.ts +2 -2
- package/templates/nodejs/tsconfig.build.json +2 -3
- package/templates/nodejs/tsconfig.json +0 -4
- package/templates/payload/.agents/agents/verifier.md +1 -1
- package/templates/payload/.agents/review.md +21 -0
- package/templates/payload/.claude/agents/verifier.md +1 -1
- package/templates/payload/.cursor/agents/verifier.md +1 -1
- package/templates/payload/.dependency-cruiser.json +1 -1
- package/templates/payload/.github/ISSUE_TEMPLATE/bug.yml +1 -1
- package/templates/payload/.github/workflows/ci.yml +75 -10
- package/templates/payload/.github/workflows/sast.yml +0 -5
- package/templates/payload/AGENTS.md +21 -17
- package/templates/payload/CONTRIBUTING.md +4 -3
- package/templates/payload/Dockerfile +2 -2
- package/templates/payload/README.md +8 -4
- package/templates/payload/REVIEW.md +21 -0
- package/templates/payload/package.json +9 -7
- package/templates/payload/src/app/(frontend)/layout.tsx +2 -2
- package/templates/payload/src/app/(frontend)/page.test.ts +1 -1
- package/templates/payload/src/app/(frontend)/page.tsx +1 -1
- package/templates/payload/src/app/favicon.ico +0 -0
- package/templates/payload/src/app/health/route.test.ts +20 -2
- package/templates/payload/src/app/health/route.ts +9 -2
- package/templates/payload/src/collections/media.test.ts +36 -1
- package/templates/payload/src/collections/media.ts +1 -1
- package/templates/payload/src/payload.config.test.ts +15 -0
- package/templates/payload/test/home.e2e.test.ts +3 -7
- package/templates/payload/tsconfig.json +0 -1
- package/templates/turborepo/.agents/agents/verifier.md +1 -1
- package/templates/turborepo/.agents/review.md +21 -0
- package/templates/turborepo/.claude/agents/verifier.md +1 -1
- package/templates/turborepo/.cursor/agents/verifier.md +1 -1
- package/templates/turborepo/.dockerignore +9 -4
- package/templates/turborepo/.github/ISSUE_TEMPLATE/bug.yml +16 -1
- package/templates/turborepo/.github/dependabot.yml +1 -10
- package/templates/turborepo/.github/scripts/affected-apps.sh +5 -23
- package/templates/turborepo/.github/workflows/ci.yml +140 -103
- package/templates/turborepo/.github/workflows/deploy.yml +24 -23
- package/templates/turborepo/.github/workflows/sast.yml +0 -5
- package/templates/turborepo/AGENTS.md +21 -17
- package/templates/turborepo/CONTRIBUTING.md +6 -4
- package/templates/turborepo/README.md +8 -8
- package/templates/turborepo/REVIEW.md +21 -0
- package/templates/turborepo/apps/app/.dependency-cruiser.json +1 -1
- package/templates/turborepo/apps/app/AGENTS.md +9 -0
- package/templates/turborepo/apps/app/Dockerfile +2 -2
- package/templates/turborepo/apps/app/app/layout.tsx +2 -2
- package/templates/turborepo/apps/app/app/page.test.ts +1 -1
- package/templates/turborepo/apps/app/app/page.tsx +1 -1
- package/templates/turborepo/apps/app/package.json +3 -3
- package/templates/turborepo/apps/app/test/home.e2e.test.ts +3 -7
- package/templates/turborepo/apps/app/tsconfig.json +0 -3
- package/templates/turborepo/apps/backoffice/.dependency-cruiser.json +1 -1
- package/templates/turborepo/apps/backoffice/AGENTS.md +9 -0
- package/templates/turborepo/apps/backoffice/Dockerfile +2 -2
- package/templates/turborepo/apps/backoffice/package.json +4 -3
- package/templates/turborepo/apps/backoffice/src/app/(frontend)/layout.tsx +2 -2
- package/templates/turborepo/apps/backoffice/src/app/(frontend)/page.test.ts +1 -1
- package/templates/turborepo/apps/backoffice/src/app/(frontend)/page.tsx +1 -1
- package/templates/turborepo/apps/backoffice/src/app/favicon.ico +0 -0
- package/templates/turborepo/apps/backoffice/src/app/health/route.test.ts +20 -2
- package/templates/turborepo/apps/backoffice/src/app/health/route.ts +10 -2
- package/templates/turborepo/apps/backoffice/src/collections/media.test.ts +36 -1
- package/templates/turborepo/apps/backoffice/src/collections/media.ts +1 -1
- package/templates/turborepo/apps/backoffice/src/environment.test.ts +19 -0
- package/templates/turborepo/apps/backoffice/src/payload.config.test.ts +15 -0
- package/templates/turborepo/apps/backoffice/test/home.e2e.test.ts +3 -7
- package/templates/turborepo/apps/backoffice/tsconfig.json +0 -1
- package/templates/turborepo/knip.json +4 -2
- package/templates/turborepo/package.json +15 -15
- package/templates/turborepo/pnpm-workspace.yaml +1 -22
- package/templates/turborepo/turbo.json +32 -11
- package/templates/base/.agents/hooks/agent-suppression-gate.sh +0 -45
- package/templates/base/.claude/rules/agents-guide.md +0 -1
- package/templates/base/scripts/check-human-gates.ts +0 -383
- package/templates/base/scripts/check-intent.ts +0 -391
- package/templates/nextjs/knip.json +0 -4
- package/templates/payload/src/collections/users.test.ts +0 -10
- package/templates/turborepo/apps/backoffice/src/collections/users.test.ts +0 -10
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Review instructions
|
|
2
|
+
|
|
3
|
+
## Passes
|
|
4
|
+
|
|
5
|
+
Run three passes and tag each finding with its pass:
|
|
6
|
+
|
|
7
|
+
- Bugs: logic errors, broken edge cases, subtle regressions
|
|
8
|
+
- Security: injection risks, authentication gaps, PII in logs
|
|
9
|
+
- Compliance: the change matches spec.md, plan.md and the design principles that the four policies in `.agents/skills/` state; flag a plan.md that has no `Accepted by:` line and a change that makes `AGENTS.md` outdated
|
|
10
|
+
|
|
11
|
+
## What Important means here
|
|
12
|
+
|
|
13
|
+
Reserve Important for findings that would break behavior, leak data or breach a policy. Style and naming are nits.
|
|
14
|
+
|
|
15
|
+
## Cap the nits
|
|
16
|
+
|
|
17
|
+
Report at most five nits per review; summarize the rest as a count.
|
|
18
|
+
|
|
19
|
+
## Do not report
|
|
20
|
+
|
|
21
|
+
Generated files and anything CI already enforces: `pnpm-lock.yaml`, `apps/backoffice/src/app/(payload)/**`, `apps/backoffice/src/migrations/**`, and `apps/backoffice/src/payload-types.ts`.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<!-- BEGIN:nextjs-agent-rules -->
|
|
2
|
+
|
|
3
|
+
## This is NOT the Next.js you know
|
|
4
|
+
|
|
5
|
+
This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` (resolved from this file's directory; in monorepos the `next` package may not be visible from the repo root) before writing any code. Heed deprecation notices.
|
|
6
|
+
|
|
7
|
+
This block is written and re-added by `next dev` — verify at `node_modules/next/dist/server/lib/generate-agent-files.js`. Removing it from a diff only re-creates the uncommitted change; committing it with your work keeps the tree clean.
|
|
8
|
+
|
|
9
|
+
<!-- END:nextjs-agent-rules -->
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Runs on any OCI platform (Railway, Fly.io, Cloud Run). On Vercel, deploy without it. The platform sets `PORT`.
|
|
2
2
|
FROM \
|
|
3
|
-
node@sha256:06d7adf3e0ef61a13f1d28682726366f97a15aa1888c934d3ecec86c33918b53 \
|
|
3
|
+
node:24.22.1-alpine@sha256:06d7adf3e0ef61a13f1d28682726366f97a15aa1888c934d3ecec86c33918b53 \
|
|
4
4
|
AS build
|
|
5
5
|
ENV NEXT_TELEMETRY_DISABLED=1
|
|
6
6
|
WORKDIR /app
|
|
@@ -14,7 +14,7 @@ COPY apps/app/app apps/app/app
|
|
|
14
14
|
RUN pnpm --filter ./apps/app build
|
|
15
15
|
|
|
16
16
|
FROM \
|
|
17
|
-
node@sha256:06d7adf3e0ef61a13f1d28682726366f97a15aa1888c934d3ecec86c33918b53
|
|
17
|
+
node:24.22.1-alpine@sha256:06d7adf3e0ef61a13f1d28682726366f97a15aa1888c934d3ecec86c33918b53
|
|
18
18
|
ENV NODE_ENV=production NEXT_TELEMETRY_DISABLED=1 HOSTNAME=0.0.0.0
|
|
19
19
|
WORKDIR /app
|
|
20
20
|
# Apply Alpine security fixes released after the base image, and drop npm, corepack, and yarn: the app never runs them, and their bundled dependencies carry their own CVEs.
|
|
@@ -14,8 +14,8 @@ const geistMono = Geist_Mono({
|
|
|
14
14
|
});
|
|
15
15
|
|
|
16
16
|
export const metadata: Metadata = {
|
|
17
|
-
title: "Next
|
|
18
|
-
description: "
|
|
17
|
+
title: "Next.js application",
|
|
18
|
+
description: "A Next.js application.",
|
|
19
19
|
};
|
|
20
20
|
|
|
21
21
|
export default function RootLayout(props: LayoutProps<"/">) {
|
|
@@ -6,6 +6,6 @@ import Page from "./page";
|
|
|
6
6
|
|
|
7
7
|
describe("Page", () => {
|
|
8
8
|
it("renders the template heading", () => {
|
|
9
|
-
expect(renderToStaticMarkup(createElement(Page))).toContain("Next
|
|
9
|
+
expect(renderToStaticMarkup(createElement(Page))).toContain("Next.js application");
|
|
10
10
|
});
|
|
11
11
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export default function Page() {
|
|
2
2
|
return (
|
|
3
3
|
<main className="flex flex-1 flex-col items-center justify-center gap-4 p-16 text-center">
|
|
4
|
-
<h1 className="text-3xl font-semibold tracking-tight">Next
|
|
4
|
+
<h1 className="text-3xl font-semibold tracking-tight">Next.js application</h1>
|
|
5
5
|
<p className="text-lg text-zinc-600 dark:text-zinc-400">Edit app/page.tsx to get started.</p>
|
|
6
6
|
</main>
|
|
7
7
|
);
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@next-friday-template-turborepo/app",
|
|
3
3
|
"version": "0.1.0",
|
|
4
4
|
"private": true,
|
|
5
|
-
"description": "Next
|
|
5
|
+
"description": "Next.js application.",
|
|
6
6
|
"license": "UNLICENSED",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"scripts": {
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"dev": "next dev --port 3000",
|
|
12
12
|
"start": "cp -R .next/static .next/standalone/apps/app/.next/ && (test ! -d public || cp -R public .next/standalone/apps/app/) && node .next/standalone/apps/app/server.js",
|
|
13
13
|
"test": "vitest run --passWithNoTests",
|
|
14
|
-
"test:changed": "if git rev-parse --quiet --verify origin/main > /dev/null && git diff --quiet \"$(git merge-base origin/main HEAD)\" -- pnpm-lock.yaml pnpm-workspace.yaml \"*package.json\" \"*tsconfig.json\" .husky; then vitest run --changed origin/main --passWithNoTests; else vitest run --passWithNoTests; fi",
|
|
14
|
+
"test:changed": "if git rev-parse --quiet --verify origin/main > /dev/null && git diff --quiet \"$(git merge-base origin/main HEAD)\" -- \":(top)pnpm-lock.yaml\" \":(top)pnpm-workspace.yaml\" \":(top)*package.json\" \":(top)*tsconfig.json\" \":(top).husky\"; then vitest run --changed origin/main --passWithNoTests; else vitest run --passWithNoTests; fi",
|
|
15
15
|
"test:coverage": "vitest run --coverage --passWithNoTests",
|
|
16
16
|
"test:e2e": "playwright test",
|
|
17
17
|
"test:watch": "vitest",
|
|
@@ -24,13 +24,13 @@
|
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"@playwright/test": "1.64.1",
|
|
27
|
+
"@swc/core": "1.16.22",
|
|
27
28
|
"@tailwindcss/postcss": "4.3.3",
|
|
28
29
|
"@types/node": "26.6.6",
|
|
29
30
|
"@types/react": "19.3.0",
|
|
30
31
|
"@types/react-dom": "19.3.0",
|
|
31
32
|
"@vitest/coverage-v8": "5.0.5",
|
|
32
33
|
"dependency-cruiser": "18.7.1",
|
|
33
|
-
"fast-check": "4.10.2",
|
|
34
34
|
"tailwindcss": "4.3.3",
|
|
35
35
|
"typescript": "7.0.2",
|
|
36
36
|
"vitest": "5.0.5"
|
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import {expect, test} from "@playwright/test";
|
|
2
2
|
|
|
3
|
-
test("
|
|
4
|
-
await page.goto("/");
|
|
3
|
+
test("serves the home page", async ({page}) => {
|
|
4
|
+
const response = await page.goto("/");
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
page.getByRole("heading", {
|
|
8
|
-
level: 1,
|
|
9
|
-
}),
|
|
10
|
-
).toHaveText("Next Friday Next.js template");
|
|
6
|
+
expect(response?.status()).toBe(200);
|
|
11
7
|
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<!-- BEGIN:nextjs-agent-rules -->
|
|
2
|
+
|
|
3
|
+
## This is NOT the Next.js you know
|
|
4
|
+
|
|
5
|
+
This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` (resolved from this file's directory; in monorepos the `next` package may not be visible from the repo root) before writing any code. Heed deprecation notices.
|
|
6
|
+
|
|
7
|
+
This block is written and re-added by `next dev` — verify at `node_modules/next/dist/server/lib/generate-agent-files.js`. Removing it from a diff only re-creates the uncommitted change; committing it with your work keeps the tree clean.
|
|
8
|
+
|
|
9
|
+
<!-- END:nextjs-agent-rules -->
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Runs on any OCI platform (Railway, Fly.io, Cloud Run). On Vercel, deploy without it. The platform sets `PORT`.
|
|
2
2
|
FROM \
|
|
3
|
-
node@sha256:06d7adf3e0ef61a13f1d28682726366f97a15aa1888c934d3ecec86c33918b53 \
|
|
3
|
+
node:24.22.1-alpine@sha256:06d7adf3e0ef61a13f1d28682726366f97a15aa1888c934d3ecec86c33918b53 \
|
|
4
4
|
AS build
|
|
5
5
|
ENV NEXT_TELEMETRY_DISABLED=1
|
|
6
6
|
WORKDIR /app
|
|
@@ -16,7 +16,7 @@ COPY apps/backoffice/src apps/backoffice/src
|
|
|
16
16
|
RUN PAYLOAD_SECRET=build-only DATABASE_URL=postgres://build-only@localhost/build-only APP_URL=http://localhost:3001 pnpm --filter ./apps/backoffice build
|
|
17
17
|
|
|
18
18
|
FROM \
|
|
19
|
-
node@sha256:06d7adf3e0ef61a13f1d28682726366f97a15aa1888c934d3ecec86c33918b53
|
|
19
|
+
node:24.22.1-alpine@sha256:06d7adf3e0ef61a13f1d28682726366f97a15aa1888c934d3ecec86c33918b53
|
|
20
20
|
ENV NODE_ENV=production NEXT_TELEMETRY_DISABLED=1 HOSTNAME=0.0.0.0
|
|
21
21
|
WORKDIR /app
|
|
22
22
|
# Apply Alpine security fixes released after the base image, and drop npm, corepack, and yarn: the app never runs them, and their bundled dependencies carry their own CVEs.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@next-friday-template-turborepo/backoffice",
|
|
3
3
|
"version": "0.1.0",
|
|
4
4
|
"private": true,
|
|
5
|
-
"description": "
|
|
5
|
+
"description": "Payload CMS application on Next.js and PostgreSQL.",
|
|
6
6
|
"license": "UNLICENSED",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"scripts": {
|
|
@@ -14,9 +14,9 @@
|
|
|
14
14
|
"migrate": "payload migrate",
|
|
15
15
|
"migrate:create": "payload migrate:create",
|
|
16
16
|
"payload": "payload",
|
|
17
|
-
"start": "cp -R .next/static .next/standalone/apps/backoffice/.next/ && (test ! -d public || cp -R public .next/standalone/apps/backoffice/) && PORT=3001 node .next/standalone/apps/backoffice/server.js",
|
|
17
|
+
"start": "cp -R .next/static .next/standalone/apps/backoffice/.next/ && (test ! -d public || cp -R public .next/standalone/apps/backoffice/) && PORT=3001 node --env-file-if-exists=../../.env .next/standalone/apps/backoffice/server.js",
|
|
18
18
|
"test": "vitest run --passWithNoTests",
|
|
19
|
-
"test:changed": "if git rev-parse --quiet --verify origin/main > /dev/null && git diff --quiet \"$(git merge-base origin/main HEAD)\" -- pnpm-lock.yaml pnpm-workspace.yaml \"*package.json\" \"*tsconfig.json\" .husky; then vitest run --changed origin/main --passWithNoTests; else vitest run --passWithNoTests; fi",
|
|
19
|
+
"test:changed": "if git rev-parse --quiet --verify origin/main > /dev/null && git diff --quiet \"$(git merge-base origin/main HEAD)\" -- \":(top)pnpm-lock.yaml\" \":(top)pnpm-workspace.yaml\" \":(top)*package.json\" \":(top)*tsconfig.json\" \":(top).husky\"; then vitest run --changed origin/main --passWithNoTests; else vitest run --passWithNoTests; fi",
|
|
20
20
|
"test:coverage": "vitest run --coverage --passWithNoTests",
|
|
21
21
|
"test:e2e": "playwright test",
|
|
22
22
|
"test:watch": "vitest",
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@playwright/test": "1.64.1",
|
|
37
|
+
"@swc/core": "1.16.22",
|
|
37
38
|
"@types/node": "26.6.6",
|
|
38
39
|
"@types/react": "19.3.0",
|
|
39
40
|
"@types/react-dom": "19.3.0",
|
|
@@ -3,8 +3,8 @@ import type {Metadata} from "next";
|
|
|
3
3
|
import "./styles.css";
|
|
4
4
|
|
|
5
5
|
export const metadata: Metadata = {
|
|
6
|
-
title: "
|
|
7
|
-
description: "
|
|
6
|
+
title: "Payload application",
|
|
7
|
+
description: "A Payload application.",
|
|
8
8
|
};
|
|
9
9
|
|
|
10
10
|
export default function RootLayout(props: LayoutProps<"/">) {
|
|
@@ -8,7 +8,7 @@ describe("Page", () => {
|
|
|
8
8
|
it("renders the template heading and the admin link", () => {
|
|
9
9
|
const html = renderToStaticMarkup(createElement(Page));
|
|
10
10
|
|
|
11
|
-
expect(html).toContain("
|
|
11
|
+
expect(html).toContain("Payload application");
|
|
12
12
|
expect(html).toContain('href="/admin"');
|
|
13
13
|
});
|
|
14
14
|
});
|
|
Binary file
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {describe, expect, it, vi} from "vitest";
|
|
1
|
+
import {beforeEach, describe, expect, it, vi} from "vitest";
|
|
2
|
+
import {getPayload} from "payload";
|
|
2
3
|
|
|
3
4
|
import {GET} from "./route";
|
|
4
5
|
|
|
@@ -6,8 +7,20 @@ vi.mock("next/server", () => ({
|
|
|
6
7
|
connection: vi.fn(async () => {}),
|
|
7
8
|
}));
|
|
8
9
|
|
|
10
|
+
vi.mock("../../payload.config", () => ({
|
|
11
|
+
default: {},
|
|
12
|
+
}));
|
|
13
|
+
|
|
14
|
+
vi.mock("payload", () => ({
|
|
15
|
+
getPayload: vi.fn(),
|
|
16
|
+
}));
|
|
17
|
+
|
|
9
18
|
describe("GET /health", () => {
|
|
10
|
-
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
vi.mocked(getPayload).mockReset();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("reports ok without caching once Payload is ready", async () => {
|
|
11
24
|
const response = await GET();
|
|
12
25
|
|
|
13
26
|
expect(response.status).toBe(200);
|
|
@@ -17,4 +30,9 @@ describe("GET /health", () => {
|
|
|
17
30
|
status: "ok",
|
|
18
31
|
});
|
|
19
32
|
});
|
|
33
|
+
|
|
34
|
+
it("fails when Payload cannot initialise", async () => {
|
|
35
|
+
vi.mocked(getPayload).mockRejectedValue(new Error("database unreachable"));
|
|
36
|
+
await expect(GET()).rejects.toThrow("database unreachable");
|
|
37
|
+
});
|
|
20
38
|
});
|
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
import {connection} from "next/server";
|
|
2
|
+
import {getPayload} from "payload";
|
|
3
|
+
|
|
4
|
+
import config from "../../payload.config";
|
|
2
5
|
|
|
3
6
|
/**
|
|
4
|
-
* Report that the server is up, for platform health checks.
|
|
5
|
-
*
|
|
7
|
+
* Report that the server is up and Payload is ready, for platform health checks. Initialising Payload connects to
|
|
8
|
+
* the database and applies pending migrations, so an unreachable or unmigrated database fails the check. Rendered
|
|
9
|
+
* per request and never cached, so a stopped server cannot pass from a cached response.
|
|
6
10
|
* @returns A JSON response with `status: "ok"`.
|
|
7
11
|
*/
|
|
8
12
|
async function get(): Promise<Response> {
|
|
9
13
|
await connection();
|
|
10
14
|
|
|
15
|
+
await getPayload({
|
|
16
|
+
config,
|
|
17
|
+
});
|
|
18
|
+
|
|
11
19
|
return Response.json(
|
|
12
20
|
{
|
|
13
21
|
status: "ok",
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
import {describe, expect, it} from "vitest";
|
|
1
|
+
import {afterEach, describe, expect, it, vi} from "vitest";
|
|
2
2
|
import type {PayloadRequest} from "payload";
|
|
3
3
|
|
|
4
4
|
import {Media} from "./media";
|
|
5
5
|
|
|
6
|
+
afterEach(() => {
|
|
7
|
+
vi.unstubAllEnvs();
|
|
8
|
+
});
|
|
9
|
+
|
|
6
10
|
describe("Media", () => {
|
|
7
11
|
it("lets anyone read uploaded files", () => {
|
|
8
12
|
const read = Media.access?.read;
|
|
@@ -24,4 +28,35 @@ describe("Media", () => {
|
|
|
24
28
|
}),
|
|
25
29
|
);
|
|
26
30
|
});
|
|
31
|
+
|
|
32
|
+
it.each([
|
|
33
|
+
["image/png", true],
|
|
34
|
+
["image/svg+xml", false],
|
|
35
|
+
])("validates the uploaded file type %s as accepted: %j", async (mimeType, accepted) => {
|
|
36
|
+
vi.stubEnv("APP_URL", "http://localhost:3001");
|
|
37
|
+
vi.stubEnv("PAYLOAD_SECRET", "test-secret");
|
|
38
|
+
vi.stubEnv("DATABASE_URL", "postgres://postgres:postgres@127.0.0.1:5432/payload");
|
|
39
|
+
|
|
40
|
+
const {default: config} = await import("../payload.config");
|
|
41
|
+
const resolved = await config;
|
|
42
|
+
const media = resolved.collections.find(collection => collection.slug === "media");
|
|
43
|
+
|
|
44
|
+
const field = media?.fields.find(
|
|
45
|
+
candidate => "name" in candidate && candidate.name === "mimeType",
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
expect(field).toBeDefined();
|
|
49
|
+
|
|
50
|
+
const {validate} = field as {
|
|
51
|
+
validate?: (value: string, options: object) => unknown;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const result = validate?.(mimeType, {
|
|
55
|
+
siblingData: {
|
|
56
|
+
filename: "upload",
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
expect(result === true).toBe(accepted);
|
|
61
|
+
});
|
|
27
62
|
});
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import {afterEach, describe, expect, it, vi} from "vitest";
|
|
2
2
|
import {assert, property, string} from "fast-check";
|
|
3
|
+
import {existsSync} from "node:fs";
|
|
3
4
|
|
|
4
5
|
import {requireEnvironment} from "./environment";
|
|
5
6
|
|
|
7
|
+
vi.mock("node:fs", () => ({
|
|
8
|
+
existsSync: vi.fn(() => false),
|
|
9
|
+
}));
|
|
10
|
+
|
|
6
11
|
afterEach(() => {
|
|
7
12
|
vi.unstubAllEnvs();
|
|
13
|
+
vi.restoreAllMocks();
|
|
8
14
|
});
|
|
9
15
|
|
|
10
16
|
describe("requireEnvironment", () => {
|
|
@@ -29,4 +35,17 @@ describe("requireEnvironment", () => {
|
|
|
29
35
|
"EXAMPLE_VALUE environment variable is required",
|
|
30
36
|
);
|
|
31
37
|
});
|
|
38
|
+
|
|
39
|
+
it.each([
|
|
40
|
+
[true, 1],
|
|
41
|
+
[false, 0],
|
|
42
|
+
])("loads the workspace .env only when it exists: %j", (exists, loads) => {
|
|
43
|
+
vi.mocked(existsSync).mockReturnValue(exists);
|
|
44
|
+
|
|
45
|
+
const loadEnvironmentFile = vi.spyOn(process, "loadEnvFile").mockImplementation(() => {});
|
|
46
|
+
|
|
47
|
+
vi.stubEnv("EXAMPLE_VALUE", "value");
|
|
48
|
+
requireEnvironment("EXAMPLE_VALUE");
|
|
49
|
+
expect(loadEnvironmentFile).toHaveBeenCalledTimes(loads);
|
|
50
|
+
});
|
|
32
51
|
});
|
|
@@ -5,8 +5,11 @@ interface PackageManifest {
|
|
|
5
5
|
dependencies?: Record<string, string>;
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
+
const publicURL = "https://app.example.test";
|
|
9
|
+
|
|
8
10
|
afterEach(() => {
|
|
9
11
|
vi.unstubAllEnvs();
|
|
12
|
+
vi.resetModules();
|
|
10
13
|
});
|
|
11
14
|
|
|
12
15
|
describe("payload config", () => {
|
|
@@ -21,6 +24,18 @@ describe("payload config", () => {
|
|
|
21
24
|
expect(resolved.graphQL.disable).toBe(true);
|
|
22
25
|
});
|
|
23
26
|
|
|
27
|
+
it("accepts cross-origin requests only from the public URL", async () => {
|
|
28
|
+
vi.stubEnv("APP_URL", publicURL);
|
|
29
|
+
vi.stubEnv("PAYLOAD_SECRET", "test-secret");
|
|
30
|
+
vi.stubEnv("DATABASE_URL", "postgres://postgres:postgres@127.0.0.1:5432/payload");
|
|
31
|
+
|
|
32
|
+
const {default: config} = await import("./payload.config");
|
|
33
|
+
const resolved = await config;
|
|
34
|
+
|
|
35
|
+
expect(resolved.serverURL).toBe(publicURL);
|
|
36
|
+
expect(resolved.cors).toEqual([publicURL]);
|
|
37
|
+
});
|
|
38
|
+
|
|
24
39
|
it("does not add an extra peer dependency", () => {
|
|
25
40
|
const manifest = JSON.parse(
|
|
26
41
|
readFileSync(new URL("../package.json", import.meta.url), "utf8"),
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
import {expect, test} from "@playwright/test";
|
|
2
2
|
|
|
3
|
-
test("
|
|
4
|
-
await page.goto("/");
|
|
3
|
+
test("serves the home page", async ({page}) => {
|
|
4
|
+
const response = await page.goto("/");
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
page.getByRole("heading", {
|
|
8
|
-
level: 1,
|
|
9
|
-
}),
|
|
10
|
-
).toHaveText("Next Friday Payload template");
|
|
6
|
+
expect(response?.status()).toBe(200);
|
|
11
7
|
});
|
|
12
8
|
|
|
13
9
|
test("admin panel asks for a user to sign in or create the first user", async ({page}) => {
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://unpkg.com/knip@6/schema.json",
|
|
3
|
-
"ignoreDependencies": ["fast-check"],
|
|
4
3
|
"workspaces": {
|
|
5
4
|
"apps/app": {
|
|
6
|
-
"ignoreDependencies": ["
|
|
5
|
+
"ignoreDependencies": ["@swc/core"]
|
|
6
|
+
},
|
|
7
|
+
"apps/backoffice": {
|
|
8
|
+
"ignoreDependencies": ["@swc/core"]
|
|
7
9
|
}
|
|
8
10
|
}
|
|
9
11
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "next-friday-template-turborepo",
|
|
3
3
|
"version": "0.1.0",
|
|
4
4
|
"private": true,
|
|
5
|
-
"description": "Next
|
|
5
|
+
"description": "Turborepo workspace with a Next.js application and a Payload CMS backoffice.",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
8
|
"url": "git+https://github.com/next-friday/next-friday-template-turborepo.git"
|
|
@@ -11,39 +11,39 @@
|
|
|
11
11
|
"author": "Next Friday",
|
|
12
12
|
"type": "module",
|
|
13
13
|
"scripts": {
|
|
14
|
-
"
|
|
14
|
+
"bands:check": "node scripts/check-bands.ts",
|
|
15
|
+
"build": "turbo run build $TURBO_FILTER",
|
|
15
16
|
"check": "pnpm verify:static && pnpm test:changed && pnpm build",
|
|
16
17
|
"clean": "rm -rf apps/app/.next apps/app/coverage apps/backoffice/.next apps/backoffice/coverage .turbo coverage *.tsbuildinfo .eslintcache node_modules/.cache",
|
|
17
|
-
"depcruise": "turbo run depcruise $
|
|
18
|
+
"depcruise": "turbo run depcruise $TURBO_FILTER",
|
|
18
19
|
"dev": "turbo run dev --filter=./apps/*",
|
|
20
|
+
"evals:run": "node scripts/run-agent-evals.ts",
|
|
19
21
|
"format": "prettier --write --cache .",
|
|
20
22
|
"format:check": "prettier --check --cache . && editorconfig-checker",
|
|
21
23
|
"gates:check": "node scripts/check-agent-gates.ts",
|
|
22
24
|
"generate:importmap": "pnpm --filter ./apps/backoffice generate:importmap",
|
|
23
25
|
"generate:types": "pnpm --filter ./apps/backoffice generate:types",
|
|
24
|
-
"human-gates:check": "node scripts/check-human-gates.ts",
|
|
25
|
-
"intent:check": "node scripts/check-intent.ts",
|
|
26
26
|
"knip": "knip",
|
|
27
27
|
"lint": "eslint . --fix --cache --max-warnings=0 --no-inline-config",
|
|
28
28
|
"lint:check": "eslint . --cache --max-warnings=0 --no-inline-config",
|
|
29
|
+
"loop:measure": "node scripts/measure-loop.ts",
|
|
29
30
|
"migrate": "pnpm --filter ./apps/backoffice migrate",
|
|
30
31
|
"migrate:create": "pnpm --filter ./apps/backoffice migrate:create",
|
|
31
|
-
"
|
|
32
|
+
"plan:check": "node scripts/check-plan.ts",
|
|
32
33
|
"prepare": "husky && pnpm --filter ./apps/app exec next typegen && pnpm --filter ./apps/backoffice exec next typegen",
|
|
33
34
|
"rules:check": "node scripts/sync-agent-rules.ts --check",
|
|
34
35
|
"rules:sync": "node scripts/sync-agent-rules.ts",
|
|
35
36
|
"sort-package-json": "sort-package-json package.json apps/app/package.json apps/backoffice/package.json",
|
|
36
37
|
"sort-package-json:check": "sort-package-json --check package.json apps/app/package.json apps/backoffice/package.json",
|
|
37
38
|
"start": "turbo run start --filter=./apps/*",
|
|
38
|
-
"
|
|
39
|
-
"test": "turbo run test $
|
|
40
|
-
"test:
|
|
41
|
-
"test:
|
|
42
|
-
"test:e2e": "turbo run test:e2e ${TURBO_FILTER:-\"--filter=./apps/*\"}",
|
|
39
|
+
"test": "turbo run test $TURBO_FILTER",
|
|
40
|
+
"test:changed": "turbo run test:changed $TURBO_FILTER",
|
|
41
|
+
"test:coverage": "turbo run test:coverage $TURBO_FILTER",
|
|
42
|
+
"test:e2e": "turbo run test:e2e $TURBO_FILTER",
|
|
43
43
|
"test:watch": "turbo run test:watch --filter=./apps/*",
|
|
44
|
-
"typecheck": "tsc --noEmit -p tsconfig.json && turbo run typecheck $
|
|
44
|
+
"typecheck": "tsc --noEmit -p tsconfig.json && turbo run typecheck $TURBO_FILTER",
|
|
45
45
|
"verify": "pnpm verify:static && pnpm test:coverage && pnpm build",
|
|
46
|
-
"verify:static": "pnpm
|
|
46
|
+
"verify:static": "pnpm rules:check && pnpm gates:check && pnpm plan:check && pnpm bands:check && pnpm lint:check && pnpm format:check && pnpm sort-package-json:check && pnpm typecheck && pnpm knip && pnpm depcruise"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"@commitlint/cli": "21.2.4",
|
|
@@ -54,7 +54,6 @@
|
|
|
54
54
|
"@types/node": "26.6.6",
|
|
55
55
|
"editorconfig-checker": "7.0.0",
|
|
56
56
|
"eslint": "10.14.0",
|
|
57
|
-
"fast-check": "4.10.2",
|
|
58
57
|
"husky": "9.1.7",
|
|
59
58
|
"jiti": "2.7.0",
|
|
60
59
|
"knip": "6.44.1",
|
|
@@ -63,7 +62,8 @@
|
|
|
63
62
|
"prettier-plugin-tailwindcss": "0.8.1",
|
|
64
63
|
"sort-package-json": "4.1.0",
|
|
65
64
|
"turbo": "2.11.10",
|
|
66
|
-
"typescript": "7.0.2"
|
|
65
|
+
"typescript": "7.0.2",
|
|
66
|
+
"yaml": "2.9.1"
|
|
67
67
|
},
|
|
68
68
|
"packageManager": "pnpm@12.6.0+sha512.3ef68f951cb111ac204b4a5a16f0b2ddf0da56a96e0413e81d855d9f0b55ef926714709028e1cd00c405c2c5fb7b9e8ec4dc46777c805d0373c2f2ff00fd20ec",
|
|
69
69
|
"engines": {
|
|
@@ -4,6 +4,7 @@ packages:
|
|
|
4
4
|
engineStrict: true
|
|
5
5
|
savePrefix: ""
|
|
6
6
|
allowBuilds:
|
|
7
|
+
"@swc/core": false
|
|
7
8
|
esbuild: true
|
|
8
9
|
unrs-resolver: true
|
|
9
10
|
overrides:
|
|
@@ -16,31 +17,9 @@ overrides:
|
|
|
16
17
|
"minimatch@<11.0.1": ^11.0.1
|
|
17
18
|
minimumReleaseAgeExclude:
|
|
18
19
|
- "@next-friday/commitlint-config-friday@4.0.0"
|
|
19
|
-
- "@next-friday/eslint-config-friday@5.0.0"
|
|
20
20
|
- "@next-friday/eslint-config-friday@5.1.0"
|
|
21
21
|
- "@next-friday/prettier-config-friday@4.0.0"
|
|
22
22
|
- "@next-friday/eslint-plugin-friday@1.1.3"
|
|
23
|
-
packageExtensions:
|
|
24
|
-
payload:
|
|
25
|
-
peerDependenciesMeta:
|
|
26
|
-
graphql:
|
|
27
|
-
optional: true
|
|
28
|
-
"@payloadcms/next":
|
|
29
|
-
peerDependenciesMeta:
|
|
30
|
-
graphql:
|
|
31
|
-
optional: true
|
|
32
|
-
"@payloadcms/graphql":
|
|
33
|
-
peerDependenciesMeta:
|
|
34
|
-
graphql:
|
|
35
|
-
optional: true
|
|
36
|
-
graphql-http:
|
|
37
|
-
peerDependenciesMeta:
|
|
38
|
-
graphql:
|
|
39
|
-
optional: true
|
|
40
|
-
graphql-scalars:
|
|
41
|
-
peerDependenciesMeta:
|
|
42
|
-
graphql:
|
|
43
|
-
optional: true
|
|
44
23
|
peerDependencyRules:
|
|
45
24
|
ignoreMissing:
|
|
46
25
|
- graphql
|