mirror of
https://github.com/github/awesome-copilot.git
synced 2026-07-21 12:54:13 +00:00
fix(the-workshop): add HTTP error boundary and make workshop detection non-terminal
Two follow-up review findings: - signals-dashboard: the async createServer callback had no top-level error boundary, so a malformed %-encoded path, a stash write on a read-only workshop, or a scan failure rejected a promise the server never awaits — hanging the request and risking an unhandled-rejection crash. Wrap the handler and return a controlled 500. - workshop-create: Path A treated finding a marker (desks/, CAIRN.md, etc.) as 'just use it', an early stop that left partially initialized workshops incomplete. Make it detection-only and continue scaffolding whatever is missing, per the 'only add what's missing' principle. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 26faf13e-639c-4a21-ac05-c0dc2bff7c62
This commit is contained in:
@@ -649,6 +649,7 @@ function renderDashboard(signals, stashed) {
|
||||
|
||||
async function startServer(instanceId, workshopDir) {
|
||||
const server = createServer(async (req, res) => {
|
||||
try {
|
||||
const url = new URL(req.url, `http://${req.headers.host}`);
|
||||
|
||||
if (req.method === "POST" && url.pathname.startsWith("/api/") && isCrossSiteRequest(req)) {
|
||||
@@ -708,6 +709,18 @@ async function startServer(instanceId, workshopDir) {
|
||||
const stashed = await readStash(workshopDir);
|
||||
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
||||
res.end(renderDashboard(signals, stashed));
|
||||
} catch (err) {
|
||||
// Top-level boundary: never leave a request hanging or let a
|
||||
// rejection become an unhandled crash — e.g. malformed %-encoding
|
||||
// in the path, a read-only workshop on a stash write, or a scan
|
||||
// failure. Return a controlled error instead.
|
||||
if (!res.headersSent) {
|
||||
res.writeHead(500, { "Content-Type": "application/json" });
|
||||
res.end(JSON.stringify({ ok: false, error: "internal_error" }));
|
||||
} else {
|
||||
try { res.end(); } catch {}
|
||||
}
|
||||
}
|
||||
});
|
||||
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
|
||||
const address = server.address();
|
||||
|
||||
@@ -21,9 +21,11 @@ The operator already has a folder they want to use. Maybe it's a repo
|
||||
they cloned, maybe it's a local project folder.
|
||||
|
||||
1. **Confirm the path exists.** If not, ask the operator for a valid path.
|
||||
2. **Check if it's already a workshop.** Look for `desks/` or `classroom/`
|
||||
folders, a `workshop.md`, `CAIRN.md`, or `hands-up.md`. If any exist,
|
||||
it's already a workshop — just use it.
|
||||
2. **Detect existing workshop markers.** Look for `desks/` or `classroom/`
|
||||
folders, a `workshop.md`, `CAIRN.md`, or `hands-up.md`. Finding any of
|
||||
these tells you this is an existing workshop — but this is detection
|
||||
only, not a stopping point. Continue to the next step and add whatever
|
||||
is missing; never overwrite what is already there.
|
||||
3. **Scaffold the workshop structure** (only what's missing):
|
||||
```
|
||||
<path>/
|
||||
|
||||
Reference in New Issue
Block a user