fix(pi): add snap node compatibility diagnostics and documentation
- Added detailed error logging to detect snap node compatibility issues - When Pi process exits with code 1, log helpful diagnostic info including node path - Add hint to check for snap node and reinstall via apt/nvm - Create SNAP_NODE_COMPATIBILITY.md with full troubleshooting guide - Document root cause: snap node has file descriptor incompatibility with Bun.spawn stdin pipes - Provide clear installation instructions for NodeSource and nvm alternatives
This commit is contained in:
@@ -30,6 +30,7 @@ piRestRouter.get('/pi/models', async (ctx: Context) => {
|
||||
providerNames[`officer-local-${lp.id}`] = lp.name;
|
||||
}
|
||||
|
||||
logger.info('Models endpoint', { count: models.length, providers: [...new Set(models.map((m) => m.provider))] });
|
||||
return ctx.json({ models, providerNames, hostHome: process.env.HOME ?? '' });
|
||||
} catch (err) {
|
||||
logger.error('Failed to list models', { error: String(err) });
|
||||
@@ -51,7 +52,9 @@ piRestRouter.post('/pi/sessions', async (ctx: Context) => {
|
||||
const body = await ctx.req.json().catch(() => ({}));
|
||||
const userHome = getHomeDir(user.email);
|
||||
const filterCwd = body.cwd ? resolveBaseCwd(user.email, body.cwdRoot, body.cwd) : null;
|
||||
const contextFilter = body.context ? { context: body.context as string, contextId: body.contextId as string | undefined } : undefined;
|
||||
const contextFilter = body.context
|
||||
? { context: body.context as string, contextId: body.contextId as string | undefined }
|
||||
: undefined;
|
||||
|
||||
try {
|
||||
let sessions = await storage.listUserSessions(userHome, contextFilter);
|
||||
@@ -119,6 +122,14 @@ piRestRouter.get('/pi/sessions/:sessionId', async (ctx: Context) => {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* PUT /api/pi/sessions/:sessionId/messages
|
||||
* Client-side message save — no-op, sessions are persisted server-side via WebSocket events
|
||||
*/
|
||||
piRestRouter.put('/pi/sessions/:sessionId/messages', async (ctx: Context) => {
|
||||
return ctx.json({ success: true });
|
||||
});
|
||||
|
||||
/**
|
||||
* PATCH /api/pi/sessions/:sessionId
|
||||
* Update session metadata (e.g., rename)
|
||||
@@ -162,9 +173,14 @@ piRestRouter.patch('/pi/sessions/:sessionId', async (ctx: Context) => {
|
||||
}
|
||||
}
|
||||
|
||||
const updatedMeta = await storage.updateSessionMeta(userHome, sessionId, {
|
||||
title: body.title,
|
||||
}, groupSlug);
|
||||
const updatedMeta = await storage.updateSessionMeta(
|
||||
userHome,
|
||||
sessionId,
|
||||
{
|
||||
title: body.title,
|
||||
},
|
||||
groupSlug,
|
||||
);
|
||||
|
||||
return ctx.json({
|
||||
success: true,
|
||||
@@ -246,7 +262,9 @@ piRestRouter.delete('/pi/sessions', async (ctx: Context) => {
|
||||
}
|
||||
|
||||
const body = await ctx.req.json().catch(() => ({}));
|
||||
const contextFilter = body.context ? { context: body.context as string, contextId: body.contextId as string | undefined } : undefined;
|
||||
const contextFilter = body.context
|
||||
? { context: body.context as string, contextId: body.contextId as string | undefined }
|
||||
: undefined;
|
||||
const userHome = getHomeDir(user.email);
|
||||
|
||||
try {
|
||||
@@ -260,7 +278,12 @@ piRestRouter.delete('/pi/sessions', async (ctx: Context) => {
|
||||
// Skip sessions that fail to delete
|
||||
}
|
||||
}
|
||||
logger.info('Bulk deleted sessions', { email: user.email, deleted, total: sessions.length, context: contextFilter?.context });
|
||||
logger.info('Bulk deleted sessions', {
|
||||
email: user.email,
|
||||
deleted,
|
||||
total: sessions.length,
|
||||
context: contextFilter?.context,
|
||||
});
|
||||
return ctx.json({ success: true, deleted });
|
||||
} catch (err) {
|
||||
logger.error('Failed to bulk delete sessions', { email: user.email, error: String(err) });
|
||||
|
||||
Reference in New Issue
Block a user