Skip to content

Commit 174d925

Browse files
committed
fix(deps): cap opennextjs-cloudflare to 1.15.x for Next 14, fix resend v6 replyTo and formatting
1 parent d94cf5b commit 174d925

14 files changed

Lines changed: 2825 additions & 1354 deletions

File tree

‎app/(public)/about/page.tsx‎

Lines changed: 20 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -22,35 +22,32 @@ export default function AboutPage() {
2222
<div className="prose max-w-none space-y-8 text-text-secondary [&_h2]:font-sans [&_h2]:font-bold [&_h2]:text-text-primary [&_a]:text-accent [&_a:hover]:underline">
2323
<p>
2424
I&apos;m Royal Simpson Pinto, an AI and product engineer. I spent
25-
months documenting real AI agent failures in production: deleted
26-
data, wrong recipients, surprise bills, exposed credentials. That
27-
public registry still exists on this site, and every guardrail in
28-
my installs traces back to a case in it.
25+
months documenting real AI agent failures in production: deleted data,
26+
wrong recipients, surprise bills, exposed credentials. That public
27+
registry still exists on this site, and every guardrail in my installs
28+
traces back to a case in it.
2929
</p>
3030

3131
<p>
32-
The lesson from all those cases is simple. Agents fail when they
33-
get unlimited access, no audit trail, and nobody approving the
34-
risky calls. So that is exactly what my installs refuse to do:
35-
scoped keys, every action logged, and a human approval step for
36-
anything irreversible.
32+
The lesson from all those cases is simple. Agents fail when they get
33+
unlimited access, no audit trail, and nobody approving the risky
34+
calls. So that is exactly what my installs refuse to do: scoped keys,
35+
every action logged, and a human approval step for anything
36+
irreversible.
3737
</p>
3838

3939
<h2>What I sell</h2>
4040

4141
<p>
42-
One thing: a 14-day pilot that puts an agent on one of your
43-
support or portal workflows. Triage plus guarded refunds within
44-
your policy, or portal pulls with screenshot proof. $1,200 fixed,
45-
and the second half is only due if it closes real work. After
46-
that, $400 per month care, pause anytime.
42+
One thing: a 14-day pilot that puts an agent on one of your support or
43+
portal workflows. Triage plus guarded refunds within your policy, or
44+
portal pulls with screenshot proof. $1,200 fixed, and the second half
45+
is only due if it closes real work. After that, $400 per month care,
46+
pause anytime.
4747
</p>
4848

4949
<p>
50-
<a href="/pilot">
51-
Book the pilot here
52-
</a>
53-
. I reply within a day.
50+
<a href="/pilot">Book the pilot here</a>. I reply within a day.
5451
</p>
5552

5653
<h2>Why trust a solo builder</h2>
@@ -71,9 +68,9 @@ export default function AboutPage() {
7168

7269
<p>
7370
The public case registry remains online as a reference: numbered,
74-
tagged, searchable reports of agent incidents, with a moderation
75-
queue and anonymous submissions. It no longer defines this site;
76-
it is the evidence shelf the installs stand on.
71+
tagged, searchable reports of agent incidents, with a moderation queue
72+
and anonymous submissions. It no longer defines this site; it is the
73+
evidence shelf the installs stand on.
7774
</p>
7875

7976
<div id="contact">
@@ -90,8 +87,8 @@ export default function AboutPage() {
9087
<div className="mt-10 border-t border-border-default pt-6">
9188
<p className="font-mono text-xs text-text-tertiary">
9289
AgentPostmortem is an independent project. We are not affiliated
93-
with Anthropic, OpenAI, Google, Microsoft, or any AI vendor named
94-
in the case database.
90+
with Anthropic, OpenAI, Google, Microsoft, or any AI vendor named in
91+
the case database.
9592
</p>
9693
</div>
9794
</div>

‎app/(public)/page.tsx‎

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,9 @@ export default function HomePage() {
8989
</h1>
9090

9191
<p className="mt-6 max-w-[56ch] text-lg leading-relaxed text-stone-600">
92-
Done for you install for support and ops teams. Triage plus
93-
small refunds within policy, portal pulls with screenshot proof,
94-
risky actions paused for your one tap approval.
92+
Done for you install for support and ops teams. Triage plus small
93+
refunds within policy, portal pulls with screenshot proof, risky
94+
actions paused for your one tap approval.
9595
</p>
9696

9797
<div className="mt-8 flex flex-col gap-3 sm:flex-row">
@@ -125,7 +125,10 @@ export default function HomePage() {
125125
</header>
126126

127127
{/* Plan cards */}
128-
<section aria-label="How the pilot works" className="grid gap-4 md:grid-cols-3">
128+
<section
129+
aria-label="How the pilot works"
130+
className="grid gap-4 md:grid-cols-3"
131+
>
129132
{PLAN_CARDS.map((card, i) => (
130133
<div
131134
key={card.step}
@@ -213,8 +216,8 @@ export default function HomePage() {
213216
If it does not close real work, you do not pay the second half.
214217
</h2>
215218
<p className="mx-auto mt-4 max-w-[52ch] text-[16px] leading-relaxed text-emerald-100/80">
216-
$1,200 fixed for the 14 day pilot. Then $400 per month care,
217-
pause anytime. Reply within a day.
219+
$1,200 fixed for the 14 day pilot. Then $400 per month care, pause
220+
anytime. Reply within a day.
218221
</p>
219222
<Link
220223
href="/pilot"

‎app/(public)/pilot/PilotForm.tsx‎

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,18 @@ function fieldClass(invalid: boolean): string {
4242
export function PilotForm() {
4343
const [values, setValues] = useState<Values>(EMPTY);
4444
const [errors, setErrors] = useState<PilotErrors>({});
45-
const [touched, setTouched] = useState<Partial<Record<PilotField, boolean>>>({});
45+
const [touched, setTouched] = useState<Partial<Record<PilotField, boolean>>>(
46+
{},
47+
);
4648
const [formError, setFormError] = useState("");
4749
const [sending, setSending] = useState(false);
4850
const [done, setDone] = useState("");
4951
const refs = useRef<
5052
Partial<
51-
Record<PilotField, HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement | null>
53+
Record<
54+
PilotField,
55+
HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement | null
56+
>
5257
>
5358
>({});
5459

@@ -75,7 +80,13 @@ export function PilotForm() {
7580
}
7681

7782
function focusFirstInvalid(next: PilotErrors) {
78-
const order: PilotField[] = ["name", "email", "company", "track", "workflow"];
83+
const order: PilotField[] = [
84+
"name",
85+
"email",
86+
"company",
87+
"track",
88+
"workflow",
89+
];
7990
for (const field of order) {
8091
if (next[field]) {
8192
setTouched((prev) => ({ ...prev, [field]: true }));
@@ -152,7 +163,11 @@ export function PilotForm() {
152163

153164
const errorLine = (field: PilotField) =>
154165
touched[field] && errors[field] ? (
155-
<p id={`pilot-${field}-error`} role="alert" className="mt-1.5 text-[13px] font-medium text-sev-critical">
166+
<p
167+
id={`pilot-${field}-error`}
168+
role="alert"
169+
className="mt-1.5 text-[13px] font-medium text-sev-critical"
170+
>
156171
{errors[field]}
157172
</p>
158173
) : null;
@@ -208,7 +223,8 @@ export function PilotForm() {
208223
<div className="mt-4 grid gap-4 sm:grid-cols-2">
209224
<div>
210225
<label htmlFor="pilot-company" className={LABEL}>
211-
Company or site <span className="font-normal text-text-tertiary">(optional)</span>
226+
Company or site{" "}
227+
<span className="font-normal text-text-tertiary">(optional)</span>
212228
</label>
213229
<input
214230
id="pilot-company"
@@ -284,7 +300,10 @@ export function PilotForm() {
284300
</div>
285301

286302
{/* Honeypot: invisible to humans, irresistible to bots. */}
287-
<div aria-hidden="true" className="absolute h-px w-px overflow-hidden opacity-0">
303+
<div
304+
aria-hidden="true"
305+
className="absolute h-px w-px overflow-hidden opacity-0"
306+
>
288307
<label htmlFor="pilot-website">Website</label>
289308
<input
290309
id="pilot-website"
@@ -310,8 +329,8 @@ export function PilotForm() {
310329
</p>
311330
)}
312331
<p className="mt-3 text-[13px] leading-relaxed text-text-tertiary">
313-
No payment now. Half up front only when we agree on the workflow,
314-
second half only if it closes real work.
332+
No payment now. Half up front only when we agree on the workflow, second
333+
half only if it closes real work.
315334
</p>
316335
</form>
317336
);

‎app/(public)/pilot/page.tsx‎

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -78,14 +78,17 @@ export default function PilotPage() {
7878
</span>
7979
</h1>
8080
<p className="mt-5 max-w-[56ch] text-lg leading-relaxed text-text-secondary">
81-
$1,200 fixed. Second half only if it closes real work. Then $400
82-
per month care, pause anytime.
81+
$1,200 fixed. Second half only if it closes real work. Then $400 per
82+
month care, pause anytime.
8383
</p>
8484
</header>
8585

8686
<div className="grid gap-10 lg:grid-cols-[minmax(0,1fr)_minmax(0,26rem)] lg:items-start">
8787
<div>
88-
<section aria-label="How it works" className="grid gap-4 sm:grid-cols-3">
88+
<section
89+
aria-label="How it works"
90+
className="grid gap-4 sm:grid-cols-3"
91+
>
8992
{STEPS.map((s) => (
9093
<div
9194
key={s.n}
@@ -110,7 +113,10 @@ export default function PilotPage() {
110113
</h2>
111114
<ul className="mt-4 space-y-2.5">
112115
{INCLUDED.map((item) => (
113-
<li key={item} className="flex items-start gap-2.5 text-[15px] leading-relaxed text-text-secondary">
116+
<li
117+
key={item}
118+
className="flex items-start gap-2.5 text-[15px] leading-relaxed text-text-secondary"
119+
>
114120
<span className="mt-0.5 grid h-5 w-5 shrink-0 place-items-center rounded-full bg-emerald-100 text-[12px] font-bold text-emerald-700">
115121
✓
116122
</span>
@@ -130,13 +136,18 @@ export default function PilotPage() {
130136
<summary className="cursor-pointer list-none font-sans text-[15px] font-bold text-text-primary marker:hidden [&::-webkit-details-marker]:hidden">
131137
<span className="flex items-center justify-between gap-4">
132138
{f.q}
133-
<span className="text-emerald-700 transition-transform group-open:rotate-45">+</span>
139+
<span className="text-emerald-700 transition-transform group-open:rotate-45">
140+
+
141+
</span>
134142
</span>
135143
</summary>
136144
<p className="mt-2 text-[15px] leading-relaxed text-text-secondary">
137145
{f.a}{" "}
138146
{f.q.startsWith("Why") && (
139-
<Link href="/tools" className="font-semibold text-emerald-700 hover:text-emerald-800">
147+
<Link
148+
href="/tools"
149+
className="font-semibold text-emerald-700 hover:text-emerald-800"
150+
>
140151
See the proof.
141152
</Link>
142153
)}

‎app/(public)/tools/page.tsx‎

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -238,12 +238,9 @@ export default function ToolsPage() {
238238
What the pilot runs on
239239
</h1>
240240
<p className="mt-3 max-w-2xl text-text-secondary">
241-
These backends run the 14-day pilot behind the scenes. They are
242-
not separate products to evaluate. Try any of them live, then{" "}
243-
<a
244-
href="/pilot"
245-
className="text-accent hover:underline"
246-
>
241+
These backends run the 14-day pilot behind the scenes. They are not
242+
separate products to evaluate. Try any of them live, then{" "}
243+
<a href="/pilot" className="text-accent hover:underline">
247244
book the pilot
248245
</a>
249246
.
@@ -285,13 +282,9 @@ export default function ToolsPage() {
285282

286283
<div className="mt-10 rounded-sm border border-accent/40 bg-accent-soft p-5">
287284
<p className="text-sm leading-relaxed text-text-secondary">
288-
One support or portal workflow, live in 14 days with guardrails
289-
from day one. $1,200 fixed, second half only if it closes real
290-
work.{" "}
291-
<a
292-
href="/pilot"
293-
className="font-medium text-accent hover:underline"
294-
>
285+
One support or portal workflow, live in 14 days with guardrails from
286+
day one. $1,200 fixed, second half only if it closes real work.{" "}
287+
<a href="/pilot" className="font-medium text-accent hover:underline">
295288
Book the pilot
296289
</a>
297290
.

‎app/api/pilot-lead/route.test.ts‎

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ const consumeSharedRateLimit = vi.fn(async () => ({
77
resetAt: new Date().toISOString(),
88
currentCount: 1,
99
}));
10-
const send = vi.fn(async () => ({ data: { id: "mail-1" }, error: null }));
10+
const send = vi.fn(async (_payload: Record<string, unknown>) => ({
11+
data: { id: "mail-1" },
12+
error: null,
13+
}));
1114
const logEvent = vi.fn();
1215

1316
vi.mock("@/lib/utils/hash", () => ({
@@ -40,7 +43,8 @@ const valid = {
4043
email: "ada@company.com",
4144
company: "company.com",
4245
track: "support",
43-
workflow: "Triage sixty Zendesk tickets every morning and refund damaged orders.",
46+
workflow:
47+
"Triage sixty Zendesk tickets every morning and refund damaged orders.",
4448
};
4549

4650
describe("POST /api/pilot-lead", () => {
@@ -62,16 +66,21 @@ describe("POST /api/pilot-lead", () => {
6266

6367
expect(response.status).toBe(200);
6468
expect(send).toHaveBeenCalledOnce();
65-
const args = send.mock.calls[0][0] as Record<string, unknown>;
69+
const args = send.mock.calls[0][0];
6670
expect(args.to).toBe("hello@agentpostmortem.com");
67-
expect(args.reply_to).toBe("ada@company.com");
71+
expect(args.replyTo).toBe("ada@company.com");
6872
expect(args.subject).toContain("Ada Lovelace");
6973
});
7074

7175
it("returns every field error at once", async () => {
7276
const { POST } = await import("./route");
7377
const response = await POST(
74-
createRequest({ name: "", email: "nope", track: "support", workflow: "short" }),
78+
createRequest({
79+
name: "",
80+
email: "nope",
81+
track: "support",
82+
workflow: "short",
83+
}),
7584
);
7685
const data = (await response.json()) as {
7786
errors: Record<string, string>;
@@ -98,7 +107,9 @@ describe("POST /api/pilot-lead", () => {
98107

99108
it("answers honeypot submissions with fake success and sends nothing", async () => {
100109
const { POST } = await import("./route");
101-
const response = await POST(createRequest({ ...valid, website: "spam-bot" }));
110+
const response = await POST(
111+
createRequest({ ...valid, website: "spam-bot" }),
112+
);
102113
const data = (await response.json()) as { ok: boolean };
103114

104115
expect(response.status).toBe(200);

‎app/api/pilot-lead/route.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ export async function POST(req: NextRequest) {
9393
const { error } = await resend.emails.send({
9494
from: process.env.RESEND_FROM_EMAIL ?? "noreply@agentpostmortem.com",
9595
to: "hello@agentpostmortem.com",
96-
reply_to: email,
96+
replyTo: email,
9797
subject: `Pilot application: ${name}`,
9898
html: [
9999
`<p><strong>Name:</strong> ${escapeHtml(name)}</p>`,

‎app/globals.css‎

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,7 @@
1818
rgba(5, 150, 105, 0.06),
1919
transparent 62%
2020
),
21-
linear-gradient(
22-
to bottom,
23-
rgba(28, 25, 23, 0.028) 1px,
24-
transparent 1px
25-
);
21+
linear-gradient(to bottom, rgba(28, 25, 23, 0.028) 1px, transparent 1px);
2622
background-size:
2723
100% 1400px,
2824
100% 28px;

‎components/layout/Footer.tsx‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,9 @@ export function Footer() {
111111
</span>
112112
</div>
113113
<p className="max-w-[18rem] font-sans text-[13px] leading-relaxed text-text-tertiary">
114-
Ops agents installed with guardrails, built on documented
115-
failure evidence. Failure reports quoted on this site are
116-
aggregated from public sources and may be unverified.
114+
Ops agents installed with guardrails, built on documented failure
115+
evidence. Failure reports quoted on this site are aggregated from
116+
public sources and may be unverified.
117117
</p>
118118
</div>
119119

‎components/post/SubmitForm.tsx‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,9 @@ function FieldLabel({
8080

8181
function FieldError({ message }: { message?: string }) {
8282
if (!message) return null;
83-
return <p className="mt-1 font-sans text-xs font-medium text-accent">{message}</p>;
83+
return (
84+
<p className="mt-1 font-sans text-xs font-medium text-accent">{message}</p>
85+
);
8486
}
8587

8688
const inputBase =
@@ -212,7 +214,9 @@ export function SubmitForm() {
212214
<CheckIcon size={16} />
213215
</span>
214216
</div>
215-
<h2 className="font-sans text-xl font-bold tracking-tight text-text-primary">Case Filed</h2>
217+
<h2 className="font-sans text-xl font-bold tracking-tight text-text-primary">
218+
Case Filed
219+
</h2>
216220
<p className="mt-2 text-sm text-text-secondary">
217221
Your report is in the moderation queue. Once approved, it will be
218222
assigned a permanent case number.

0 commit comments

Comments
 (0)