WIP: Claude Code progress on #31

Automated salvage commit — agent session ended (exit 124).
Work in progress, may need continuation.
This commit is contained in:
Alexander Whitestone
2026-03-23 16:21:19 -04:00
parent 113095d2f0
commit 3cd924b44c
4 changed files with 426 additions and 1 deletions

View File

@@ -1,7 +1,7 @@
import { Router, type Request, type Response } from "express";
import { randomUUID, createHash } from "crypto";
import { db, jobs, invoices, jobDebates, type Job } from "@workspace/db";
import { eq, and } from "drizzle-orm";
import { eq, and, desc } from "drizzle-orm";
import { CreateJobBody, GetJobParams } from "@workspace/api-zod";
import { lnbitsService } from "../lib/lnbits.js";
import { agentService } from "../lib/agent.js";
@@ -494,6 +494,67 @@ async function advanceJob(job: Job): Promise<Job | null> {
return job;
}
// ── GET /jobs ─────────────────────────────────────────────────────────────────
// Returns the caller's completed/rejected job history (requires Nostr token).
router.get("/jobs", async (req: Request, res: Response) => {
const header = req.headers["x-nostr-token"];
const raw = typeof header === "string" ? header.trim() : null;
if (!raw) {
res.status(401).json({ error: "X-Nostr-Token header required" });
return;
}
const parsed = trustService.verifyToken(raw);
if (!parsed) {
res.status(401).json({ error: "Invalid or expired token" });
return;
}
try {
const rows = await db
.select({
id: jobs.id,
request: jobs.request,
state: jobs.state,
workAmountSats: jobs.workAmountSats,
actualAmountSats: jobs.actualAmountSats,
result: jobs.result,
rejectionReason: jobs.rejectionReason,
freeTier: jobs.freeTier,
absorbedSats: jobs.absorbedSats,
createdAt: jobs.createdAt,
updatedAt: jobs.updatedAt,
})
.from(jobs)
.where(
and(
eq(jobs.nostrPubkey, parsed.pubkey),
// Only terminal states are useful for history
)
)
.orderBy(desc(jobs.createdAt))
.limit(50);
res.json({ jobs: rows.map(j => ({
id: j.id,
request: j.request,
state: j.state,
costSats: j.actualAmountSats ?? j.workAmountSats ?? null,
freeTier: j.freeTier,
absorbedSats: j.absorbedSats ?? null,
result: j.state === "complete" ? j.result : null,
rejectionReason: j.state === "rejected" ? j.rejectionReason : null,
createdAt: j.createdAt.toISOString(),
completedAt: (j.state === "complete" || j.state === "rejected")
? j.updatedAt.toISOString()
: null,
})) });
} catch (err) {
const message = err instanceof Error ? err.message : "Failed to fetch jobs";
res.status(500).json({ error: message });
}
});
// ── POST /jobs ────────────────────────────────────────────────────────────────
// ── Resolve Nostr pubkey from token header or body ────────────────────────────