spectoflow 0.23.0 → 0.23.1

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 (2) hide show
  1. package/lib/hub-server.js +16 -3
  2. package/package.json +1 -1
package/lib/hub-server.js CHANGED
@@ -55,6 +55,19 @@ function getProject(id) {
55
55
  return proj;
56
56
  }
57
57
 
58
+ // Only called after getProject(id) already returned null — figures out WHY, so the 404 points the
59
+ // user at the right fix instead of a bare "unknown project". The two common real causes: never
60
+ // registered at all, vs. registered but this project predates handlers.js (needs `spectoflow
61
+ // update`) or its folder moved/was deleted.
62
+ function projectErrorMessage(id) {
63
+ const entry = registry.listProjects().find((p) => p.id === id);
64
+ if (!entry) return 'Unknown project.';
65
+ if (!fs.existsSync(entry.path)) return `Project "${entry.name}" is registered, but its folder no longer exists at ${entry.path}.`;
66
+ const handlersPath = path.join(entry.path, '.spectoflow', 'dashboard', 'handlers.js');
67
+ if (!fs.existsSync(handlersPath)) return `Project "${entry.name}" needs an update — run \`spectoflow update\` inside it, then reload this page.`;
68
+ return `Project "${entry.name}" is registered, but its dashboard code failed to load — check its .spectoflow/dashboard/handlers.js for errors.`;
69
+ }
70
+
58
71
  // Clears every require.cache entry under this project's own .spectoflow/ tree (its vendored
59
72
  // handlers.js and everything IT requires — orchestrator.js, runner.js, files.js, summarize.js,
60
73
  // lib/store.js, lib/agents-registry.js) and drops its cached Map entry. The require cache keys by
@@ -195,7 +208,7 @@ const server = http.createServer(async (req, res) => {
195
208
  if (p === '/api/events') {
196
209
  const id = u.searchParams.get('p');
197
210
  const proj = id && getProject(id);
198
- if (!proj) return sendJSON(res, 404, { error: 'Unknown or unreachable project.' });
211
+ if (!proj) return sendJSON(res, 404, { error: projectErrorMessage(id) });
199
212
  res.writeHead(200, { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', Connection: 'keep-alive' });
200
213
  res.write('data: ' + JSON.stringify({ type: 'hello' }) + '\n\n');
201
214
  proj.clients.add(res); req.on('close', () => proj.clients.delete(res));
@@ -211,7 +224,7 @@ const server = http.createServer(async (req, res) => {
211
224
  if (p.startsWith('/api/')) {
212
225
  const id = u.searchParams.get('p');
213
226
  const proj = id && getProject(id);
214
- if (!proj) return sendJSON(res, 404, { error: 'Unknown or unreachable project.' });
227
+ if (!proj) return sendJSON(res, 404, { error: projectErrorMessage(id) });
215
228
  const handled = await proj.handlers.handleApi(req, res, u, proj.emit);
216
229
  if (handled) return;
217
230
  res.writeHead(404); return res.end('Not found');
@@ -220,7 +233,7 @@ const server = http.createServer(async (req, res) => {
220
233
  if (m) {
221
234
  const id = m[1];
222
235
  const proj = getProject(id);
223
- if (!proj) { res.writeHead(404); return res.end('Unknown project.'); }
236
+ if (!proj) { res.writeHead(404); return res.end(projectErrorMessage(id)); }
224
237
  registry.touchProject(id);
225
238
  return serveStatic(m[2] || '/', req, res);
226
239
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spectoflow",
3
- "version": "0.23.0",
3
+ "version": "0.23.1",
4
4
  "description": "Agent-agnostic spec-driven development framework + real-time local control plane. Markdown artifacts, intent router, workflow-by-scope.",
5
5
  "keywords": [
6
6
  "spec-driven-development",