{"record":{"id":"7cc23518fe10f3d4","repo":"Hmbown/CodeWhale","slug":"bad-args-trajectory-id-must-be-a-traj-jsonl-name-from","errorCode":"bad_args","errorMessage":"trajectory id must be a traj-*.jsonl name from trajectory status","messagePattern":"trajectory id must be a traj-\\*\\.jsonl name from trajectory status","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"crates/tui/plugins/computer-use/src/trajectory.mjs","lineNumber":85,"sourceCode":"      });\n  } catch { return []; }\n}\n\n/**\n * Resolve an id (\"latest\" or a traj-*.jsonl basename) to a file inside the\n * trajectories dir. Anything that escapes the directory is refused, not read.\n */\nexport function resolveTrajectory(id) {\n  const dir = trajectoriesDir();\n  const bad = (message) => Object.assign(new Error(message), { code: \"bad_args\" });\n  const missing = (message) => Object.assign(new Error(message), { code: \"trajectory_not_found\" });\n  let name = typeof id === \"string\" && id.trim() && id !== \"latest\" ? id.trim() : null;\n  if (!name) {\n    const recent = listTrajectories(1);\n    if (!recent.length) throw missing(\"no trajectories on this machine yet — start one with trajectory {action:\\\"start\\\"}\");\n    name = recent[0].id;\n  }\n  if (name.includes(\"/\") || name.includes(\"\\\\\") || name.startsWith(\".\")) throw bad(\"trajectory id must be a traj-*.jsonl name from trajectory status\");\n  const file = path.resolve(dir, name);\n  if (path.dirname(file) !== path.resolve(dir)) throw bad(\"trajectory id must stay inside the trajectories directory\");\n  if (!fs.existsSync(file)) throw missing(`no trajectory named \"${name}\" (see trajectory {action:\"status\"})`);\n  return file;\n}\n","sourceCodeStart":67,"sourceCodeEnd":91,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/plugins/computer-use/src/trajectory.mjs#L67-L91","documentation":"resolveTrajectory validates a user-supplied trajectory id before resolving it to a file inside the plugin's trajectories directory. If the id contains path separators or starts with a dot it is rejected, because ids must be plain traj-*.jsonl filenames listed by trajectory status. This is a guard against path traversal and malformed ids.","triggerScenarios":"Calling any trajectory action with an id containing '/' or '\\\\' or beginning with '.' (e.g. '../foo', 'sub/traj-1.jsonl', '.hidden.jsonl', or an absolute path).","commonSituations":"Pasting a full file path instead of the bare id shown by trajectory status; constructing ids programmatically from directory listings including '.'/'..'; a client cache holding pre-slug ids from an older plugin version.","solutions":["Run trajectory {action:\"status\"} and pass the exact id it reports (e.g. 'traj-20260921-....jsonl')","Strip any directory portion and pass only the basename that matches traj-*.jsonl","Pass no id at all (or 'latest') to let resolveTrajectory pick the most recent trajectory"],"exampleFix":"// before\nrun(\"trajectory\", {action:\"read\", id:\"/home/me/.codewhale/trajectories/traj-abc.jsonl\"})\n// after\nrun(\"trajectory\", {action:\"read\", id:\"traj-abc.jsonl\"})","handlingStrategy":"validation","validationCode":"const ok = typeof id === 'string' && /^traj-[^/\\\\]*\\.jsonl$/.test(id) && !id.startsWith('.');\nif (!ok) throw new Error('id must be a traj-*.jsonl name from trajectory status');","typeGuard":"const isTrajectoryId = (v) => typeof v === 'string' && /^traj-[^/\\\\]*\\.jsonl$/.test(v);","tryCatchPattern":"try { await run('trajectory', {action:'read', id}) } catch (e) { if (e.code === 'bad_args') console.error('Bad trajectory id:', id); else throw e }","preventionTips":["Always source ids from trajectory {action:\"status\"} output","Never interpolate directory paths into the id","Prefer omitting the id to target the latest trajectory"],"tags":["validation","path-traversal","plugin"],"backgroundTag":"invalid-identifier-format","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T16:17:23.217Z"}