{"record":{"id":"ca7ad461dbf8a769","repo":"paperclipai/paperclip","slug":"applying-a-company-import-from-a-non-interactive-t","errorCode":null,"errorMessage":"Applying a company import from a non-interactive terminal requires --yes. Use --dry-run first to inspect the preview.","messagePattern":"Applying a company import from a non-interactive terminal requires --yes\\. Use --dry-run first to inspect the preview\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"cli/src/commands/client/company.ts","lineNumber":814,"sourceCode":"  url.hash = \"\";\n  return url.toString();\n}\n\nexport function resolveCompanyImportApplyConfirmationMode(input: {\n  yes?: boolean;\n  interactive: boolean;\n  json: boolean;\n}): \"skip\" | \"prompt\" {\n  if (input.yes) {\n    return \"skip\";\n  }\n  if (input.json) {\n    throw new Error(\n      \"Applying a company import with --json requires --yes. Use --dry-run first to inspect the preview.\",\n    );\n  }\n  if (!input.interactive) {\n    throw new Error(\n      \"Applying a company import from a non-interactive terminal requires --yes. Use --dry-run first to inspect the preview.\",\n    );\n  }\n  return \"prompt\";\n}\n\nexport function isHttpUrl(input: string): boolean {\n  return /^https?:\\/\\//i.test(input.trim());\n}\n\nexport function looksLikeRepoUrl(input: string): boolean {\n  try {\n    const url = new URL(input.trim());\n    if (url.protocol !== \"https:\") return false;\n    const segments = url.pathname.split(\"/\").filter(Boolean);\n    return segments.length >= 2;\n  } catch {\n    return false;","sourceCodeStart":796,"sourceCodeEnd":832,"githubUrl":"https://github.com/paperclipai/paperclip/blob/67001ec6eb96ae601aa27bc91d9b2415d665334a/cli/src/commands/client/company.ts#L796-L832","documentation":"Thrown by resolveCompanyImportApplyConfirmationMode when an apply is run from a non-interactive terminal (no TTY on stdin/stdout) without --yes. Without a TTY the confirmation prompt cannot be displayed, so the library blocks the destructive apply and points the caller at --dry-run.","triggerScenarios":"Piping stdout into a file or another command, running inside cron/systemd/Docker without a pseudo-TTY, SSH non-interactive sessions, or any shell where process.stdin.isTTY or process.stdout.isTTY is false — and --yes is not set.","commonSituations":"Scheduled nightly imports, CI runners, containerized jobs, 'nohup' or backgrounded processes, and redirected output (>'log'). The interactive prompt worked locally but fails in the scheduled environment.","solutions":["Add --yes to the apply command when running non-interactively.","Allocate a TTY if you genuinely want the prompt (ssh -t, docker run -t -i, or run directly in a terminal).","Run --dry-run first in the same environment to validate the package, then apply with --yes.","In code, detect !process.stdin.isTTY up front and force yes:true before calling resolveCompanyImportApplyConfirmationMode."],"exampleFix":"# before (cron)\n0 2 * * * paperclipai company import pkg.zip --target new-company\n# after\n0 2 * * * paperclipai company import pkg.zip --target new-company --yes","handlingStrategy":"validation","validationCode":"function resolveConfirmationMode(input: { yes?: boolean; interactive: boolean; json: boolean }) {\n  const nonInteractive = !input.interactive;\n  if (nonInteractive && !input.yes) {\n    throw new Error(\"Non-interactive terminal: pass --yes or run interactively.\");\n  }\n  return input.yes ? \"skip\" : \"prompt\";\n}","typeGuard":"function isInteractiveApplyReady(input: { yes?: boolean; interactive: boolean }): boolean {\n  return input.yes === true || input.interactive === true;\n}","tryCatchPattern":null,"preventionTips":["Detect TTY up front and fail fast with a clear message.","Bake --yes into every scheduled/CI invocation.","Document that cron/docker/ssh-default sessions are non-interactive."],"tags":["cli","validation","non-interactive","company-import","tty"],"backgroundTag":null,"analyzedSha":"67001ec6eb96ae601aa27bc91d9b2415d665334a","analyzedAt":"2026-08-12T12:05:45.408Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}