phewsh 0.14.4 → 0.14.5

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/commands/serve.js +46 -0
  2. package/package.json +1 -1
package/commands/serve.js CHANGED
@@ -264,6 +264,51 @@ function main() {
264
264
  }
265
265
  }
266
266
 
267
+ // Mission control state — the same five rows bare `phewsh` shows, so
268
+ // the web cockpit (phewsh.com/cockpit) mirrors the CLI to a T.
269
+ if (url.pathname === '/cockpit' && req.method === 'GET') {
270
+ try {
271
+ const { listHarnesses, HARNESSES } = require('../lib/harnesses');
272
+ const { outcomeStats, pendingDecisions, bypassStats } = require('../lib/outcomes');
273
+ const { listProjects } = require('../lib/projects-index');
274
+
275
+ let config = {};
276
+ try { config = JSON.parse(fs.readFileSync(path.join(os.homedir(), '.phewsh', 'config.json'), 'utf-8')) || {}; } catch { /* none */ }
277
+
278
+ const harnessList = listHarnesses().map(h => ({
279
+ id: h.id, label: h.label, role: h.role, installed: h.installed, headless: h.headless,
280
+ }));
281
+
282
+ // Same route precedence as the CLI session
283
+ const chatCapable = harnessList.filter(h => h.installed && h.headless);
284
+ let routeId = null;
285
+ if (config.defaultRoute === 'api' && config.apiKey) routeId = 'api';
286
+ else if (config.defaultRoute && chatCapable.some(h => h.id === config.defaultRoute)) routeId = config.defaultRoute;
287
+ else if (config.apiKey) routeId = 'api';
288
+ else if (chatCapable.length > 0) routeId = chatCapable[0].id;
289
+
290
+ const intentFiles = ['vision.md', 'plan.md', 'next.md']
291
+ .filter(f => fs.existsSync(path.join(process.cwd(), '.intent', f)));
292
+
293
+ return json(res, {
294
+ project: { name: path.basename(process.cwd()), cwd: process.cwd(), intentFiles },
295
+ route: routeId === 'api'
296
+ ? { id: 'api', label: `API (${config.provider || 'anthropic'} key)` }
297
+ : routeId ? { id: routeId, label: HARNESSES[routeId].label } : null,
298
+ fallback: config.fallback === 'auto' ? 'auto' : 'ask',
299
+ harnesses: harnessList,
300
+ web: { loggedIn: !!config.supabaseUserId, email: config.email || null },
301
+ record: outcomeStats(),
302
+ pending: pendingDecisions().length,
303
+ bypasses: bypassStats(),
304
+ recentProjects: listProjects().slice(0, 5).map(p => ({ name: p.name, path: p.path, lastOpened: p.lastOpened })),
305
+ version: require('../package.json').version,
306
+ });
307
+ } catch (err) {
308
+ return json(res, { error: err.message }, 500);
309
+ }
310
+ }
311
+
267
312
  // The proof trail — same merged data as `phewsh receipts` and the MCP
268
313
  // bridge's /receipts, so the web can show evidence regardless of which
269
314
  // local bridge is running.
@@ -298,6 +343,7 @@ function main() {
298
343
  console.log(` ${g('Live execution bridge for phewsh.com/intent')}`);
299
344
  console.log('');
300
345
  console.log(` ${green('●')} Running on ${w(`http://localhost:${port}`)}`);
346
+ console.log(` ${g('Web cockpit:')} ${w('phewsh.com/cockpit')} ${g('— mirrors this machine live')}`);
301
347
  console.log('');
302
348
  console.log(` ${b('Connected runtimes:')}`);
303
349
  runtimes.forEach(r => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "phewsh",
3
- "version": "0.14.4",
3
+ "version": "0.14.5",
4
4
  "description": "Turn intent into action. Structure your thinking, execute your next step.",
5
5
  "bin": {
6
6
  "phewsh": "bin/phewsh.js"