coder(pending): new-file-from-RightRail create endpoint + modal
POST /api/sessions/:sessionId/pending/create queues a pending_changes create via queueCreate (WriteGuardError -> 422 with the guard message). RightRail gains a 'New file from pasted text' modal (path + content) wired through api.coder.createPendingFile; sessionId is threaded down from App.tsx. The staged change shows in the CoderPane DiffPanel for explicit apply. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import type { FastifyInstance } from 'fastify';
|
||||
import { z } from 'zod';
|
||||
import type { Sql } from '../db.js';
|
||||
import {
|
||||
listPending,
|
||||
@@ -6,7 +7,14 @@ import {
|
||||
applyAll,
|
||||
rejectOne,
|
||||
rewindOne,
|
||||
queueCreate,
|
||||
} from '../services/pending_changes.js';
|
||||
import { WriteGuardError } from '../services/write_guard.js';
|
||||
|
||||
const CreateBody = z.object({
|
||||
file_path: z.string().min(1),
|
||||
content: z.string(),
|
||||
});
|
||||
|
||||
/**
|
||||
* Resolve project root from a session's project path.
|
||||
@@ -51,6 +59,49 @@ export function registerPendingRoutes(app: FastifyInstance, sql: Sql): void {
|
||||
},
|
||||
);
|
||||
|
||||
// POST /api/sessions/:sessionId/pending/create — queue a new-file create
|
||||
// (manual create from the RightRail file browser; no inference involved).
|
||||
// queueCreate runs resolveWritePath internally, so a path that escapes the
|
||||
// project root or hits a secret file throws WriteGuardError → 422 with the
|
||||
// guard message. Mirrors the { error } 404 shape used by the other routes
|
||||
// and the 422 status used by apply/rewind on failure.
|
||||
app.post<{ Params: { sessionId: string } }>(
|
||||
'/api/sessions/:sessionId/pending/create',
|
||||
async (req, reply) => {
|
||||
const sessionId = req.params.sessionId;
|
||||
|
||||
const parsed = CreateBody.safeParse(req.body);
|
||||
if (!parsed.success) {
|
||||
reply.code(400);
|
||||
return { error: 'invalid body', details: parsed.error.flatten() };
|
||||
}
|
||||
|
||||
const projectRoot = await resolveProjectRoot(sql, sessionId);
|
||||
if (!projectRoot) {
|
||||
reply.code(404);
|
||||
return { error: 'session or project not found' };
|
||||
}
|
||||
|
||||
try {
|
||||
const change = await queueCreate(
|
||||
sql,
|
||||
sessionId,
|
||||
null,
|
||||
parsed.data.file_path,
|
||||
parsed.data.content,
|
||||
projectRoot,
|
||||
);
|
||||
return change;
|
||||
} catch (err) {
|
||||
if (err instanceof WriteGuardError) {
|
||||
reply.code(422);
|
||||
return { error: err.message };
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// POST /api/sessions/:sessionId/pending/apply — apply all pending changes
|
||||
app.post<{ Params: { sessionId: string } }>(
|
||||
'/api/sessions/:sessionId/pending/apply',
|
||||
|
||||
Reference in New Issue
Block a user