Основи: продукт, код і робоче середовище
Термінал, локальне середовище та виконання програми
Уявіть, що агент написав: «Тести пройшли». Щоб оцінити цю фразу, недостатньо побачити зелену позначку. Треба знати, яку команду він запустив, з якого…
Уявіть, що агент написав: «Тести пройшли». Щоб оцінити цю фразу, недостатньо побачити зелену позначку. Треба знати, яку команду він запустив, з якого каталогу, в якій оболонці та середовищі, який процес реально її виконав, що вивів і з яким кодом завершився. І навіть це ще не доводить, що готова функція відповідає потребі користувача.
Термінал є місцем, де написана команда може стати дією: програма може прочитати файли, змінити їх, встановити залежності, відкрити мережевий порт або звернутися до даних. Навчившись читати журнал виконання, можна відрізнити видимий доказ від припущення, поставити агенту точне запитання й зупинити команду, побічний ефект якої не зрозумілий.
Навчальний результат
Після цієї глави читач може прочитати запис виконання команди й пояснити, де вона працювала, який процес її запустив, що означали її потоки виводу та код завершення, які файли або ресурси вона могла змінити й чого її результат не доводить. Він уміє розрізняти PowerShell, Bash (Bourne-Again SHell — оболонка Bourne-Again) та Linux-середовище в Windows, не переносить команди між ними навмання, знаходить можливі причини розбіжності між середовищем агента й власним комп’ютером та розпізнає моменти, коли треба попросити пояснення до продовження дії.
Передумови. За послідовністю курсу ця глава йде після глав 1–2. Вона використовує базове розуміння продукту, коду та репозиторію й коротко визначає потрібні тут терміни. Git детально розбиратиметься в главі 4, межі ізоляції — у главі 47, середовища — у главі 58. Встановлювати інструменти або виконувати завдання не потрібно.
Контекст прикладів. На час підготовки цієї глави в навчальному репозиторії є README.md і текстові глави, але немає маніфесту застосунку Node.js, тестового сценарію чи встановленого проєктного runtime. Тому наведені нижче команди й результати — позначені навчальні приклади з інших, умовних проєктів. Вони не є запуском у репозиторії курсу.
1. Термінал, оболонка, процес і агент — різні речі
Термінал — інтерфейс для введення команд і показу текстового результату. Колись він був окремим фізичним пристроєм; сьогодні це зазвичай вікно або вкладка в іншій програмі. Оболонка (shell) читає введений текст, розбирає його за власними правилами й запускає вказані команди. CLI (Command-Line Interface — інтерфейс командного рядка) — спосіб керувати програмою через команди й аргументи, а не через кнопки графічного вікна. Процес — екземпляр запущеної програми: він має власний ідентифікатор, поточний каталог, змінні середовища, відкриті потоки й дозволи.
Коли людина вводить node app.js у Bash або PowerShell, оболонка знаходить node, передає йому аргумент app.js і запускає процес. Node.js — середовище виконання JavaScript поза браузером — читає файл і виконує його. Для розуміння дії важливі також фактичний шлях програми, її налаштування та права.
Команда в журналі — не внутрішня «думка моделі». Зазвичай модель пропонує дію, продукт визначає, чи можна її запустити, у якому просторі й за якою політикою дозволів; оболонка розбирає рядок, а процес читає або змінює ресурси. Тому на безпеку впливають середовище, користувач процесу, мережа, дозволи на файли й налаштування продукту.
Для будь-якого запису спершу запитайте:
- Який клієнт агента та його інтерфейс запустив дію?
- Де виконувалася команда: на локальному комп’ютері, у контейнері, окремому робочому дереві Git чи на віддаленому виконавці?
- Яка оболонка, робочий каталог і точна команда?
- Який процес її виконав, що він міг читати або змінювати, і як завершився?
Повний журнал у розділі 9 збирає ці умови в одну послідовність, зокрема ідентичність процесу, вивід і стан після виконання.
Фраза «агент запустив це на моїй машині» надто нечітка. Настільний Codex розрізняє локальне, Git worktree на цьому комп’ютері та віддалене хмарне середовище; Codex CLI, інтегрований термінал і Claude Code можуть мати інші дозволи й спосіб запуску. Перевіряйте саме ту продуктову поверхню, що виконала команду (середовища Codex).
2. Де саме виконується команда
Середовище — це поєднання комп’ютера або віртуальної машини, операційної системи, файлової системи, встановлених програм, налаштувань, мережі та дозволів. Локальний процес запускається безпосередньо на комп’ютері. У процесно ізольованому режимі (process isolation) контейнер окремо відображає частину просторів імен операційної системи — наприклад, файлову систему, мережеві порти та простір ідентифікаторів процесів, — але процеси контейнера зазвичай ділять ядро хоста. Окремі ресурси можуть бути навмисно спільними: це залежить від налаштувань змонтованих файлів, мережевого простору імен, портів або пристроїв. У режимі Windows Hyper-V isolation контейнер працює всередині оптимізованої віртуальної машини й фактично має власне ядро. Отже, межі доступу залежать від платформи, runtime, режиму ізоляції й налаштованих спільних ресурсів; слово «контейнер» саме по собі не гарантує повної ізоляції. Microsoft про контейнери й віртуальні машини та режими ізоляції Windows Containers. Віддалений виконавець працює на іншій машині або в хмарному середовищі. У кожному з них можуть бути інші файли, версії програм, облікові дані й адреса localhost.
localhost означає «цей самий мережевий вузол, який бачить поточний процес». Для процесу в контейнері це може бути контейнер, а не ноутбук людини. Для віддаленого агента це може бути хмарна машина. Навіть Windows і Linux-середовище в Windows не завжди бачать localhost однаково: спосіб доступу залежить від версії та режиму мережі. У WSL 2 (Windows Subsystem for Linux — підсистема Windows для запуску Linux) типове перенаправлення портів дозволяє Windows звернутися до сервера Linux через localhost, але доступ у зворотному напрямку та поведінка у дзеркальному режимі залежать від налаштування мережі. Документація Microsoft про мережу WSL
Поточний каталог — це місце, відносно якого оболонка тлумачить короткі шляхи. Абсолютний шлях указує місце від кореня або диска; відносний описує шлях від поточного каталогу. Наприклад, src/app.js у каталозі /workspace/data-api означає /workspace/data-api/src/app.js. Такий самий відносний шлях із /workspace/other указує вже на інший файл.
Розширення файла — це кінцева частина його назви після останньої крапки: наприклад, .js у app.js або .md у README.md. Воно часто підказує формат чи програму, яка відкриє файл, але саме по собі не доводить, що вміст відповідає розширенню.
Windows та Linux показують шляхи по-різному. У PowerShell шлях може виглядати як C:\Projects\FootballStats\src\app.js; у Bash — як /home/sam/football-stats/src/app.js. Диск Windows у звичній конфігурації WSL видно Linux-процесу як /mnt/c/Projects/FootballStats, а домашній каталог Linux-дистрибутива є окремим місцем. Microsoft радить тримати файли там, де переважно працює інструмент: у файловій системі Windows для Windows-програм або у файловій системі Linux для Linux-програм, оскільки перехід між ними має різні наслідки для швидкодії й прав доступу. Microsoft про роботу між файловими системами
Щоб перейти до каталогу й прочитати початок файла, звірте команди з оболонкою. Перехід змінює каталог лише в поточній сесії; наведені команди читання файла не змінюють.
Windows PowerShell:
Set-Location 'C:\Projects\FootballStats'
Get-Location
Get-Content -LiteralPath '.\README.md' -TotalCount 20
Bash у Linux або macOS:
cd "/home/sam/football-stats"
pwd
sed -n '1,20p' README.md
Get-Content -TotalCount 20 і sed -n '1,20p' показують перші 20 рядків. Замініть зразкові шляхи на перевірений шлях свого проєкту; не вставляйте ці команди в іншу оболонку без адаптації.
У наведеній нижче таблиці — приклади безпечного огляду. Це окремі команди для конкретних оболонок, а не послідовність для копіювання в будь-який термінал.
| Що з’ясувати | Windows PowerShell | Linux або macOS, Bash |
|---|---|---|
| Поточний каталог | Get-Location |
pwd |
| Перелік звичайних і прихованих файлів | Get-ChildItem -Force |
ls -la |
| Який Node.js буде запущено | Get-Command node -All |
type -a node |
| Версія Node.js | node --version |
node --version |
| Де розташований вибраний Node.js | node -p 'process.execPath' |
node -p 'process.execPath' |
У PowerShell команди можуть бути псевдонімами чи функціями; Get-Command node -All показує знайдені варіанти з урахуванням пріоритету та $Env:PATH. Bash шукає функцію, вбудовану команду й виконуваний файл у $PATH; type -a node може показати кілька збігів. Звірте фактично вибраний файл і його шлях (PowerShell, Bash).
Назва файла теж не завжди відповідає його видимості. У Bash крапка на початку імені, як у .env, зазвичай означає прихований файл; ls -la показує й такі файли. У PowerShell файловий провайдер і прапорець -Force мають власну семантику. Файл може існувати, хоча звичайний список його не показує.
3. Як оболонка тлумачить команду
Командний рядок часто складається з назви програми, аргументів і прапорців. У node --test test/api.test.js назва програми — node, прапорець --test вмикає режим тестового запуску, а остання частина вказує файл. Слово «команда» не завжди означає один виконуваний файл: оболонка може підставити змінну, розгорнути шаблон файлів, перенаправити потік, з’єднати команди або виконати кілька рядків послідовно.
Пробіли відокремлюють аргументи, якщо оболонка не бачить лапок. Шлях C:\Project Demo\app.js без лапок може розпастися на кілька частин. Лапки зберігають шлях як одне значення, але самі лапки також можуть впливати на підстановку змінних. У PowerShell рядок у одинарних лапках є буквальним, а в подвійних $name замінюється значенням змінної. У Bash одинарні лапки вимикають підстановки, а подвійні зазвичай залишають підстановку змінних. Точні правила складніші; їх треба звіряти з документацією оболонки, а не вигадувати додаткові зворотні скісні риски навмання. Microsoft про лапки в PowerShell та GNU Bash про лапки
Змінна оболонки на кшталт $HOME або $Env:USERPROFILE може підставити шлях користувача, але синтаксис залежить від оболонки. Змінна, записана перед командою в Bash, може змінити оточення лише для цієї команди; PowerShell-змінна середовища $Env:APP_MODE належить процесу PowerShell і успадковується дочірнім процесом, який він запускає. Не переносіть приклад підстановки зі змінною між оболонками без адаптації.
Перенаправлення змінює місце, куди програма читає або пише. У Bash > зазвичай створює або перезаписує файл, а >> додає до нього в кінець. Запис 2>&1 з’єднує стандартний потік помилок зі стандартним виводом у конкретному порядку перенаправлень. У PowerShell є нумеровані потоки оболонки, і > для результату командлета зазвичай працює як передавання в Out-File; для стандартного виводу зовнішніх програм поведінка змінилася у PowerShell 7.4. Ці відмінності означають, що однаковий на вигляд оператор не завжди створить однаковий файл чи байти. Перезапис файлу — побічний ефект, а не оздоблення команди. GNU Bash про перенаправлення та Microsoft про потоки й перенаправлення PowerShell
4. Вивід, помилки й код завершення
Багато програм мають окремий звичайний потік виводу stdout (standard output — стандартний потік звичайного виводу) та stderr (standard error — стандартний потік діагностичних повідомлень). Обидва зазвичай видно у вікні, але оболонка може обробляти чи перенаправляти їх по-різному. Програма може записати попередження або навіть помилку в stderr, але повернути код успішного завершення; інша програма може вивести звичайний результат у stderr. Тому канал сам по собі не визначає правильність.
Після завершення процес повертає код завершення — домовлене числове значення для батьківського процесу. У Bash нуль означає, що команда повідомила про успіх; ненульове значення — що вона повідомила про помилку або інший стан. Якщо команда не знайдена, Bash зазвичай повертає 127. Поточний статус оболонка зберігає у $?, але наступна команда замінить це значення. У PowerShell $? зберігає коротку ознаку успіху останньої дії, а $LASTEXITCODE — код останньої зовнішньої програми. Треба читати статус відразу, до іншої команди, яка його змінить. Навіть нуль означає лише, що конкретний процес повідомив про успіх за своєю логікою; це не підтверджує бізнес-результат або повне покриття перевірки. GNU Bash про коди завершення та Microsoft про $? і $LASTEXITCODE
Моделі конвеєра й статусу відрізняються: Bash передає байти й за замовчуванням повертає статус останньої команди; pipefail зберігає помилку попередньої. PowerShell передає між командлетами об’єкти, а && і || з’явилися лише у версії 7. Це різні правила, не взаємозамінні скорочення; приклад нижче показує втрату помилки Bash (Bash, PowerShell).
Коли журнал обрізаний, завершився за тайм-аутом або показує лише останній рядок, невідоме не дорівнює успіху. Уточніть повну команду, її робочий каталог, оболонку, надану тривалість, код завершення, позначку усічення та факт, чи процес справді зупинився. Якщо команда запускала фоновий процес або від’єднала його від оболонки, зупинка очікування не доводить, що дочірній сервер завершився. Це висновок із моделі процесів, а не обіцянка поведінки кожного агентного інтерфейсу: його потрібно підтвердити спостереженням у тому самому середовищі.
5. Встановлення, збірка, запуск і перевірки
Слова install, build, run, test, lint і format часто стоять поруч у меню проєкту, але означають різні операції. Їхня точна поведінка задається файлами проєкту, параметрами та версіями інструментів.
| Операція | Типова мета | Можливі побічні ефекти, які треба перевірити |
|---|---|---|
Встановлення (install) |
Отримати залежності проєкту | Завантаження з мережі, зміна каталогу залежностей, оновлення lockfile, запуск сценаріїв пакунків залежно від версії й налаштувань пакетного менеджера. |
Збірка (build) |
Перетворити джерело на артефакти для запуску або поширення | Запис у dist/, кеш, згенеровані файли, карти джерел або інші продукти; іноді звернення до мережі чи служб. |
Запуск (run) |
Виконати програму або сценарій | Створення файлів, читання локальних даних, відкриття порту, запуск дочірнього процесу або звернення до зовнішнього сервісу. |
Тест (test) |
Перевірити частину очікуваної поведінки | Старт тестового сервера, зміна тестової бази, очищення фікстур, запис артефактів, мережеві виклики або фонові процеси. |
Перевірка стилю (lint) |
Знайти частину помилок або порушень правил у коді | Зазвичай читає файли, але плагіни й налаштування можуть завантажувати виконуваний код; перевірте, чи команда працює лише в режимі читання. |
Форматування (format) |
Переписати текст за правилами стилю | Зміна одного чи багатьох файлів; різницю треба переглянути до прийняття. |
У JavaScript-проєкті package.json — маніфест JSON (JavaScript Object Notation), а його секція scripts задає, що роблять npm test і npm run build; npm не надає цим командам універсального змісту. Lockfile зберігає вибране дерево залежностей. За документацією npm v11, npm ci вимагає lockfile, видаляє наявний node_modules, не змінює package.json чи lockfile і завершується помилкою, якщо вони не відповідають одне одному. Він встановлює залежності за lockfile, але може запускати lifecycle-скрипти проєкту й залежностей відповідно до версії та налаштувань. Перед повтором перевірте очікувані зміни (npm ci, lifecycle-скрипти).
Lockfile покращує відтворюваність, але не робить машини однаковими: можуть відрізнятися версії інструментів, ОС, архітектура, змінні та зовнішні служби.
6. Версії, $PATH і змінні середовища
Одна програма може мати кілька встановлень. Менеджери пакетів і версій іноді використовують shim — посередницький файл, що вибирає версію за каталогом чи налаштуванням. Новий термінал може мати інший профіль і $PATH, ніж термінал агента; «команда не знайдена» означає, що поточна оболонка її не знайшла.
У тому самому середовищі звірте фактично вибрану програму й версію командами з розділу 2: node --version і node -p 'process.execPath' показують версію та шлях Node.js. Відмінність — корисна зачіпка, але сама по собі не доводить причину збою. Node.js про process та змінні середовища
Змінні середовища — пари «назва-значення», які процес отримує під час запуску й передає дочірнім, якщо їх явно не замінити чи прибрати. Вони можуть задавати режим застосунку, адресу сервісу або шлях; синтаксис PowerShell ($Env:NAME) і Bash ($NAME, після експорту) різний. Регістр назв і зберігання змінних також залежать від операційної системи.
Секрети (ключі, паролі, токени) теж можуть бути в оточенні й залишатися видимими агенту або дочірньому процесу. Не друкуйте всі змінні через env, printenv чи Get-ChildItem Env:; для діагностики достатньо факту «задано / не задано», а секрет замаскуйте. За замовчуванням команди Claude Code у sandbox успадковують змінні батьківського процесу, зокрема облікові дані; налаштування sandbox.credentials можуть їх вилучити або замаскувати. Якщо sandbox не запускається через відсутні залежності чи непідтримувану платформу, Claude Code за замовчуванням попереджає й виконує команди без нього; sandbox.failIfUnavailable перетворює це на помилку. Перевіряйте ці режими для конкретного продукту й конфігурації (Claude Code).
7. Локальний сервер, порт і завершення процесу
Сервер — це програма, яка довше за одну команду очікує запитів. Зазвичай він слухає мережевий порт у певному просторі мережі. TCP (Transmission Control Protocol — протокол керування передаванням) — один зі способів, якими програми встановлюють з’єднання; номер порту разом із адресою допомагає системі спрямувати з’єднання потрібному слухачеві.
EADDRINUSE (address already in use — «адресу вже використовують») означає, що процес не зміг зайняти адресу або порт; помилка сама не встановлює причину. Можливі інший застосунок, сервер попереднього запуску, паралельний тест чи дочірній процес, інше мережеве середовище або помилка реалізації.
Документація Node.js визначає EADDRINUSE як помилку, що виникає, коли запитаний порт, шлях або дескриптор уже зайнятий (Node.js про помилку мережі). Реальний звіт у nodejs/node демонструє, чому не слід автоматично звинувачувати «забутий сервер»: автор описав нестабільне зіткнення між двома працівниками кластера, які створювали сервери на випадковому порту, звільняли його, а потім пробували використати знову. Помилка частіше виникала за високого навантаження процесора. Це конкретний звіт і відтворення з власним контекстом Node.js та macOS, а не пояснення кожного конфлікту портів і не доказ, що інший збій має ту саму причину (звіт nodejs/node #53738).
З’ясовуйте власника порту в тому самому середовищі, де працює сервер. На Windows Get-NetTCPConnection -LocalPort 4317 -State Listen показує PID власника; підставте його замість прикладового номера в Get-Process -Id 4812. На Linux ss -ltnp 'sport = :4317' показує слухачів, якщо утиліта доступна й дозволи дають бачити процес. Це команди читання стану; далі звірте, що процес належить потрібному проєкту (Microsoft).
Після тайм-ауту чи переривання дочірній процес може лишитися активним. Не запускайте Stop-Process -Name node, killall node чи pkill -f node через сам факт помилки порту: це може зупинити чужу програму. Спершу звірте PID, команду, каталог, час запуску, батьківський процес і власника; якщо зв’язок із поточною сесією неясний, попросіть дозвіл на зупинку.
8. PowerShell, Bash та WSL не мають спільної граматики
PowerShell працює на Windows, Linux і macOS, але синтаксис оболонки все одно є PowerShell. Команда $Env:APP_MODE = 'test' присвоює змінну середовища для поточної PowerShell-сесії, а Get-Location показує поточне місце у файловому провайдері. Його конвеєр передає об’єкти, найчастіше .NET-об’єкти командлетів. Виклик зовнішньої програми, наприклад node, повертає текст, але правила лапок і перенаправлення обробляє оболонка PowerShell перед передаванням аргументів. Деякі можливості різняться між Windows PowerShell 5.1 і PowerShell 7; наприклад, умовні оператори конвеєра && і || додані в PowerShell 7.
Bash — назва від Bourne-Again SHell (оболонка Bourne-Again), конкретна оболонка з родини Unix. Вона розбиває текст на слова, виконує розгортання змінних і шляхів, а оператор | передає байтовий потік наступній команді. Bash часто використовується у Linux, macOS та WSL, але сам факт запуску Bash не визначає операційну систему: на одному Windows-комп’ютері можуть працювати PowerShell, Bash у WSL і віддалена Bash-сесія. POSIX.1-2024 визначає опцію pipefail; оболонка, що відповідає цій редакції, має її підтримувати. Старіші реалізації sh або оболонки, що орієнтуються на попередні редакції стандарту, можуть її не підтримувати. Тому перевіряйте конкретну оболонку й її версію. Команда set -o pipefail у прикладі нижче розміщена в Bash-блоці; перед використанням в іншому sh перевірте його підтримку (GNU Bash Reference Manual, POSIX.1-2024: мова команд оболонки).
WSL — це окремий Linux-користувацький простір і набір програм із власним шляхом до файлів та процесами, не просто режим PowerShell. Розширення файлів, права, символьний регістр, шляхи, мережа та встановлені бінарні файли можуть відрізнятися між Windows і Linux у WSL. На Linux-подібній файловій системі доступ зазвичай описують бітами читання, запису й виконання для власника, групи та інших користувачів; для файлів Windows, змонтованих у /mnt/c, WSL може обчислити ці біти з фактичних Windows-дозволів, якщо не ввімкнено окремі метадані. Тому chmod 777 у WSL не може надати більше доступу, ніж дозволяє обліковий запис Windows. Якщо файл видно, це ще не означає, що процес має право його змінити (Microsoft про дозволи файлів у WSL).
Запис «команда виконалася на Windows» недостатній: уточніть оболонку й застосовуйте її синтаксис. Особливо перевірте команди на видалення, підвищення прав або перенаправлення.
9. Як читати журнал агента
Корисний журнал дозволяє відновити послідовність, а не лише побачити підсумкову фразу. Для кожного важливого запуску зафіксуйте або попросіть показати:
| Поле | На яке запитання відповідає |
|---|---|
| Час і послідовність | Яка дія передувала іншій; чи не показані лише вибрані записи? |
| Робоча директорія | Який саме файл або пакет означали відносні шляхи? |
| Продукт, середовище й shell | Який клієнт запустив команду; Windows, Linux, контейнер, WSL чи віддалена машина; PowerShell чи Bash? |
| Команда та аргументи | Який точний процес мав запуститися; чи були лапки, змінні й перенаправлення? |
| Обліковий запис і права | Від чийого імені виконувалася команда; чи мала вона підвищені права? |
| Ідентичність процесу (PID і батьківський процес, коли важливо) | Який процес запустив команду і чи належить він цій сесії? |
| Версії та виконуваний файл | Які Node.js, npm або інші інтерпретатори були реально вибрані? |
| Вивід | Які дані й помилки повернулися; чи позначено обрізаний вивід? |
| Код і стан після запуску | Який код повернувся; чи лишилися сервери, дочірні процеси або змінені файли? |
Не плутайте три твердження: «процес повернув код 0»; «перевірка охопила потрібний сценарій»; «функція правильна для користувача». Перше може бути доведене журналом конкретного виконання. Друге потребує знання тестів і конфігурації. Третє може вимагати аналізу поведінки продукту, даних і вимог.
Обрізаний вивід, відсутній stderr або лише останній статус конвеєра — привід попросити повний журнал. Без каталогу й середовища він не доводить, що перевіряли саме ваші файли; приклад 3 показує, як успішний останній процес може приховати попередню помилку.
10. Коли слід зупинити запуск і попросити пояснення
Зупиніться до виконання команди або подальших спроб, якщо не можете відповісти на питання: які саме шляхи вона зачепить, у якому середовищі, від чийого імені та чи можна відновити стан. Особливо уважно розбирайте:
- рекурсивне видалення, очищення або перезапис каталогів і wildcard-шаблони;
- підвищення прав, запуск від адміністратора чи
sudo; - запис поза робочим репозиторієм або команду, яка змінює системні налаштування;
- команду, що надсилає файли або змінні середовища в мережу, запускає невідомий скрипт чи передає завантажений код одразу в shell;
- встановлення залежностей у невідомому проєкті, форматування багатьох файлів або запуск тестів проти спільної чи робочої бази даних;
- завершення процесу без підтвердження PID (Process Identifier — ідентифікатора процесу, тобто номера, за яким операційна система розрізняє запущені процеси), батьківського процесу й належності поточній сесії;
- повтор команди з невідомими побічними ефектами після тайм-ауту або часткової помилки.
Попросіть агента пояснити команду по частинах: оболонка, каталог, кожен аргумент, змінні, перенаправлення, мережеві адреси, очікувані файли та спосіб відкату. Потім порівняйте пояснення з реальним diff, журналом або станом процесу. Дозвіл виконати одну дію не означає дозвіл повторити її в іншому середовищі чи застосувати права адміністратора.
11. Повністю розібрані приклади
Приклад 1. Тест не може відкрити зайнятий порт
Ситуація. Агент стверджує, що тест зупинився через «старий сервер». Щоб не вбити випадковий процес, спочатку відновимо факти.
Середовище та журнал. Це навчальна модель запуску сервісу приймання даних футбольних матчів у Linux-контейнері: Bash, Node.js 22.x, npm 11.x, каталог /workspace/football-stats-api. Усі рядки й числа вигадані; команди не запускалися, це не звіт про тест і не копія issue.
Environment: Linux container; Bash; Node.js 22.x; npm 11.x; cwd=/workspace/football-stats-api
$ npm ci
added 214 packages
process exit code: 0
$ npm test
> [email protected] test
> node --test
✖ feed ingestion service starts on configured port
Error: listen EADDRINUSE: address already in use 127.0.0.1:4317
ℹ tests 12
ℹ pass 11
ℹ fail 1
process exit code: 1
Що цей журнал доводить. npm ci завершився, а сценарій test завершився кодом 1: одна з 12 перевірок не змогла слухати 127.0.0.1:4317. Журнал не встановлює власника порту. Перед повтором перевірте побічні ефекти npm ci (розділ 5) і самого сценарію: тест може змінювати тестові дані або лишити дочірній сервер.
Розумна діагностика в тому самому Linux-середовищі може початися з читання слухачів порту, якщо ss встановлено й процес має достатні права:
ss -ltnp 'sport = :4317'
Припустімо, змодельований результат показує node, PID 4812 — ідентифікатор процесу в цьому середовищі на цей момент. Номер може бути повторно використаний після завершення процесу, тому звірте також команду запуску, каталог і батьківський процес. Сам факт, що процес має PID 4812, ще не підстава завершити його. Треба встановити, чи належить він процесу тесту з каталогу /workspace/football-stats-api, як його запущено й чи він не обслуговує інший проєкт. Якщо ідентичність лишається невідомою, команда має зупинитися й попросити власника перевірити процес. Не використовуйте killall node або шаблон завершення всіх процесів Node.js.
Зв’язок із реальним звітом. У nodejs/node issue #53738 описує macOS із Node.js 20.12.2: два працівники кластера одночасно створювали сервер на випадковому порту й після закриття знову намагалися прив’язатися до виданих номерів. Автор спостерігав нестабільний EADDRINUSE, частіше під навантаженням. Цей звіт дає реальну альтернативу поясненню «точно лишився старий процес», але його не можна автоматично переносити на наш змодельований Linux-тест. Підтвердженням тут є лише локальна перевірка, яка пов’язує порт із конкретним процесом та повторюваністю тесту.
Альтернативи й межі. Якщо порт належить процесу цієї самої тестової сесії, перевірте конфігурацію тесту й спосіб завершення сервера. Якщо порт належить іншій програмі, узгодьте альтернативний порт або окремий test environment. Якщо слухача немає, помилка могла бути короткою гонкою, або перевіряли інший контейнер чи мережевий простір. Динамічний порт може зменшити конфлікти, але сам по собі не виключає гонку між паралельними працівниками.
Приклад 2. Агенту працює, а локально падає
Ситуація. У чаті Codex у хмарному середовищі тест проходив, але на комп’ютері розробника та сама команда закінчується помилкою конфігурації. Статус «тести пройшли» не підтверджує, що перевірялися однакові файли, оболонка, версії чи змінні.
Порівняння. Наведені дані — умовний приклад, а не результати реально виконаних команд.
| Спостереження | Хмарне середовище агента, Bash | Комп’ютер розробника, PowerShell 7 на Windows |
|---|---|---|
| Робочий каталог | /workspace/checkout |
C:\Projects\Checkout |
| Знайдений Node.js | /usr/local/bin/node |
C:\Program Files\nodejs\node.exe |
node --version |
v22.14.0 |
v20.12.2 |
Несекретний APP_MODE |
задано | не задано |
| Тест | проходить | зупиняється з APP_MODE is required |
Чому це правдоподібне пояснення, але не остаточний діагноз. Середовища відрізняються щонайменше версією Node.js та однією змінною. Код може вимагати конкретної версії синтаксису чи API (Application Programming Interface — програмного інтерфейсу взаємодії), а програма може вмикати конфігурацію за APP_MODE. Проте з таблиці ще не відомо, яке з цих розходжень спричинило збій: могли також відрізнятися ревізія файлів, залежності, локальна .env-конфігурація, права доступу, база, мережа або кодування шляхів.
Що перевірити без друку секретів. У кожному середовищі зафіксуйте поля з розділу 9, потрібні версії та наявність APP_MODE; команди для каталогу й вибору Node.js наведено в розділі 2. Для секрету записуйте лише «задано / не задано», не значення: повний список середовища може розкрити токен агента.
Рішення. Команда знаходить у репозиторії домовлену версію середовища, перевіряє файл маніфесту та lockfile і запускає сценарій, який використовує тільки тестові дані. Якщо команда визначила, що причиною була відсутність APP_MODE, вона додає лише дозволене тестове значення у відповідну оболонку або тестову конфігурацію, а не змінює системну змінну всім користувачам. Якщо потрібна інша версія Node.js, її вибір погоджують через наявний менеджер версій або документацію проєкту, а не довільно встановлюють глобально.
Висновок. Однакова команда не означає однакове виконання, якщо середовища різні. Документація Codex прямо відрізняє локальне, робоче дерево та віддалене середовище; Claude Code також має свої дозволи, пісочницю та поведінку оболонки. Порівнювати треба контрольовані значення, по одному фактору за раз, не приписуючи відмінність моделі чи продукту без доказів.
Приклад 3. Успішна остання команда приховує попередню помилку
Ситуація. У Bash-скрипті перевірка шукає очікуване слово у файлі, а потім передає результат в наступну команду:
grep -q 'ready' missing.log | cat
echo $?
Змодельований вивід Bash:
grep: missing.log: No such file or directory
0
Перша команда не змогла відкрити файл і повернула помилку. Але cat, що є останньою командою конвеєра, отримав порожній вхід і завершився успішно. За стандартним правилом Bash статус конвеєра — статус останньої команди, тому наступний echo показав 0. Це свідчить лише про cat, а не про успішний пошук. GNU Bash документація уточнює, що опція pipefail змінює статус конвеєра на статус останньої з команд, яка завершилася ненульовим кодом.
Та сама перевірка з опцією pipefail у поточній Bash-сесії:
set -o pipefail
grep -q 'ready' missing.log | cat
echo $?
Тепер очікуваний код конвеєра ненульовий, бо помилка grep не губиться за успішним cat. Змодельоване виведення помилки все одно залишається на stderr. Команда set -o pipefail впливає на поточну Bash-сесію та її наступні конвеєри; не додавайте її навмання до глобального профілю оболонки.
Як це співвідноситься з PowerShell. PowerShell передає об’єкти між командлетами й має власні правила успіху та потік помилок (Error stream). У PowerShell 7 оператори && і || вирішують, чи запускати наступний конвеєр, за змінними статусу $? та $LASTEXITCODE; Windows PowerShell 5.1 не має цих операторів. Вони не вмикають еквівалент Bash pipefail. Отже, не можна побачити слово | й автоматично застосувати Bash-правила. У журналі має бути назва оболонки, точна команда та статус, збережений відразу після виконання.
Що повідомити рецензенту. Покажіть повний stderr, статус кожної команди в ланцюжку, назву shell, чи діяв pipefail, і що саме перевіряли (поля журналу — у розділі 9). Приклад показує помилку конкретного скрипту, а не те, що будь-який успішний конвеєр підозрілий.
Короткий підсумок
- Термінал показує обмін текстом; оболонка розбирає команду; процес реально виконує її з певним каталогом, оточенням і дозволами.
- Спочатку з’ясуйте, де виконувався агент: локально, у контейнері, WSL, робочому дереві або віддалено.
localhost, шляхи, встановлені програми та права залежать від середовища. - Команда може мати аргументи, підстановки, перенаправлення й ланцюги. Лапки, потоки та коди PowerShell, Bash і POSIX-shell відрізняються.
install,build,run,test,lintіformatмають різні цілі й можливі побічні ефекти; фактичні сценарії визначені проєктом.- Версія,
$PATH, змінні оточення й дочірні процеси пояснюють частину проблем «працює в агента, а локально ні». Секретні значення не друкують у журнал. - Код завершення — доказ того, що повідомив процес, але не підтвердження бізнес-правильності. При портовому конфлікті спершу знаходять власника, а не вбивають усі сервери.
- Якщо шлях, середовище чи побічний ефект не зрозумілі — зупиніть дію й попросіть розібрати команду до запуску. Для журналу потрібні також конкретна продуктова поверхня, точна команда, вивід, код завершення й стан після запуску.
Джерела та подальше читання
-
Microsoft Learn, about_Pipelines (PowerShell 7.5). Підтверджує, що PowerShell-командлети передають об’єкти конвеєром і пов’язують їх із параметрами наступної команди. Документація. Доступ: 23.09.2026.
-
Microsoft Learn, about_Quoting_Rules (PowerShell 7.5). Підтверджує різницю між одинарними буквальними й подвійними розгортальними рядками та обробку пробілів у аргументах. Документація. Доступ: 23.09.2026.
-
Microsoft Learn, about_Command_Precedence (PowerShell 7.5). Підтримує опис пріоритету команд,
$Env:PATH, псевдонімів і пошуку виконуваних файлів. Документація. Доступ: 23.09.2026. -
Microsoft Learn, about_Environment_Variables (PowerShell 7.5). Підтверджує успадкування процесного оточення дочірніми процесами та різницю Windows і Unix щодо регістру змінних. Документація. Доступ: 23.09.2026.
-
Microsoft Learn, about_Automatic_Variables (PowerShell 7.5). Підтверджує роль
$?і$LASTEXITCODE. Документація. Доступ: 23.09.2026. -
Microsoft Learn, about_Redirection (PowerShell 7.5). Підтверджує потоки PowerShell і зміну роботи з перенаправленням зовнішніх програм у PowerShell 7.4. Документація. Доступ: 23.09.2026.
-
Microsoft Learn, about_Pipeline_Chain_Operators (PowerShell 7.5). Підтверджує, що
&&та||додано у PowerShell 7 і вони використовують змінні статусу PowerShell. Документація. Доступ: 23.09.2026. -
Microsoft Learn, Get-NetTCPConnection (Windows Server 2025 / PowerShell). Підтверджує читання TCP-з’єднань, локального порту й ідентифікатора процесу-власника. Документація. Доступ: 23.09.2026.
-
GNU Project, Bash Reference Manual: розділи про quoting, перенаправлення, pipeline, пошук команд, environment та exit status. Підтверджує конкретну семантику Bash; її не слід переносити на PowerShell чи довільну POSIX-сумісну оболонку. Посібник. Доступ: 23.09.2026.
-
Microsoft Learn, Accessing network applications with WSL, Working across file systems та File Permissions for WSL. Підтверджують перенаправлення портів, режими мережі, змонтовані шляхи й обмеження дозволів під час взаємодії Windows та WSL. Мережа, файлові системи, дозволи файлів. Доступ: 23.09.2026.
-
Node.js, Process, Environment Variables, Child process і Net API (Application Programming Interface — програмний інтерфейс взаємодії). Підтверджують шлях та версію процесу, змінні оточення, запуск дочірніх процесів і помилку
EADDRINUSE; документація API, яку прочитано, була версії v26.10.0. Process, environment variables, child process, net. Доступ: 23.09.2026. -
npm, CLI v11.19.1:
npm ciі scripts. Підтверджує роль lockfile, очищенняnode_modulesпередnpm ciта життєвий цикл скриптів у зазначеній версії документації. npm ci, scripts. Доступ: 23.09.2026. -
OpenAI, Codex environments, sandboxing, agent approvals & security. Підтверджує локальний, worktree та cloud-режими настільного Codex, а також поточні межі workspace, мережі й погоджень для задокументованих клієнтів. Середовища, пісочниця, погодження й безпека. Доступ: 23.09.2026.
-
Anthropic, Claude Code: Configure permissions та Configure the sandboxed Bash tool. Підтверджує відокремлення правил дозволів від системної межі ізоляції та деталі успадкування оточення, мережі та переходу до виконання без пісочниці для Claude Code. Дозволи, пісочниця. Доступ: 23.09.2026.
-
nodejs/node, Issue #53738: EADDRINUSE error when trying to bind to port after it was closed. Реальний звіт автора з відтворенням на Node.js 20.12.2 і macOS про змагання кластерних працівників за порт; не універсальний висновок про всі помилки прив’язування. Issue. Створено 05.07.2024; переглянуто 23.09.2026. -
Microsoft Learn, Containers vs. virtual machines (документація Windows Server 2016–2025). Пояснює типове спільне ядро контейнерів і виняток із Hyper-V isolation; опис стосується Windows Containers. Документація. Доступ: 23.09.2026.
-
Microsoft Learn, Isolation modes: process isolation and Hyper-V isolation (документація Windows Server 2016–2025). Пояснює ізоляцію просторів імен і ядра, а також можливість спільного доступу до файлів, портів, мережі й пристроїв; опис стосується Windows Containers. Документація. Доступ: 23.09.2026.
-
The Open Group, Shell Command Language (POSIX.1-2024; Institute of Electrical and Electronics Engineers (IEEE — «Інститут інженерів з електротехніки та електроніки»), стандарт 1003.1-2024, редакція 2024 року). Визначає опцію
pipefailі те, як вона впливає на код завершення конвеєра. Стандарт. Доступ: 23.09.2026.