@next-friday/create-app 9.1.0 → 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.
Files changed (338) hide show
  1. package/README.md +5 -4
  2. package/dist/main.mjs +135 -96
  3. package/package.json +8 -6
  4. package/templates/base/.agents/hooks/agent-mcp-gate.sh +7 -2
  5. package/templates/base/.agents/hooks/agent-production-gate.sh +6 -1
  6. package/templates/base/.agents/hooks/agent-shell-gate.sh +1 -181
  7. package/templates/base/.agents/hooks/agent-test-edit-gate.sh +12 -3
  8. package/templates/base/.agents/review.md +2 -2
  9. package/templates/base/.agents/rules/no-suppression.md +1 -1
  10. package/templates/base/.agents/skill-evals/README.md +42 -0
  11. package/templates/base/.agents/skill-evals/sdlc/answers-question-without-writing/case.yaml +12 -0
  12. package/templates/base/.agents/skill-evals/sdlc/answers-question-without-writing/graders/01-the-reply-explains-why-pnpm.md +7 -0
  13. package/templates/base/.agents/skill-evals/sdlc/answers-question-without-writing/graders/02-no-file-in-the-project.md +7 -0
  14. package/templates/base/.agents/skill-evals/sdlc/answers-question-without-writing/graders/03-no-commit-is-made-nothing.md +7 -0
  15. package/templates/base/.agents/skill-evals/sdlc/answers-question-without-writing/graders/04-the-reply-is-in-the.md +7 -0
  16. package/templates/base/.agents/skill-evals/sdlc/answers-question-without-writing/graders/05-every-path-in-the-reply.md +7 -0
  17. package/templates/base/.agents/skill-evals/sdlc/answers-question-without-writing/graders/06-everything-the-reply-states-as.md +7 -0
  18. package/templates/base/.agents/skill-evals/sdlc/answers-question-without-writing/prompt.md +8 -0
  19. package/templates/base/.agents/skill-evals/sdlc/build-continues-from-an-accepted-plan/case.yaml +12 -0
  20. package/templates/base/.agents/skill-evals/sdlc/build-continues-from-an-accepted-plan/fixture.md +1 -0
  21. package/templates/base/.agents/skill-evals/sdlc/build-continues-from-an-accepted-plan/graders/01-work-happens-on-the-plan-branch.md +7 -0
  22. package/templates/base/.agents/skill-evals/sdlc/build-continues-from-an-accepted-plan/graders/02-the-plan-is-implemented-and-checked.md +7 -0
  23. package/templates/base/.agents/skill-evals/sdlc/build-continues-from-an-accepted-plan/graders/03-the-branch-is-pushed.md +7 -0
  24. package/templates/base/.agents/skill-evals/sdlc/build-continues-from-an-accepted-plan/graders/04-the-reply-lists-three-playbooks.md +7 -0
  25. package/templates/base/.agents/skill-evals/sdlc/build-continues-from-an-accepted-plan/graders/05-no-approval-and-no-merge.md +7 -0
  26. 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
  27. package/templates/base/.agents/skill-evals/sdlc/build-continues-from-an-accepted-plan/graders/07-the-plan-names-the-engineer.md +7 -0
  28. package/templates/base/.agents/skill-evals/sdlc/build-continues-from-an-accepted-plan/prompt.md +8 -0
  29. package/templates/base/.agents/skill-evals/sdlc/build-interviews-before-planning/case.yaml +71 -0
  30. package/templates/base/.agents/skill-evals/sdlc/build-interviews-before-planning/fixture.md +1 -0
  31. package/templates/base/.agents/skill-evals/sdlc/build-interviews-before-planning/graders/01-the-reply-asks-numbered-questions.md +7 -0
  32. package/templates/base/.agents/skill-evals/sdlc/build-interviews-before-planning/graders/02-no-plan-before-the-answers.md +7 -0
  33. package/templates/base/.agents/skill-evals/sdlc/build-interviews-before-planning/graders/03-no-question-depends-on-another.md +7 -0
  34. package/templates/base/.agents/skill-evals/sdlc/build-interviews-before-planning/graders/04-no-file-or-commit.md +7 -0
  35. package/templates/base/.agents/skill-evals/sdlc/build-interviews-before-planning/graders/05-the-reply-is-in-thai.md +7 -0
  36. package/templates/base/.agents/skill-evals/sdlc/build-interviews-before-planning/prompt.md +8 -0
  37. package/templates/base/.agents/skill-evals/sdlc/build-plans-and-waits-for-the-engineer/case.yaml +68 -0
  38. package/templates/base/.agents/skill-evals/sdlc/build-plans-and-waits-for-the-engineer/fixture.md +1 -0
  39. 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
  40. package/templates/base/.agents/skill-evals/sdlc/build-plans-and-waits-for-the-engineer/graders/02-no-source-file-or-commit.md +7 -0
  41. package/templates/base/.agents/skill-evals/sdlc/build-plans-and-waits-for-the-engineer/graders/03-the-reply-names-the-gate.md +7 -0
  42. package/templates/base/.agents/skill-evals/sdlc/build-plans-and-waits-for-the-engineer/graders/04-the-reply-is-in-thai.md +7 -0
  43. package/templates/base/.agents/skill-evals/sdlc/build-plans-and-waits-for-the-engineer/prompt.md +10 -0
  44. package/templates/base/.agents/skill-evals/sdlc/deploy-stops-at-the-production-gate/case.yaml +8 -0
  45. package/templates/base/.agents/skill-evals/sdlc/deploy-stops-at-the-production-gate/fixture.md +1 -0
  46. package/templates/base/.agents/skill-evals/sdlc/deploy-stops-at-the-production-gate/graders/01-no-deployment-is-started.md +7 -0
  47. 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
  48. 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
  49. package/templates/base/.agents/skill-evals/sdlc/deploy-stops-at-the-production-gate/graders/04-the-reply-is-in-the-language.md +7 -0
  50. package/templates/base/.agents/skill-evals/sdlc/deploy-stops-at-the-production-gate/prompt.md +8 -0
  51. package/templates/base/.agents/skill-evals/sdlc/drafts-intent-and-waits-for-yes/case.yaml +13 -0
  52. package/templates/base/.agents/skill-evals/sdlc/drafts-intent-and-waits-for-yes/graders/01-a-file-intentkebabcasenameintentmd-exists-with.md +7 -0
  53. package/templates/base/.agents/skill-evals/sdlc/drafts-intent-and-waits-for-yes/graders/02-the-reply-shows-the-draft.md +7 -0
  54. package/templates/base/.agents/skill-evals/sdlc/drafts-intent-and-waits-for-yes/graders/03-no-commit-is-made-nothing.md +7 -0
  55. package/templates/base/.agents/skill-evals/sdlc/drafts-intent-and-waits-for-yes/graders/04-reply-lists-the-playbook-steps.md +7 -0
  56. package/templates/base/.agents/skill-evals/sdlc/drafts-intent-and-waits-for-yes/graders/05-the-reply-is-in-the.md +7 -0
  57. package/templates/base/.agents/skill-evals/sdlc/drafts-intent-and-waits-for-yes/graders/06-every-path-in-the-reply.md +7 -0
  58. package/templates/base/.agents/skill-evals/sdlc/drafts-intent-and-waits-for-yes/graders/07-the-drafts-open-questions-section.md +7 -0
  59. package/templates/base/.agents/skill-evals/sdlc/drafts-intent-and-waits-for-yes/prompt.md +10 -0
  60. package/templates/base/.agents/skill-evals/sdlc/fix-reproduces-finds-the-cause-and-waits-for-the-engineer/case.yaml +34 -0
  61. package/templates/base/.agents/skill-evals/sdlc/fix-reproduces-finds-the-cause-and-waits-for-the-engineer/fixture.md +1 -0
  62. 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
  63. 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
  64. 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
  65. 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
  66. 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
  67. 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
  68. package/templates/base/.agents/skill-evals/sdlc/fix-reproduces-finds-the-cause-and-waits-for-the-engineer/prompt.md +8 -0
  69. package/templates/base/.agents/skill-evals/sdlc/interviews-before-writing-intent/case.yaml +12 -0
  70. package/templates/base/.agents/skill-evals/sdlc/interviews-before-writing-intent/graders/01-the-first-message-restates-the.md +7 -0
  71. package/templates/base/.agents/skill-evals/sdlc/interviews-before-writing-intent/graders/02-the-reply-asks-numbered-questions.md +7 -0
  72. package/templates/base/.agents/skill-evals/sdlc/interviews-before-writing-intent/graders/03-no-intentmd-is-written-before.md +7 -0
  73. package/templates/base/.agents/skill-evals/sdlc/interviews-before-writing-intent/graders/04-reply-lists-the-playbook-steps.md +7 -0
  74. package/templates/base/.agents/skill-evals/sdlc/interviews-before-writing-intent/graders/05-no-commit-is-made-nothing.md +7 -0
  75. package/templates/base/.agents/skill-evals/sdlc/interviews-before-writing-intent/graders/06-the-reply-is-in-the.md +7 -0
  76. package/templates/base/.agents/skill-evals/sdlc/interviews-before-writing-intent/graders/07-every-path-in-the-reply.md +7 -0
  77. package/templates/base/.agents/skill-evals/sdlc/interviews-before-writing-intent/graders/08-no-question-in-the-round.md +7 -0
  78. package/templates/base/.agents/skill-evals/sdlc/interviews-before-writing-intent/prompt.md +8 -0
  79. package/templates/base/.agents/skill-evals/sdlc/maintain-writes-intent-from-a-finding/case.yaml +14 -0
  80. package/templates/base/.agents/skill-evals/sdlc/maintain-writes-intent-from-a-finding/fixture.md +1 -0
  81. package/templates/base/.agents/skill-evals/sdlc/maintain-writes-intent-from-a-finding/graders/01-the-intent-has-the-five-headings.md +7 -0
  82. package/templates/base/.agents/skill-evals/sdlc/maintain-writes-intent-from-a-finding/graders/02-problem-holds-the-error-and-where.md +7 -0
  83. package/templates/base/.agents/skill-evals/sdlc/maintain-writes-intent-from-a-finding/graders/03-unverified-cause-is-an-open-question.md +7 -0
  84. package/templates/base/.agents/skill-evals/sdlc/maintain-writes-intent-from-a-finding/graders/04-no-source-file-is-changed.md +7 -0
  85. 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
  86. package/templates/base/.agents/skill-evals/sdlc/maintain-writes-intent-from-a-finding/graders/06-the-person-is-asked-no-question.md +7 -0
  87. package/templates/base/.agents/skill-evals/sdlc/maintain-writes-intent-from-a-finding/prompt.md +8 -0
  88. package/templates/base/.agents/skill-evals/sdlc/reported-problem-starts-the-plan/case.yaml +12 -0
  89. package/templates/base/.agents/skill-evals/sdlc/reported-problem-starts-the-plan/graders/01-the-reply-follows-the-plan.md +7 -0
  90. package/templates/base/.agents/skill-evals/sdlc/reported-problem-starts-the-plan/graders/02-the-reply-does-not-tell.md +7 -0
  91. package/templates/base/.agents/skill-evals/sdlc/reported-problem-starts-the-plan/graders/03-no-file-is-created-or.md +7 -0
  92. package/templates/base/.agents/skill-evals/sdlc/reported-problem-starts-the-plan/graders/04-the-reply-is-in-the.md +7 -0
  93. package/templates/base/.agents/skill-evals/sdlc/reported-problem-starts-the-plan/graders/05-every-path-in-the-reply.md +7 -0
  94. package/templates/base/.agents/skill-evals/sdlc/reported-problem-starts-the-plan/prompt.md +8 -0
  95. package/templates/base/.agents/skill-evals/sdlc/request-that-fits-no-row/case.yaml +11 -0
  96. package/templates/base/.agents/skill-evals/sdlc/request-that-fits-no-row/fixture.md +1 -0
  97. 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
  98. package/templates/base/.agents/skill-evals/sdlc/request-that-fits-no-row/graders/02-the-reply-names-the-closest-row.md +7 -0
  99. package/templates/base/.agents/skill-evals/sdlc/request-that-fits-no-row/graders/03-the-reply-is-short-and-in-thai.md +7 -0
  100. package/templates/base/.agents/skill-evals/sdlc/request-that-fits-no-row/prompt.md +8 -0
  101. package/templates/base/.agents/skill-evals/sdlc/review-reports-findings-and-never-merges/case.yaml +79 -0
  102. package/templates/base/.agents/skill-evals/sdlc/review-reports-findings-and-never-merges/fixture.md +1 -0
  103. package/templates/base/.agents/skill-evals/sdlc/review-reports-findings-and-never-merges/graders/01-findings-have-pass-severity-and-location.md +7 -0
  104. package/templates/base/.agents/skill-evals/sdlc/review-reports-findings-and-never-merges/graders/02-no-approval-and-no-merge.md +7 -0
  105. 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
  106. package/templates/base/.agents/skill-evals/sdlc/review-reports-findings-and-never-merges/graders/04-nothing-is-pushed-or-changed.md +7 -0
  107. 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
  108. package/templates/base/.agents/skill-evals/sdlc/review-reports-findings-and-never-merges/prompt.md +8 -0
  109. package/templates/base/.agents/skill-evals/sdlc/spec-for-unmerged-intent-stops/case.yaml +42 -0
  110. package/templates/base/.agents/skill-evals/sdlc/spec-for-unmerged-intent-stops/fixture.md +1 -0
  111. package/templates/base/.agents/skill-evals/sdlc/spec-for-unmerged-intent-stops/graders/01-no-spec-is-written.md +7 -0
  112. package/templates/base/.agents/skill-evals/sdlc/spec-for-unmerged-intent-stops/graders/02-no-commit-is-made.md +7 -0
  113. package/templates/base/.agents/skill-evals/sdlc/spec-for-unmerged-intent-stops/graders/03-the-reply-says-not-merged.md +7 -0
  114. package/templates/base/.agents/skill-evals/sdlc/spec-for-unmerged-intent-stops/graders/04-the-reply-is-in-the.md +7 -0
  115. package/templates/base/.agents/skill-evals/sdlc/spec-for-unmerged-intent-stops/graders/05-the-reply-is-short.md +7 -0
  116. package/templates/base/.agents/skill-evals/sdlc/spec-for-unmerged-intent-stops/prompt.md +8 -0
  117. package/templates/base/.agents/skill-evals/sdlc/statement-without-command-starts-no-work/case.yaml +12 -0
  118. package/templates/base/.agents/skill-evals/sdlc/statement-without-command-starts-no-work/graders/01-no-intentmd-or-any-other.md +7 -0
  119. package/templates/base/.agents/skill-evals/sdlc/statement-without-command-starts-no-work/graders/02-no-commit-is-made-nothing.md +7 -0
  120. package/templates/base/.agents/skill-evals/sdlc/statement-without-command-starts-no-work/graders/03-the-reply-is-in-the.md +7 -0
  121. package/templates/base/.agents/skill-evals/sdlc/statement-without-command-starts-no-work/graders/04-every-path-in-the-reply.md +7 -0
  122. package/templates/base/.agents/skill-evals/sdlc/statement-without-command-starts-no-work/graders/05-the-reply-says-that-work.md +7 -0
  123. package/templates/base/.agents/skill-evals/sdlc/statement-without-command-starts-no-work/prompt.md +8 -0
  124. package/templates/base/.agents/skill-evals/sdlc/writes-spec-from-merged-intent/case.yaml +42 -0
  125. package/templates/base/.agents/skill-evals/sdlc/writes-spec-from-merged-intent/fixture.md +1 -0
  126. package/templates/base/.agents/skill-evals/sdlc/writes-spec-from-merged-intent/graders/01-the-spec-has-the-five-headings.md +7 -0
  127. package/templates/base/.agents/skill-evals/sdlc/writes-spec-from-merged-intent/graders/02-policies-has-one-line-per-policy.md +7 -0
  128. package/templates/base/.agents/skill-evals/sdlc/writes-spec-from-merged-intent/graders/03-no-policy-is-called-unwritten.md +7 -0
  129. package/templates/base/.agents/skill-evals/sdlc/writes-spec-from-merged-intent/graders/04-a-branch-is-pushed-for-review.md +7 -0
  130. package/templates/base/.agents/skill-evals/sdlc/writes-spec-from-merged-intent/graders/05-the-reply-names-the-gate.md +7 -0
  131. package/templates/base/.agents/skill-evals/sdlc/writes-spec-from-merged-intent/graders/06-the-reply-is-in-the.md +7 -0
  132. package/templates/base/.agents/skill-evals/sdlc/writes-spec-from-merged-intent/graders/07-no-merge-is-made.md +7 -0
  133. package/templates/base/.agents/skill-evals/sdlc/writes-spec-from-merged-intent/graders/08-the-four-policies-are-read-before-writing.md +7 -0
  134. package/templates/base/.agents/skill-evals/sdlc/writes-spec-from-merged-intent/prompt.md +8 -0
  135. package/templates/base/.agents/skill-evals/sdlc-help/explains-how-to-start-work/case.yaml +11 -0
  136. package/templates/base/.agents/skill-evals/sdlc-help/explains-how-to-start-work/graders/01-the-reply-says-that-work.md +7 -0
  137. package/templates/base/.agents/skill-evals/sdlc-help/explains-how-to-start-work/graders/02-the-reply-gives-one-example.md +7 -0
  138. package/templates/base/.agents/skill-evals/sdlc-help/explains-how-to-start-work/graders/03-the-reply-lists-the-project.md +7 -0
  139. package/templates/base/.agents/skill-evals/sdlc-help/explains-how-to-start-work/graders/04-no-file-is-created-or.md +7 -0
  140. package/templates/base/.agents/skill-evals/sdlc-help/explains-how-to-start-work/graders/05-the-reply-is-in-the.md +7 -0
  141. package/templates/base/.agents/skill-evals/sdlc-help/explains-how-to-start-work/graders/06-every-path-in-the-reply.md +7 -0
  142. package/templates/base/.agents/skill-evals/sdlc-help/explains-how-to-start-work/prompt.md +8 -0
  143. package/templates/base/.agents/skill-evals/sdlc-help/unknown-playbook-is-not-invented/case.yaml +10 -0
  144. package/templates/base/.agents/skill-evals/sdlc-help/unknown-playbook-is-not-invented/graders/01-the-reply-says-that-this.md +7 -0
  145. package/templates/base/.agents/skill-evals/sdlc-help/unknown-playbook-is-not-invented/graders/02-the-reply-does-not-describe.md +7 -0
  146. package/templates/base/.agents/skill-evals/sdlc-help/unknown-playbook-is-not-invented/graders/03-no-file-is-created-or.md +7 -0
  147. package/templates/base/.agents/skill-evals/sdlc-help/unknown-playbook-is-not-invented/graders/04-the-reply-is-in-the.md +7 -0
  148. package/templates/base/.agents/skill-evals/sdlc-help/unknown-playbook-is-not-invented/graders/05-every-path-in-the-reply.md +7 -0
  149. package/templates/base/.agents/skill-evals/sdlc-help/unknown-playbook-is-not-invented/prompt.md +8 -0
  150. package/templates/base/.agents/skill-evals/sdlc-help/work-request-is-sent-to-sdlc/case.yaml +11 -0
  151. package/templates/base/.agents/skill-evals/sdlc-help/work-request-is-sent-to-sdlc/graders/01-the-reply-says-to-send.md +7 -0
  152. package/templates/base/.agents/skill-evals/sdlc-help/work-request-is-sent-to-sdlc/graders/02-no-file-is-created-or.md +7 -0
  153. package/templates/base/.agents/skill-evals/sdlc-help/work-request-is-sent-to-sdlc/graders/03-the-reply-is-in-the.md +7 -0
  154. package/templates/base/.agents/skill-evals/sdlc-help/work-request-is-sent-to-sdlc/graders/04-every-path-in-the-reply.md +7 -0
  155. package/templates/base/.agents/skill-evals/sdlc-help/work-request-is-sent-to-sdlc/prompt.md +8 -0
  156. package/templates/base/.agents/skills/sdlc/SKILL.md +25 -21
  157. package/templates/base/.agents/skills/sdlc/playbooks/build.md +13 -8
  158. package/templates/base/.agents/skills/sdlc/playbooks/deploy.md +2 -2
  159. package/templates/base/.agents/skills/sdlc/playbooks/design.md +4 -4
  160. package/templates/base/.agents/skills/sdlc/playbooks/fix.md +23 -0
  161. package/templates/base/.agents/skills/sdlc/playbooks/maintain.md +2 -3
  162. package/templates/base/.agents/skills/sdlc/playbooks/open-pr.md +3 -3
  163. package/templates/base/.agents/skills/sdlc/playbooks/plan.md +2 -2
  164. package/templates/base/.agents/skills/sdlc/playbooks/review.md +2 -2
  165. package/templates/base/.agents/skills/sdlc-help/SKILL.md +3 -1
  166. package/templates/base/.claude/managed-settings.example.json +2 -2
  167. package/templates/base/.claude/settings.json +0 -13
  168. package/templates/base/.claude/skills/sdlc/SKILL.md +25 -21
  169. package/templates/base/.claude/skills/sdlc/playbooks/build.md +13 -8
  170. package/templates/base/.claude/skills/sdlc/playbooks/deploy.md +2 -2
  171. package/templates/base/.claude/skills/sdlc/playbooks/design.md +4 -4
  172. package/templates/base/.claude/skills/sdlc/playbooks/fix.md +23 -0
  173. package/templates/base/.claude/skills/sdlc/playbooks/maintain.md +2 -3
  174. package/templates/base/.claude/skills/sdlc/playbooks/open-pr.md +3 -3
  175. package/templates/base/.claude/skills/sdlc/playbooks/plan.md +2 -2
  176. package/templates/base/.claude/skills/sdlc/playbooks/review.md +2 -2
  177. package/templates/base/.claude/skills/sdlc-help/SKILL.md +3 -1
  178. package/templates/base/.cursor/hooks.json +0 -6
  179. package/templates/base/.cursor/rules/no-suppression.mdc +1 -1
  180. package/templates/base/.cursor/skills/sdlc/SKILL.md +25 -21
  181. package/templates/base/.cursor/skills/sdlc/playbooks/build.md +13 -8
  182. package/templates/base/.cursor/skills/sdlc/playbooks/deploy.md +2 -2
  183. package/templates/base/.cursor/skills/sdlc/playbooks/design.md +4 -4
  184. package/templates/base/.cursor/skills/sdlc/playbooks/fix.md +23 -0
  185. package/templates/base/.cursor/skills/sdlc/playbooks/maintain.md +2 -3
  186. package/templates/base/.cursor/skills/sdlc/playbooks/open-pr.md +3 -3
  187. package/templates/base/.cursor/skills/sdlc/playbooks/plan.md +2 -2
  188. package/templates/base/.cursor/skills/sdlc/playbooks/review.md +2 -2
  189. package/templates/base/.cursor/skills/sdlc-help/SKILL.md +3 -1
  190. package/templates/base/.github/ISSUE_TEMPLATE/documentation.yml +1 -1
  191. package/templates/base/.github/dependabot.yml +1 -10
  192. package/templates/base/.github/file-filters.yml +3 -6
  193. package/templates/base/.github/workflows/agent-evals.yml +46 -0
  194. package/templates/base/.github/workflows/claude-fix-loop.yml +45 -0
  195. package/templates/base/.github/workflows/control-band.yml +115 -0
  196. package/templates/base/.github/workflows/dependency-review.yml +1 -0
  197. package/templates/base/.github/workflows/deploy.yml +4 -2
  198. package/templates/base/.github/workflows/osv-scanner.yml +0 -5
  199. package/templates/base/.github/workflows/pr-triage.yml +1 -1
  200. package/templates/base/.github/workflows/secret-scan.yml +4 -1
  201. package/templates/base/.github/workflows/spec-on-intent-merge.yml +108 -0
  202. package/templates/base/.github/workflows/validate-pr-title.yml +3 -2
  203. package/templates/base/.husky/pre-push +1 -8
  204. package/templates/base/REVIEW.md +2 -2
  205. package/templates/base/SETUP.md +44 -8
  206. package/templates/base/bands.yaml +3 -3
  207. package/templates/base/intent/README.md +1 -0
  208. package/templates/base/knip.json +2 -1
  209. package/templates/base/pnpm-workspace.yaml +1 -22
  210. package/templates/base/runbooks/rollback-deploy.md +27 -0
  211. package/templates/base/scripts/check-agent-gates.ts +251 -225
  212. package/templates/base/scripts/check-bands.ts +665 -0
  213. package/templates/base/scripts/check-plan.ts +1047 -0
  214. package/templates/base/scripts/measure-loop.ts +293 -0
  215. package/templates/base/scripts/run-agent-evals.ts +1186 -0
  216. package/templates/base/scripts/sync-agent-rules.ts +0 -8
  217. package/templates/nestjs/.dependency-cruiser.json +1 -1
  218. package/templates/nestjs/.github/ISSUE_TEMPLATE/bug.yml +5 -5
  219. package/templates/nestjs/.github/workflows/ci.yml +58 -9
  220. package/templates/nestjs/.github/workflows/sast.yml +0 -5
  221. package/templates/nestjs/AGENTS.md +16 -12
  222. package/templates/nestjs/CONTRIBUTING.md +3 -2
  223. package/templates/nestjs/Dockerfile +4 -4
  224. package/templates/nestjs/README.md +4 -6
  225. package/templates/nestjs/_gitignore +0 -1
  226. package/templates/nestjs/package.json +15 -13
  227. package/templates/nestjs/src/app.controller.test.ts +1 -0
  228. package/templates/nestjs/src/health/health.controller.test.ts +1 -0
  229. package/templates/nestjs/src/port.test.ts +1 -0
  230. package/templates/nestjs/test/app.e2e.test.ts +1 -0
  231. package/templates/nestjs/tsconfig.build.json +2 -3
  232. package/templates/nestjs/tsconfig.json +1 -3
  233. package/templates/nestjs/vitest.config.ts +0 -1
  234. package/templates/nestjs/vitest.e2e.config.ts +0 -1
  235. package/templates/nextjs/.dependency-cruiser.json +1 -1
  236. package/templates/nextjs/.github/ISSUE_TEMPLATE/bug.yml +1 -1
  237. package/templates/nextjs/.github/workflows/ci.yml +58 -9
  238. package/templates/nextjs/.github/workflows/sast.yml +0 -5
  239. package/templates/nextjs/AGENTS.md +16 -12
  240. package/templates/nextjs/CONTRIBUTING.md +3 -2
  241. package/templates/nextjs/Dockerfile +2 -2
  242. package/templates/nextjs/README.md +5 -3
  243. package/templates/nextjs/app/layout.tsx +2 -2
  244. package/templates/nextjs/app/page.test.ts +1 -1
  245. package/templates/nextjs/app/page.tsx +1 -1
  246. package/templates/nextjs/package.json +9 -8
  247. package/templates/nextjs/test/home.e2e.test.ts +3 -7
  248. package/templates/nextjs/tsconfig.json +0 -3
  249. package/templates/nodejs/.dependency-cruiser.json +1 -1
  250. package/templates/nodejs/.github/ISSUE_TEMPLATE/bug.yml +5 -5
  251. package/templates/nodejs/.github/workflows/ci.yml +58 -9
  252. package/templates/nodejs/.github/workflows/sast.yml +0 -5
  253. package/templates/nodejs/AGENTS.md +16 -11
  254. package/templates/nodejs/CONTRIBUTING.md +4 -3
  255. package/templates/nodejs/Dockerfile +3 -3
  256. package/templates/nodejs/README.md +4 -4
  257. package/templates/nodejs/_gitignore +0 -1
  258. package/templates/nodejs/package.json +11 -9
  259. package/templates/nodejs/src/server.test.ts +23 -0
  260. package/templates/nodejs/src/server.ts +2 -2
  261. package/templates/nodejs/tsconfig.build.json +2 -3
  262. package/templates/nodejs/tsconfig.json +0 -4
  263. package/templates/payload/.agents/agents/verifier.md +1 -1
  264. package/templates/payload/.agents/review.md +21 -0
  265. package/templates/payload/.claude/agents/verifier.md +1 -1
  266. package/templates/payload/.cursor/agents/verifier.md +1 -1
  267. package/templates/payload/.dependency-cruiser.json +1 -1
  268. package/templates/payload/.github/ISSUE_TEMPLATE/bug.yml +1 -1
  269. package/templates/payload/.github/workflows/ci.yml +75 -10
  270. package/templates/payload/.github/workflows/sast.yml +0 -5
  271. package/templates/payload/AGENTS.md +21 -17
  272. package/templates/payload/CONTRIBUTING.md +4 -3
  273. package/templates/payload/Dockerfile +2 -2
  274. package/templates/payload/README.md +8 -4
  275. package/templates/payload/REVIEW.md +21 -0
  276. package/templates/payload/package.json +9 -7
  277. package/templates/payload/src/app/(frontend)/layout.tsx +2 -2
  278. package/templates/payload/src/app/(frontend)/page.test.ts +1 -1
  279. package/templates/payload/src/app/(frontend)/page.tsx +1 -1
  280. package/templates/payload/src/app/favicon.ico +0 -0
  281. package/templates/payload/src/app/health/route.test.ts +20 -2
  282. package/templates/payload/src/app/health/route.ts +9 -2
  283. package/templates/payload/src/collections/media.test.ts +36 -1
  284. package/templates/payload/src/collections/media.ts +1 -1
  285. package/templates/payload/src/payload.config.test.ts +15 -0
  286. package/templates/payload/test/home.e2e.test.ts +3 -7
  287. package/templates/payload/tsconfig.json +0 -1
  288. package/templates/turborepo/.agents/agents/verifier.md +1 -1
  289. package/templates/turborepo/.agents/review.md +21 -0
  290. package/templates/turborepo/.claude/agents/verifier.md +1 -1
  291. package/templates/turborepo/.cursor/agents/verifier.md +1 -1
  292. package/templates/turborepo/.dockerignore +9 -4
  293. package/templates/turborepo/.github/ISSUE_TEMPLATE/bug.yml +16 -1
  294. package/templates/turborepo/.github/dependabot.yml +1 -10
  295. package/templates/turborepo/.github/scripts/affected-apps.sh +5 -23
  296. package/templates/turborepo/.github/workflows/ci.yml +140 -103
  297. package/templates/turborepo/.github/workflows/deploy.yml +24 -23
  298. package/templates/turborepo/.github/workflows/sast.yml +0 -5
  299. package/templates/turborepo/AGENTS.md +21 -17
  300. package/templates/turborepo/CONTRIBUTING.md +6 -4
  301. package/templates/turborepo/README.md +8 -8
  302. package/templates/turborepo/REVIEW.md +21 -0
  303. package/templates/turborepo/apps/app/.dependency-cruiser.json +1 -1
  304. package/templates/turborepo/apps/app/AGENTS.md +9 -0
  305. package/templates/turborepo/apps/app/Dockerfile +2 -2
  306. package/templates/turborepo/apps/app/app/layout.tsx +2 -2
  307. package/templates/turborepo/apps/app/app/page.test.ts +1 -1
  308. package/templates/turborepo/apps/app/app/page.tsx +1 -1
  309. package/templates/turborepo/apps/app/package.json +3 -3
  310. package/templates/turborepo/apps/app/test/home.e2e.test.ts +3 -7
  311. package/templates/turborepo/apps/app/tsconfig.json +0 -3
  312. package/templates/turborepo/apps/backoffice/.dependency-cruiser.json +1 -1
  313. package/templates/turborepo/apps/backoffice/AGENTS.md +9 -0
  314. package/templates/turborepo/apps/backoffice/Dockerfile +2 -2
  315. package/templates/turborepo/apps/backoffice/package.json +4 -3
  316. package/templates/turborepo/apps/backoffice/src/app/(frontend)/layout.tsx +2 -2
  317. package/templates/turborepo/apps/backoffice/src/app/(frontend)/page.test.ts +1 -1
  318. package/templates/turborepo/apps/backoffice/src/app/(frontend)/page.tsx +1 -1
  319. package/templates/turborepo/apps/backoffice/src/app/favicon.ico +0 -0
  320. package/templates/turborepo/apps/backoffice/src/app/health/route.test.ts +20 -2
  321. package/templates/turborepo/apps/backoffice/src/app/health/route.ts +10 -2
  322. package/templates/turborepo/apps/backoffice/src/collections/media.test.ts +36 -1
  323. package/templates/turborepo/apps/backoffice/src/collections/media.ts +1 -1
  324. package/templates/turborepo/apps/backoffice/src/environment.test.ts +19 -0
  325. package/templates/turborepo/apps/backoffice/src/payload.config.test.ts +15 -0
  326. package/templates/turborepo/apps/backoffice/test/home.e2e.test.ts +3 -7
  327. package/templates/turborepo/apps/backoffice/tsconfig.json +0 -1
  328. package/templates/turborepo/knip.json +4 -2
  329. package/templates/turborepo/package.json +15 -15
  330. package/templates/turborepo/pnpm-workspace.yaml +1 -22
  331. package/templates/turborepo/turbo.json +32 -11
  332. package/templates/base/.agents/hooks/agent-suppression-gate.sh +0 -45
  333. package/templates/base/.claude/rules/agents-guide.md +0 -1
  334. package/templates/base/scripts/check-human-gates.ts +0 -383
  335. package/templates/base/scripts/check-intent.ts +0 -391
  336. package/templates/nextjs/knip.json +0 -4
  337. package/templates/payload/src/collections/users.test.ts +0 -10
  338. 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`.
@@ -20,8 +20,8 @@
20
20
  }
21
21
  ],
22
22
  "options": {
23
+ "parser": "swc",
23
24
  "skipAnalysisNotInRules": true,
24
- "tsPreCompilationDeps": true,
25
25
  "enhancedResolveOptions": {
26
26
  "conditionNames": ["import", "require", "node", "default", "types"],
27
27
  "exportsFields": ["exports"]
@@ -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 Friday Next.js template",
18
- description: "Starter application for Next Friday Next.js projects.",
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 Friday Next.js template");
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 Friday Next.js template</h1>
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 Friday Next.js app.",
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("home page shows the template heading", async ({page}) => {
4
- await page.goto("/");
3
+ test("serves the home page", async ({page}) => {
4
+ const response = await page.goto("/");
5
5
 
6
- await expect(
7
- page.getByRole("heading", {
8
- level: 1,
9
- }),
10
- ).toHaveText("Next Friday Next.js template");
6
+ expect(response?.status()).toBe(200);
11
7
  });
@@ -17,9 +17,6 @@
17
17
  "name": "next"
18
18
  }
19
19
  ],
20
- "paths": {
21
- "@/*": ["./*"]
22
- },
23
20
  "allowJs": true
24
21
  },
25
22
  "include": [
@@ -20,8 +20,8 @@
20
20
  }
21
21
  ],
22
22
  "options": {
23
+ "parser": "swc",
23
24
  "skipAnalysisNotInRules": true,
24
- "tsPreCompilationDeps": true,
25
25
  "enhancedResolveOptions": {
26
26
  "conditionNames": ["import", "require", "node", "default", "types"],
27
27
  "exportsFields": ["exports"]
@@ -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": "Next Friday Payload backoffice.",
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: "Next Friday Payload template",
7
- description: "Starter application for Next Friday Payload projects.",
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("Next Friday Payload template");
11
+ expect(html).toContain("Payload application");
12
12
  expect(html).toContain('href="/admin"');
13
13
  });
14
14
  });
@@ -3,7 +3,7 @@ import Link from "next/link";
3
3
  export default function Page() {
4
4
  return (
5
5
  <main>
6
- <h1>Next Friday Payload template</h1>
6
+ <h1>Payload application</h1>
7
7
 
8
8
  <p>
9
9
  Edit <code>src/app/(frontend)/page.tsx</code> to get started, or open the{" "}
@@ -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
- it("reports ok without caching", async () => {
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. Rendered per request and never cached, so a
5
- * stopped server cannot pass from a cached response.
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
  });
@@ -10,7 +10,7 @@ export const Media: CollectionConfig = {
10
10
  },
11
11
  ],
12
12
  upload: {
13
- mimeTypes: ["image/*"],
13
+ mimeTypes: ["image/avif", "image/gif", "image/jpeg", "image/png", "image/webp"],
14
14
  },
15
15
  access: {
16
16
  read: () => true,
@@ -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("home page shows the template heading", async ({page}) => {
4
- await page.goto("/");
3
+ test("serves the home page", async ({page}) => {
4
+ const response = await page.goto("/");
5
5
 
6
- await expect(
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}) => {
@@ -18,7 +18,6 @@
18
18
  }
19
19
  ],
20
20
  "paths": {
21
- "@/*": ["./src/*"],
22
21
  "@payload-config": ["./src/payload.config.ts"]
23
22
  },
24
23
  "allowJs": true
@@ -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": ["fast-check"]
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 Friday Turborepo template.",
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
- "build": "turbo run build ${TURBO_FILTER:-\"--filter=./apps/*\"}",
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 ${TURBO_FILTER:-\"--filter=./apps/*\"}",
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
- "peers:check": "pnpm peers check",
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
- "suppressions:check": "bash .agents/hooks/agent-suppression-gate.sh --repo",
39
- "test": "turbo run test ${TURBO_FILTER:-\"--filter=./apps/*\"}",
40
- "test:changed": "turbo run test:changed ${TURBO_FILTER:-\"--filter=./apps/*\"}",
41
- "test:coverage": "turbo run test:coverage ${TURBO_FILTER:-\"--filter=./apps/*\"}",
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 ${TURBO_FILTER:-\"--filter=./apps/*\"}",
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 suppressions:check && pnpm rules:check && pnpm gates:check && pnpm human-gates:check && pnpm intent:check && pnpm lint:check && pnpm format:check && pnpm sort-package-json:check && pnpm peers:check && pnpm typecheck && pnpm knip && pnpm depcruise"
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