sandbox_sync

ローカルのディレクトリ、または 1 つのファイルをボックスの /work/<dest> にアップロードします。違うファイルだけを送ります。stdio アダプター経由でのみ動きます。

入力 出力
id、localPath、dest、commit、alsoPaths、includeIgnored、exclude、prune、submodules、baseline、baselineDeps、dryRun、maxMB(アダプターのみ) ok、dest、remotePath、selected、files、sentFiles、sentPaths、changedOnBox、uploadedBytes、skipped。該当するときは staleInDest、pruned、excluded、deps、uncommitted、commitSha、submodules、submodulesMissing、notes。dryRun では dryRun、sendMB、totalMB、largest。baseline を指定したときは baseline と note も

sandbox_sync(アダプターのみ)はローカルディレクトリを /work/<dest> にアップロードします。localPath は絶対パスで渡してください。相対パスはアダプターのプロセスの作業ディレクトリを基準に解決され、エージェントからは見えません。dest は /work からの相対パスで、/work/app ではなく app と書きます。先頭の /work/ は取り除かれるので /work/app でも動きますが、それ以外の絶対パスや /work の外に出るパスは、何も送る前にエラーになります。

git の作業ツリーでは、git が追跡しているファイルと .gitignore で除外されていない未追跡ファイルを対象に、dest にあるものと違うファイルをボックスに問い合わせ、それだけを送ります。そのため /work/<dest> を監視している dev server には編集した箇所だけが届きます。skipped は送らなかったトップレベルの名前です。git 以外では node_modules、.git、dist、build、coverage、.venv など以外のすべてのファイルを、commit ではそのコミットのファイルを対象に、同じように比べて違うものだけを送るので、2 回目の同期は変わったものだけを送ります。.git は送りません。結果は何が起きたかを伝えます。

  • remotePath:ボックスのどこに置かれたか。/work/<dest> です。
  • sentPaths:この呼び出しで送ったファイル(先頭 50 件。sentFiles が総数)。changedOnBox:ボックスが実際に書き換えたファイルの数。0 なら、ボックスにはすでに全部ありました。
  • notes:対応が必要なこと。たとえば package.json、vite.config.*、tsconfig*、.env* を送ったときは、動いている dev server(Vite、webpack、Metro)がページ全体を再読み込みするか再起動し、言語、ルート、差し込んだデータのようなページの状態が失われます。ほかに次のことも伝えます。
    • 依存:node_modules は送りません。package-lock.json、pnpm-lock.yaml、yarn.lock があるのにボックスに node_modules がないフォルダーは、そこで実行するインストールのコマンド(sandbox_build { "dir": "repo/sdk", "cmd": "npm ci", "out": ["node_modules"] } など)と一緒に挙げます。npm では、インストール済みのパッケージが lockfile と比べて足りない、またはバージョンが違うとき、その数と例を伝えます。同じ内容は deps(dir、lock、state が missing か stale)にも入ります。そこで出る "Cannot find module" はこれが原因で、あなたの変更のせいではありません。
    • dest への最初の同期:無視ルールが外したビルド設定(tsconfig.json、.env.local、*.config.*)とその送り方(それらを alsoPaths に並べるか includeIgnored)、そして .git は送らないので、そこでの git コマンドは "not a git repository" で失敗すること。
    • 実行ビットなしで送った gradlew、mvnw、#! で始まる *.sh(git が 100644 で記録しているもの):bash で実行するか、ボックスで chmod +x してください。
    • fetch failed、接続のリセット、HTTP 502/504 のあとで 1 回だけ送り直したアップロード。
  • 同期に失敗すると、結果は NOT SYNCED: /work/<dest> still has its old files (or only part of this sync) と伝え、送ろうとしていたファイルを並べます。そのあとそこで動かすコマンドは古いコードを見ます。そのボックスで次に呼んだ sandbox_exec の結果の最後にも、一度だけ警告が付きます。テスト結果を信じる前に、もう一度同期してください。

サイズ:送る量(ディスク上のサイズ)が 100 MB を超える同期は何も送りません。エラーには renderer/ 195.2 MB in 1203 files (renderer/dist-win/ 191.6 MB) のように大きいフォルダーが並びます。そうしたビルド成果物は .gitignore か exclude に加えるか、commit と alsoPaths で自分のファイルだけを送るか、そのサイズが想定どおりなら maxMB を渡してください。"dryRun": true はボックスと比べて、同期したら何を送るか(sentFiles、sentPaths、sendMB、largest、staleInDest、notes)を返し、何も送らず何も消しません。同期中は、進捗を求めるクライアントに 10 秒ごとに 1 行(ハッシュ計算、比較、アップロード済みの MB)が届きます。2 分間何も進まないアップロードや、受け取ってから 10 分以内にボックスが応答しないアップロードは、止まったままにならず、その段階を書いたメッセージで失敗します。

1 つのファイル:localPath がファイルのときは、dest がボックス内でのそのファイルのパスです。"localPath": "/abs/repo/renderer/.env", "dest": "renderer/.env" は /work/renderer/.env に書きます。dest が / で終わるか、ボックスですでにフォルダーになっているときは、ファイルはその中に元の名前で入ります。どちらになったかは remotePath でわかります。commit、alsoPaths、prune にはディレクトリが必要です。

削除:localPath になく dest にあるファイル(ローカルで削除・改名したもの、または送ったコミットにもうないもの)はボックスに残り、そこで実行した型チェックやテストはそのファイルのエラーを出し続けます。結果の staleInDest がそれらを並べ(count と先頭 20 件の paths。1000 件を超えると countIsPartial)、notes でも知らせます。"prune": true で削除でき、pruned が削除した数です。ローカルの無視ルールが除外するパス(node_modules、ビルド成果物、.env)は数えも消しもしないので、ボックスが自分で作ったものは残ります。prune には、localPath が git の作業ツリーにあるか commit があること、dest が /work の下(/work そのものではない)であること、includeIgnored がないことが必要です。新しい dest に同期しても、まっさらなツリーが得られます。

オプション:

  • commit:作業ツリーではなく、この git リビジョン(HEAD、origin/main)のツリーを送ります。共有の作業ディレクトリにある他人の書きかけのファイルが入りません。存在しないリビジョンはエラーになり、何も送られません。結果の commitSha が送ったコミットです。
  • alsoPaths:commit と一緒に使い、localPath 配下のこれらのパスはそのツリーではなく作業ツリーのものを使います。コミットに自分の編集を加えた状態をテストできます。ディレクトリはコミット側のものを丸ごと置き換え、中身は commit なしの同期で送られるファイルになります。作業ツリーで削除・改名したファイルがコミット側から戻ってくることはなく、node_modules のような無視されたファイルは includeIgnored を指定しない限り入りません。commit なしでは、alsoPaths はそれらのパス(ファイルやディレクトリ。git diff --name-only の一覧など)だけを、それぞれ dest の下の同じ場所に、同じ選び方で送ります。staleInDest もそのディレクトリの中だけを探します。それらがリポジトリのほかの場所から import しているファイルは一緒に送られません。ボックスにまだ全体のコピーがないときは、サブフォルダーだけを同期せず、"commit": "HEAD" にそれらのパスを alsoPaths として付けて送ってください。
  • includeIgnored:無視ルールで除外されるファイル(dist、生成物)も、.git 以外すべて送ります。既定はオフです。
  • exclude:localPath からの相対の glob。この同期では両方向とも手を付けません。送らず、比べず、ボックス側のコピーを staleInDest に並べることも prune で消すこともないので、ボックスで変えたファイル(dev server を指すようにした capacitor.config.ts など)はそのまま残ります。/ を含まないパターンはどの階層のその名前にも当たり(*.log、dist-win)、/ を含むものは localPath から数えます(android/app/build.gradle)。** はフォルダーをまたぎます。外したものは excluded に並びます。
  • dryRun:何も送らず何も消さずに、同期したら何をするかを返します(上記)。
  • maxMB:1 回の同期のサイズ上限。既定は 100 です(上記)。
  • prune:staleInDest に並んだものを削除します(上記)。
  • submodules:commit と一緒に使い、各サブモジュールもツリーが記録しているコミットで送ります(下記)。
  • baseline:同じ呼び出しで、この git リビジョン(HEAD、origin/main、ブランチのマージベース)のツリーも <dest>-baseline に送ります。2 つのコピーは同じリポジトリの同じ時点から作られます。結果に baseline(そのコピーの dest、commit、件数、または error)と note が加わります。使い方は下にあります。
  • baselineDeps:baseline と一緒に使い、dest の各 node_modules を baseline にコピーします(既定は true。下記)。

ほかの人や会話も編集している作業ディレクトリ(1 つのリポジトリで複数のセッションが作業している場合)では、commit なしの同期はその人たちの書きかけのファイルも送り、ボックスはそのエラーをあなたのもののように出します。こうした同期では、HEAD と違うパスが uncommitted に並び(count と、git status のコード付きの先頭 20 件)、注意書きが付きます。"commit": "HEAD" を送り、自分の未コミットのファイルを alsoPaths に並べるか、自分専用の git worktree を同期してください。

sandbox_sync { "id": "<id>", "localPath": "/absolute/path/to/repo", "dest": "repo", "commit": "HEAD", "alsoPaths": ["src/refund.ts", "src/refund.test.ts"] }

テストが失敗し、自分の変更のせいか分からないときは、baseline を付けて両方のコピーで同じコマンドを実行します。

sandbox_sync { "id": "<id>", "localPath": "/absolute/path/to/repo", "dest": "repo", "baseline": "origin/main" }
sandbox_exec { "id": "<id>", "cmd": "go test ./... 2>&1 | grep -E '^(--- FAIL|FAIL|ok)'", "cwd": "repo", "note": "変更を入れたテストを実行" }
sandbox_exec { "id": "<id>", "cmd": "go test ./... 2>&1 | grep -E '^(--- FAIL|FAIL|ok)'", "cwd": "repo-baseline", "note": "変更前の同じテストを実行" }

両方で失敗するものは、変更の前から失敗していたものです。1 回の呼び出しで両方の実行と比較ができます。"baseline": true を付け、cwd を dest の中にした sandbox_exec は、コマンドを repo で、次に repo-baseline で実行し、所要時間とテスト番号を無視して onlyMine、alreadyFailing、fixedByMine を返します(sandbox_exec)。

sandbox_exec { "id": "<id>", "cmd": "go test ./...", "cwd": "repo", "baseline": true, "note": "変更ありとなしでテストの失敗を比べる" }

新しいテストがバグを捕まえることを示すには、そのテストを repo-baseline にコピーして、そちらで失敗するのを確かめます。baseline のコピーには、そのコミットが追跡しているファイルに加えて、dest の各 node_modules のコピーが同じ場所に入ります。baseline にまだないものだけを、ハードリンクで作ります(ディスクを追加で使わず、数秒です)。baseline.depsCopied がその一覧です。2 つのツリーはそれぞれ自分のフォルダーと Vite のキャッシュを持つので、同時に動かせます(1 つの node_modules を両方に symlink すると Vite のキャッシュが互いに上書きされます)。baseline のコミットの lockfile が別のバージョンを求めるときは、baseline の notes がそう伝えるので、そこで npm ci を実行してください(コピーは置き換わります)。"baselineDeps": false でコピーしません。baseline には専用のテスト用データベース(psbx-testdb up base)を用意して、2 つの実行が互いのテーブルを消さないようにしてください。

git サブモジュール:

  • commit なしでは、初期化済みのサブモジュールはディスク上の状態のまま丸ごと送られます。中の無視されたファイル(その node_modules、ビルド成果物)も含み、変更がなくても同期のたびに送られます。初期化していないサブモジュールは空のディレクトリになります。
  • commit ありのとき、および baseline のコピーでは、"submodules": true を付けない限りサブモジュールは空のディレクトリです(git archive はサブモジュールの中に入りません)。付けると、各サブモジュール(入れ子のものも)がツリーの記録しているコミットで、ローカルのサブモジュールのチェックアウトから送られます。結果の submodules(path、commit)に並び、送れなかったものは理由付きで submodulesMissing に並びます(初期化していない:git submodule update --init。そのコミットがローカルのサブモジュールにない:そこで git fetch)。同期全体は止まりません。
  • .git は送られないので、同期したコピーでは git コマンド(git submodule update、git describe)が動きません。ビルドに必要なら、代わりにボックスで git clone --recurse-submodules してください。

すべてのツールとトピックはツールリファレンスに並んでいます。