feat: choose your own pool account; skills with "token" in a doc name upload; System Health off Linux
- Skill snapshot/upload: a key file's name (.env, *.pem, id_rsa, .netrc, .credentials.json…) is always refused, but a word like token/secret/ password/credential only in a data file's name — design-tokens.md or count_tokens.py is skill content, not a key. - System Health: off Linux the History, CPU threads and Busiest processes cards (all read from /proc) are left out instead of shown empty; the CPU bar without a sample and Windows' always-zero Load row go too. - Users pick their own pool account per tool (/api/me/pool-accounts, Settings → AI tools), within their groups, refused while pinned. - Admin user detail, 9router update, session replay and Antigravity catalog changes from parallel sessions.
This commit is contained in:
@@ -35,6 +35,20 @@ const {
|
||||
|
||||
const router = Router();
|
||||
|
||||
/**
|
||||
* Whether `p` is a regular file, by `stat`. Not `fs.existsSync`: that is
|
||||
* access(2), which checks the REAL uid with capabilities cleared, so it says
|
||||
* "no" for a member's journal behind a 0700 folder (`~/.omp/agent`, S3) that
|
||||
* the server itself reads through its CAP_DAC_READ_SEARCH.
|
||||
*/
|
||||
function isFile(p) {
|
||||
try {
|
||||
return fs.statSync(p).isFile();
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// JSONL entry types the transcript reader turns into renderable messages.
|
||||
// `user`/`assistant` are the conversation. `custom-title` is the metadata line
|
||||
// written by /rename, `claude -n`, and the picker's Ctrl+R — surfaced as an
|
||||
@@ -864,7 +878,7 @@ router.get("/:id/transcripts", async (req, res) => {
|
||||
? require("../lib/cursor-usage").transcriptPath(req.params.id)
|
||||
: require("../lib/antigravity-usage").transcriptPath(req.params.id);
|
||||
const list =
|
||||
file && fs.existsSync(file)
|
||||
file && isFile(file)
|
||||
? [
|
||||
{
|
||||
id: "main",
|
||||
@@ -1142,7 +1156,7 @@ router.get("/:id/transcript", async (req, res) => {
|
||||
getSnapshotTranscriptPath(req.params.id);
|
||||
}
|
||||
|
||||
if (!jsonlPath || !fs.existsSync(jsonlPath)) {
|
||||
if (!jsonlPath || !isFile(jsonlPath)) {
|
||||
return res.json({ messages: [], total: 0, has_more: false, last_line: 0, first_line: 0 });
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user