first-app / plan-and-build · 約 15 分

codex exec で生成する

制約付きプロンプトで server.js を作らせます。自分で置いても構いません。

学習目標

非対話の codex exec に、成果物と制約と検証を1つのプロンプトで渡します。 [codex-noninteractive]

前提

Git リポ。workspace-write が使えること。

なぜ必要か

対話だけだと再現しにくいです。exec なら同じプロンプトを再実行できます。

実行場所

codex exec は local-bridge です。Web実習 (browser) では starter の Node ファイルを実 FS に書いて node --check できます。プロンプト全文(starter の完了条件と一致):

このディレクトリに Node.js の小さな HTTP サーバを作ってください。

要件:
- package.json の name は hello-codex-school、type は module
- scripts.start は node server.js、scripts.test は node --test
- server.js は node:http のみを使う
- 127.0.0.1 のポート 4780(環境変数 PORT があればそれを使う)
- GET / と GET /health は 200 で本文 hello-codex-school
- その他は 404
- 応答に Access-Control-Allow-Origin: * と
  Cross-Origin-Resource-Policy: cross-origin と
  Cross-Origin-Embedder-Policy: require-corp を付ける
  (学習サイトの COEP require-corp 下での iframe 埋込と、
   サイト origin からの http_ok fetch 用。公開学習本文のみ)
- test/http.test.js を置く。server.js を別ポート(例: 4799)で spawn し、
  fetch で GET / が 200 かつ hello-codex-school であること、
  ACAO / CORP / COEP ヘッダがあることを assert する
- 依存パッケージを増やさない
- 秘密値をファイルに書かない

終わったら node --check server.js と npm test を実行して報告する。
npm test を codex の sandbox(workspace-write)内で走らせるときは、
-c sandbox_workspace_write.network_access=true が必要です
(既定では localhost の listen / fetch が拒否されます。このフラグは外向き通信も許可します。
ユーザー config の sandbox を緩めず、この実行だけに付けます)。
codex exec --sandbox workspace-write \
  -c sandbox_workspace_write.network_access=true \
  "$(cat <<'EOF'
このディレクトリに Node.js の小さな HTTP サーバを作ってください。
要件は README・package.json・test/http.test.js と一致させる。
scripts.test は node --test。依存を増やさない。秘密値を書かない。
終わったら node --check server.js と npm test を実行して報告する。
EOF
)" </dev/null

</dev/null は非 TTY / スクリプト実行で、プロンプトを引数に渡したとき stdin 待ちで止まらないための EOF です。対話 TUI の codex では不要です。

node --check server.js が終了コード 0 であることと、test/http.test.jsnpm test script があることが判定です。次の run-and-preview と capstone で HTTP と npm test を実実行します。 [codex-prompting]

test/http.test.js 全文:

import assert from "node:assert/strict";
import test from "node:test";
import { spawn } from "node:child_process";

test("GET / returns hello-codex-school with embed/CORS headers", async (t) => {
  const port = "4799";
  const child = spawn(process.execPath, ["server.js"], {
    env: { ...process.env, PORT: port },
    stdio: ["ignore", "pipe", "pipe"],
  });
  t.after(() => {
    child.kill("SIGTERM");
  });
  await new Promise((resolve, reject) => {
    const timer = setTimeout(resolve, 500);
    child.stdout.on("data", () => {
      clearTimeout(timer);
      resolve();
    });
    child.on("error", reject);
  });
  const res = await fetch(`http://127.0.0.1:${port}/`);
  assert.equal(res.status, 200);
  assert.equal(await res.text(), "hello-codex-school");
  assert.equal(res.headers.get("access-control-allow-origin"), "*");
  assert.equal(res.headers.get("cross-origin-resource-policy"), "cross-origin");
  assert.equal(res.headers.get("cross-origin-embedder-policy"), "require-corp");
});

ホスト上の確認:

npm test

sandbox 内で同じテストを走らせるときだけ:

codex sandbox -c 'sandbox_mode="workspace-write"' \
  -c 'sandbox_workspace_write.network_access=true' -- npm test

成功結果

server.jshello-codex-school127.0.0.1 があり、package.jsontest script、test/http.test.js があります。

失敗対処

読み取り専用で書けないときは --sandbox workspace-write です。ネットワークインストールを始めたら、制約を再送してください。npm test が sandbox 内で fetch failed / EPERM なら、上記の network_access=true をその実行だけに付けます。global の sandbox 設定は緩めません。

このレッスンで接続する

ページを移動するとブラウザ内実習の接続とファイルは消えます。演習の直前に、このパネルから明示的に再接続してください(自動では戻りません)。