phewsh 0.14.3 → 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.
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 => {
@@ -4,13 +4,16 @@
4
4
  // so running `phewsh` at machine root becomes mission-control bootstrap
5
5
  // ("where do you want to work?") instead of "no project found, goodbye."
6
6
  //
7
- // Storage: ~/.phewsh/projects.json. Local-first; web sync layers on top.
7
+ // Storage: ~/.phewsh/project-index.json. Local-first; web sync layers on top.
8
+ // NOT projects.json — that file belongs to `phewsh mcp` (web project cache,
9
+ // array-shaped). Claiming it caused a startup crash AND would have clobbered
10
+ // MCP data on first write. One file, one owner.
8
11
 
9
12
  const fs = require('fs');
10
13
  const path = require('path');
11
14
  const os = require('os');
12
15
 
13
- const INDEX_FILE = path.join(os.homedir(), '.phewsh', 'projects.json');
16
+ const INDEX_FILE = path.join(os.homedir(), '.phewsh', 'project-index.json');
14
17
 
15
18
  // Shallow-scanned roots when the user asks to find projects. One level deep,
16
19
  // opt-in only — deep-scanning someone's machine uninvited is invasive.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "phewsh",
3
- "version": "0.14.3",
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"