{"record":{"id":"338010ee18720f92","repo":"affaan-m/ECC","slug":"end-requires-a-file-path","errorCode":null,"errorMessage":"end requires a file path","messagePattern":"end requires a file path","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/plan-canvas.js","lineNumber":329,"sourceCode":"// Report feedback the human sent that no agent has picked up yet. Reads state\n// directly so it answers even when the server has idled out.\nfunction cmdPending({ stateDir }) {\n  const store = createSessionStore({ stateDir });\n  const waiting = store\n    .list()\n    .filter(session => session.status !== 'ended' && session.pending > 0)\n    .map(session => ({ file: session.file, pending: session.pending, updatedAt: session.updatedAt }));\n  return {\n    status: waiting.length ? 'pending' : 'clear',\n    sessions: waiting,\n    next_step: waiting.length\n      ? 'Run `ecc-plan-canvas await <file>` for each file above to receive the messages.'\n      : 'No canvas feedback is waiting.'\n  };\n}\n\nasync function cmdEnd(file, { port }) {\n  if (!file) throw new Error('end requires a file path');\n  if (!(await healthCheck(port))) return { status: 'no-server' };\n  const res = await request(port, 'POST', '/api/end', { file: path.resolve(file) });\n  return res.body;\n}\n\nasync function cmdStop({ stateDir, port }) {\n  if (!(await healthCheck(port))) return { status: 'not running' };\n  await request(port, 'POST', '/shutdown').catch(() => {});\n  fs.rmSync(serverInfoPath(stateDir), { force: true });\n  return { status: 'stopping' };\n}\n\nasync function cmdServer(args, { stateDir, port }) {\n  const portArg = valueAfter(args, '--port');\n  const hostArg = valueAfter(args, '--host');\n  const listenPort = portArg !== null ? Number.parseInt(portArg, 10) : port;\n  const store = createSessionStore({ stateDir });\n  let shuttingDown = false;","sourceCodeStart":311,"sourceCodeEnd":347,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/plan-canvas.js#L311-L347","documentation":"cmdEnd terminates the canvas session tied to a plan file by POSTing the resolved path to /api/end. The file argument is mandatory; without it the command cannot identify which session to end and throws 'end requires a file path' immediately, before the health check.","triggerScenarios":"Running `ecc-plan-canvas end` with no positional argument — omitted path, empty shell variable, or an npm-script/alias wrapper that does not forward arguments.","commonSituations":"Cleanup steps in CI where `END_FILE=$PLAN_FILE` was never set; ending a session from a different directory and assuming the tool infers 'the current plan'; typos where the path was given to the wrong flag.","solutions":["Pass the plan file path: `ecc-plan-canvas end path/to/plan.md` (same path used with `open`).","Guard shell variables: `: \"${PLAN_FILE:?PLAN_FILE not set}\"` before invoking end.","If the session is already gone, note cmdEnd returns the server's body regardless — once a valid path is supplied, 'no-server' or an already-ended status is a non-error outcome.","Fix any wrapper script so positional arguments are forwarded."],"exampleFix":"# before\necc-plan-canvas end\n\n# after\necc-plan-canvas end \"$PLAN_FILE\"   # e.g. ecc-plan-canvas end docs/plans/feature.plan.md","handlingStrategy":"validation","validationCode":"if (!PLAN_FILE) { echo 'usage: ecc-plan-canvas end <file>' >&2; exit 2; }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Reuse one canonical plan-path variable across open/await/end in CI cleanup steps.","Fail fast on empty variables with :? expansions.","Remember end is idempotent once a valid path is given — a 'no-server' body is fine."],"tags":["cli","missing-argument","plan-canvas"],"backgroundTag":"missing-required-argument","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}