{"record":{"id":"9912c83e6ca0736f","repo":"affaan-m/ECC","slug":"typing-requires-a-file-path","errorCode":null,"errorMessage":"typing requires a file path","messagePattern":"typing requires a file path","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"scripts/plan-canvas.js","lineNumber":302,"sourceCode":"  process.stderr.write('[plan-canvas] waiting for human feedback... leave this running (re-run if interrupted; queued feedback is never lost)\\n');\n  const result = await awaitRequest(port, sessionKeyFor(canonicalizeArtifactPath(file)), timeoutMs);\n  if (result.status === 'feedback') {\n    result.next_step = result.sessionEnded\n      ? 'The user sent this feedback and ended the session. Address it and report in chat; do not reopen the canvas uninvited.'\n      : 'Address the feedback, then run `ecc-plan-canvas await <file> --reply \"<what you changed>\"` to answer in the canvas and keep listening.';\n  } else if (result.status === 'ended') {\n    result.next_step =\n      result.endedBy === 'user'\n        ? 'The user ended this review. Stop polling and deliver any remaining updates in chat; do not reopen uninvited.'\n        : 'Session ended. Stop polling.';\n  }\n  return result;\n}\n\n// Show the human an activity indicator in the canvas chat. Cheap and\n// fire-and-forget: a failed signal must never derail the actual work.\nasync function cmdTyping(file, args, { port }) {\n  if (!file) throw new Error('typing requires a file path');\n  const state = valueAfter(args, '--state') || 'typing';\n  if (!(await healthCheck(port))) return { status: 'no-server' };\n  const key = sessionKeyFor(canonicalizeArtifactPath(file));\n  const res = await request(port, 'POST', `/api/session/${key}/typing`, { state });\n  if (res.statusCode !== 200) throw new Error(res.body.error || `typing failed (HTTP ${res.statusCode})`);\n  return { status: 'ok', state, presence: res.body.presence };\n}\n\n// 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',","sourceCodeStart":284,"sourceCodeEnd":320,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/scripts/plan-canvas.js#L284-L320","documentation":"Thrown by cmdTyping when the `typing` subcommand is called without a positional file path. The typing command POSTs an activity/presence indicator to a per-file review session (`/api/session/<key>/typing`), so the session key is derived from the file and cannot be omitted. It is a fire-and-forget presence signal meant to cheaply show the agent is working.","triggerScenarios":"Calling `node scripts/plan-canvas.js typing` with only `--state` and no file; an agent loop that sends typing pings but lost the file reference; typo'ing the subcommand order so a flag lands where the file belongs.","commonSituations":"Agent orchestrator passes an optional file that was undefined for this turn; user copies the typing example but drops the path; session was never `open`ed so the caller assumes no file needed.","solutions":["Provide the file whose session you want to signal: `node scripts/plan-canvas.js typing .claude/plans/feature.plan.md`.","Ensure `open <file>` ran first so a session exists for that key.","Treat typing failures as non-fatal in the caller — the source comment says a failed signal must never derail the work, so wrap the call and ignore errors when the file is unknown."],"exampleFix":"// before\nnode scripts/plan-canvas.js typing --state thinking\n// after\nnode scripts/plan-canvas.js typing .claude/plans/feature.plan.md --state thinking","handlingStrategy":"validation","validationCode":"function validateTypingFile(file) {\n  if (typeof file !== 'string' || file.trim() === '') {\n    throw new Error('cmdTyping: file argument is required');\n  }\n  return file;\n}","typeGuard":"function isTypingFile(arg) {\n  return typeof arg === 'string' && arg.length > 0 && !arg.startsWith('--');\n}","tryCatchPattern":"// Presence signals must never break the parent workflow\ntry {\n  await cmdTyping(file, args, ctx);\n} catch (err) {\n  console.error(`[plan-canvas] typing signal skipped: ${err.message}`);\n  // continue regardless\n}","preventionTips":["Treat typing as best-effort: log and ignore failures.","Ensure `open <file>` ran before sending presence pings.","Pass the same file path used for open/await so the session key matches."],"tags":["cli","argument-validation","plan-canvas","presence"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}