codexteer 0.19.0 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/README.md +11 -5
- package/bin/codexteer.mjs +1 -1
- package/docs/distribution.md +21 -6
- package/docs/orchestration.md +4 -4
- package/package.json +1 -1
- package/src/cli.mjs +18 -15
- package/src/cloud-cli.mjs +7 -25
- package/src/cursor.mjs +370 -0
- package/src/directive.mjs +3 -2
- package/src/distribution.mjs +58 -33
- package/src/findings.mjs +7 -5
- package/src/help-cloud-remote.mjs +2 -2
- package/src/help-errors.mjs +1 -1
- package/src/help-intervention.mjs +1 -1
- package/src/help-local.mjs +4 -2
- package/src/help-supervision.mjs +15 -11
- package/src/help.mjs +71 -3
- package/src/journal.mjs +11 -5
- package/src/monitor.mjs +3 -2
- package/src/observe.mjs +7 -36
- package/src/orchestrate-prompt.mjs +14 -12
- package/src/orchestrate.mjs +4 -7
- package/src/paged-read.mjs +9 -16
- package/src/prompt-command.mjs +45 -7
- package/src/prompt.mjs +15 -12
- package/src/supervise.mjs +4 -6
- package/src/task-id.mjs +24 -0
- package/src/unknown-options.mjs +17 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
公開日は日本時間です。
|
|
4
4
|
|
|
5
|
+
## 0.20.0 — 2026-11-02公開
|
|
6
|
+
|
|
7
|
+
- 介入も報告も不要な通知に「変化なし」とだけ応答する指示を、標準方針から共通手順へ移しました。`supervise prompt`のMESSAGEやオーケストレーションの担当方針で方針を置き換えても、方針に別の指定がなければ維持されます。
|
|
8
|
+
- 監督役が自分の判断・指示を`--kind decision`(ユーザー決定の伝達)で送っていたため、decisionはユーザー本人の決定を発言日時とともに引用する場合に限り、監督の指示は`review`で送るよう生成プロンプトで指示します。`supervise status`・`help send`・`help findings`の確認は最初の介入の前に一度にしました。
|
|
9
|
+
- 生成プロンプトは、タスクが待機中でも監督停止まで監視を続け、会話の要約・再起動の後は実行コマンド・読了cursorを確認し、手順を読み直してから再開するよう指示します。実行コマンドをシェル変数や関数に入れないこと(zshでは終了コード127になります)、調べれば分かる事実や決まっていることをユーザーに聞き直さないこと、別の論点には別のkeyを使うことも加えました。
|
|
10
|
+
- `orchestrate prompt`の本文は、本文と各担当のdata.promptをファイルに保存して要約・再起動の後に読み直すよう指示します。全体の完了時とユーザーの停止指示時には、各担当の監督を`supervise stop`で終了します。既存の成果物や以前のAIが選んだ仕組みを確定要件として扱わないことも明記しました。
|
|
11
|
+
- 子の監督本文だけで継続と監視の終了が決まるようにしました。共通手順は、監督方針で明示的に許可された`--new-turn`の再開と、方針の終了条件を認めます。オーケストレーションの担当方針は、idleの未完了作業の再開(paused/stopped・承認・質問待ちは迂回しない)と、ユーザーの停止指示か全体の完了を終了条件とすることを定めます。`orchestrate prompt`の本文から、子の規則を読み替える文を削除しました。標準方針は再開も終了条件も定めないため、単一スレッド監督の挙動は変わりません。
|
|
12
|
+
- 保存済みCLI方式の`supervise`・`supervise prompt`・`orchestrate`・`orchestrate prompt`は、300〜500文字の実行コマンド(`CODEX_HOME`指定・Node・保存したCLIのパス・`--require-node-version`・`--supervisor`・`--connection`・リモートの経路)を本文に20回ほど繰り返す代わりに、これらを固定した起動ファイル`CODEX_HOME/codex-steer/bin/codexteer-s-<hash>`(プロジェクト用は`codexteer-p-<hash>`)を生成し、そのパスを1語の実行コマンドとして示します。子の監督本文は約4割短くなります。起動ファイルは本人専用で内容のハッシュを名前にし、同じ名前で内容が違えば上書きせず`LAUNCHER_MODIFIED`、生成時に実行できなければ本文を出力せず`LAUNCHER_UNUSABLE`で止まります。`--json`は`data.command`も返します。
|
|
13
|
+
- `--supervisor`・`--connection`・`--require-node-version`・`--host`・`--remote-transport`・`--context-thread`を`--`より前に重ねて指定すると、全経路で`OPTIONS_INVALID`になります。生成した実行コマンドに付け直しても束縛は変わりません。以前の版が生成した長い実行コマンドはそのまま使えます。`--use-path-cli`の実行コマンドと動作は変わりません。
|
|
14
|
+
- `read`・`watch`・`status`が返すcursorを、タスクのターン数で長くならない`c1`で始まる形式にしました。全ターンの一覧の代わりにターン列のSHA-256を持ち、`--since`・`--based-on`では従来どおり現在のターン列・項目と照合するため、`STALE_CURSOR`・`STALE_OBSERVATION`の判定は変わりません。200ターンのタスクでは約18,600文字から約190文字になります。以前の版が出力したcursor(`eyJ`で始まる)も引き続き使え、続きは新しい形式で返します。保存済みの指摘・送信履歴の記録は変わりません。保存済みCLIなど以前の版に新しいcursorを渡すと`STALE_CURSOR`になるため、`--since`なしで読み直してください。
|
|
15
|
+
- 失敗した呼び出しは`error.help`に該当トピック、`error.action`にそのトピックに記載した対処を返し、引数エラー(`OPTIONS_INVALID`・`CLOUD_OPTIONS_INVALID`・`DESKTOP_CLOUD_OPTIONS_INVALID`)は`error.usage`に失敗したサブコマンドの使い方も返します。テキスト出力では標準エラーに`使い方:`・`対処:`の行を足します。代わりに`help <topic>`はテキストでも`--json`でもエラー一覧を載せず、`help <topic> --errors`を示す1行だけにしました(`--json`の`errors`配列は`errors_command`に置き換わります)。一覧は`help <topic> --errors`で取得できます。`help send`は約4,300から約2,300 o200kに減ります。エラーコード・メッセージ・終了コードは変わりません。
|
|
16
|
+
- `findings`の`create`・`reopen`・`show`・`list`・`resolve`・`dismiss`・`evaluate`(`revisions`を含む)と`history list`・`show`・`check`・`mark`、`instructions list`は、`based_on`のcursorをそのまま返す代わりに、cursorのSHA-256(16進64桁)を`based_on_sha256`として返します。保存済みの記録は全文のcursorを保持し、以前の記録もそのまま読めます。
|
|
17
|
+
- 生成プロンプトは、会話の要約・再起動の後に保存した本文を読み直し、保存していない場合だけ`help monitor`を読むよう指示します。単発の`watch --until change`の行の後に、完了まで待つ`--until idle`と本文を短くする`--max-chars N`(既定2000)も示します。
|
|
18
|
+
- `send`・`thread create`(ローカル・Cloud・Desktop Cloud)・`orchestrate`で`--`より前の未知のオプションを拒否するとき、エラー文と`error.unknown_options`がその語を示します(例: `Unknown send option: --kidn. Put instruction text that starts with -- after --.`)。示すのは`--`で始まる語を先頭から3件までで、本文を含まないよう各語を最初の空白の手前・40文字までに切り詰めます。拒否する入力・エラーコード・終了コードは変わりません。
|
|
19
|
+
- 生成済みの本文は変わりません。更新後のCLIで生成し直してください。
|
|
20
|
+
|
|
5
21
|
## 0.19.0 — 2026-11-01公開
|
|
6
22
|
|
|
7
23
|
- タスクIDと接続指定の不一致エラーに、修正用の`--connection`とJSONの`expected_connection`・`connection`を追加しました。Desktop Cloudには`desktop-cloud`、Web Cloudには`cloud`、ローカルには既定の`shared`を示します。拒否・終了コード・既存エラーコードを維持し、自動切り替えは行いません。
|
package/README.md
CHANGED
|
@@ -159,11 +159,11 @@ codexteer supervise <thread-id> "セキュリティの問題だけを私へ報
|
|
|
159
159
|
|
|
160
160
|
上書きは今回の生成・起動だけに適用し、次回の既定設定や保存したCLIには書き込みません。改行・空白・プレースホルダーに見える文字も指定文のまま本文に含めます。空文字・空白だけのメッセージはエラーです。呼び出し元のシェルで一つの引数として引用してください。`$`やバッククォートを文字として含めるときは、シェルが展開しない引用方法を使ってください。
|
|
161
161
|
|
|
162
|
-
既定では両方とも、起動したCLI本体と依存を`CODEX_HOME/codex-steer/runtimes/<version>-<sha256
|
|
162
|
+
既定では両方とも、起動したCLI本体と依存を`CODEX_HOME/codex-steer/runtimes/<version>-<sha256>`へ検証して保存し、そのコピーを実行する起動ファイルを`CODEX_HOME/codex-steer/bin/codexteer-s-<hash>`に作って、そのパスを実行コマンドとして監督プロンプトに埋め込みます。監督役に渡す切り替えオプションは不要です。npxのキャッシュが新版に更新された場合や、ソース導入先を`git pull`・削除した場合も、開始済みの監督は保存した内容を使い続けます。
|
|
163
163
|
|
|
164
|
-
|
|
164
|
+
起動ファイルは、生成時に検証した`CODEX_HOME`の実体パス、Node、保存したCLI、監督ごとの`--supervisor` ID、選択した`--connection`(リモートでは経路も)を固定した本人専用のシェルスクリプトです。プロンプトにはそのパスが1語だけ現れ(空白等を含むホームでは引用します)、監督役は後ろにサブコマンドを付けて実行します。固定済みのオプションを付け直すと`OPTIONS_INVALID`で止まります。名前は内容のハッシュで、同じ内容なら検証して再利用し、異なる内容の既存ファイルは上書きせず`LAUNCHER_MODIFIED`で止まります。生成時に一度実行し、sandboxなどで実行できなければ本文を出力せず`LAUNCHER_UNUSABLE`で止まります。貼り付け先の環境変数が未設定・別設定でも、生成元の接続先と履歴を使います。同じPCで使い、監督中は保存したコピーを保持してください。新しいCLIや別のプロファイルに切り替えるときは、その環境から監督を起動し直すか、プロンプトを生成し直します。同じ版・同じ内容のコピーは検証して再利用し、内容が変われば別の保存先を作ります。既存のコピーは自動削除・上書きしません。
|
|
165
165
|
|
|
166
|
-
Node本体はコピーせず、開始時の実体への絶対パスとNode
|
|
166
|
+
Node本体はコピーせず、開始時の実体への絶対パスとNodeバージョンの検査を起動ファイルに含めます。元のNodeは保持してください。バージョンが変われば`NODE_VERSION_MISMATCH`で操作を止めます。同じバージョンのNodeの改変や共有ライブラリまで固定するものではありません。保存先やNodeが使えなくなった場合は介入を止め、理由を報告するよう指示します。
|
|
167
167
|
|
|
168
168
|
起動時にバージョンを指定するかどうかに関係なく、監督用CLIの保存処理は同じです。キャッシュの動作と保存処理の詳細は[配布ドキュメント](docs/distribution.md#監督役が使うcli)を参照してください。
|
|
169
169
|
|
|
@@ -174,7 +174,7 @@ codexteer supervise <thread-id> --use-path-cli
|
|
|
174
174
|
codexteer supervise prompt <thread-id> --use-path-cli
|
|
175
175
|
```
|
|
176
176
|
|
|
177
|
-
この場合の実行例は`codexteer --supervisor '<SESSION-ID>' --connection shared read <thread-id> --json`の形式です。CLI
|
|
177
|
+
この場合の実行例は`codexteer --supervisor '<SESSION-ID>' --connection shared read <thread-id> --json`の形式です。CLIのコピー・起動ファイルの生成・Nodeの固定・`CODEX_HOME`の埋め込みを行わず、実行環境のPATHと`CODEX_HOME`を使います。CLIの更新は次の実行から反映されます。監督ID・接続方式・一時停止等の制御は維持するため、対象Desktopと同じプロファイルで実行してください。直接起動時も同じプロンプトを渡し、登録と終了時の停止を行います。`--agent`・監督方針・`--connection desktop`と併用でき、エージェント用の`--`区切りより前に指定します。`supervise prompt --json`の`data.cli_mode`は`path`、`data.deployment`と`data.node`は`null`です。指定しなければ`cli_mode`は`saved`で、従来の保存済みCLIを使います。
|
|
178
178
|
|
|
179
179
|
モデルなどClaude側の起動引数は、`--`の後ろへ渡します。
|
|
180
180
|
|
|
@@ -398,6 +398,9 @@ codexteer help send
|
|
|
398
398
|
codexteer send --help
|
|
399
399
|
codexteer help send --json
|
|
400
400
|
|
|
401
|
+
# そのコマンドのエラーと対処の一覧(通常のヘルプには載せず、失敗時はerror.actionに返る)
|
|
402
|
+
codexteer help send --errors
|
|
403
|
+
|
|
401
404
|
# Claude CodeのMonitorとの連携
|
|
402
405
|
codexteer help monitor
|
|
403
406
|
|
|
@@ -407,6 +410,8 @@ codexteer --version
|
|
|
407
410
|
|
|
408
411
|
引数なしの`codexteer`と`codexteer --help`でも全体のヘルプを表示します。
|
|
409
412
|
|
|
413
|
+
失敗した呼び出しは`--json`の`error.help`に該当トピックを、`error.action`にそのトピックに記載した対処を返します。引数エラー(`OPTIONS_INVALID`など)は`error.usage`に失敗したサブコマンドの使い方も返します。テキスト出力では標準エラーの`使い方:`・`対処:`の行に出ます。
|
|
414
|
+
|
|
410
415
|
#### 監督役の起動
|
|
411
416
|
|
|
412
417
|
```bash
|
|
@@ -451,7 +456,7 @@ codexteer help supervise prompt
|
|
|
451
456
|
|
|
452
457
|
`supervise prompt`は、ClaudeやCodexなどの監督役(オーケストレーター)へ渡す初期プロンプトを生成します。対象IDと引数を検証し、既定ではCLI一式を内容ハッシュ別の保存先へ配置・検証してから、正規化したIDと保存先を本文へ埋め込みます。保存・検証に失敗した場合は本文を出力せず、直接起動の場合も監督エージェントを起動しません。Desktopの起動・接続、履歴取得、送信、監督エージェントの起動は行いません。タスクの存在と接続は監督開始時に確認します。本文には観測・根拠付き介入・結果確認・停止までの手順を含みます。
|
|
453
458
|
|
|
454
|
-
|
|
459
|
+
既定の実行コマンドは起動ファイルの絶対パスで、起動ファイルが開始時のNodeと保存したCLIの絶対パスを使うため、本文を貼り付ける先のPATHに`codexteer`がなくても実行できます。起動ファイルは`CODEX_HOME`に生成元のプロファイルを設定します。相対パスやシンボリックリンクで指定していたホームも、検証した実体への絶対パスを使います。空白や引用符を含むパスはシェル引数として引用します。本文に埋め込むパスに改行等の制御文字があれば、本文を出力する前に`SUPERVISION_PATH_UNSAFE`で拒否します。実行コマンドはシェル変数に入れず、毎回そのまま書いてください。以前の版が生成した`CODEX_HOME='…'`から始まる実行コマンドも、そのまま使えます。別のPCや別のプロファイルを監督する場合は、そこで本文を生成し直してください。
|
|
455
460
|
|
|
456
461
|
`--use-path-cli`を指定すると、本文はPATH上の`codexteer`を使い、CLIの保存や絶対パスの埋め込みを省略します。接続先と履歴は実行環境の`CODEX_HOME`に従います。
|
|
457
462
|
|
|
@@ -464,6 +469,7 @@ codexteer help supervise prompt
|
|
|
464
469
|
"data": {
|
|
465
470
|
"thread_id": "aaaaaaaa-aaaa-4aaa-8aaa-000000000001",
|
|
466
471
|
"prompt": "対象IDと保存したCLIの実行コマンドを含む監督プロンプト本文…",
|
|
472
|
+
"command": "/Users/me/.codex/codex-steer/bin/codexteer-s-<hash>",
|
|
467
473
|
"cli_mode": "saved",
|
|
468
474
|
"deployment": {
|
|
469
475
|
"codex_home": "/Users/me/.codex",
|
package/bin/codexteer.mjs
CHANGED
|
@@ -5,5 +5,5 @@ import { cloudInvocation, mainCloud } from "../src/cloud-cli.mjs";
|
|
|
5
5
|
|
|
6
6
|
const args = process.argv.slice(2);
|
|
7
7
|
if (cloudInvocation(args)) {
|
|
8
|
-
try { await mainCloud(args); } catch (failure) { fail(failure, args.includes("--json")); }
|
|
8
|
+
try { await mainCloud(args); } catch (failure) { fail(failure, args.includes("--json"), args); }
|
|
9
9
|
} else await main(args);
|
package/docs/distribution.md
CHANGED
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
|
|
10
10
|
`0.19.0`は、`help`の全トピックを同じ構成に揃えて実装と照合し、Desktop Cloudで受付不明の記録が残ると以後の送信・割り当てが止まる問題、ローカル`send`の未知オプションの送信、`--supervisor`付きローカル`resource`の監督状態の未確認を修正します。利用者向けの失敗にはエラーコードを付けました。実行中のターンがない送信の`NOT_SENT`は`TASK_IDLE`・`TASK_BUSY`に変わるため、コードで分岐している呼び出し側は更新してください。runtime protocolとcapability契約はv1を維持し、Desktopの再起動は必要ありません。保存済み旧CLIで動く監督には反映されないため、更新後のCLIで監督を起動し直すか、プロンプトを生成し直してください。
|
|
11
11
|
|
|
12
|
+
`0.20.0`は、実際の監督・オーケストレーションの記録に合わせて生成プロンプトを直し、監督役が読む量と打ち込む量を減らします。保存済みCLI方式の実行コマンドは、`CODEX_HOME/codex-steer/bin/`に置く所有者専用の起動ファイル1語になります。起動ファイルを実行できない環境では生成時に`LAUNCHER_UNUSABLE`で止まるので、`--use-path-cli`を使ってください。`read`・`watch`・`status`のcursorは`c1`で始まる短い形式になり、旧形式の`eyJ`も引き続き読めます。0.19.0以前のCLIに`c1`のcursorを渡すと`STALE_CURSOR`になるため、`--since`なしで読み直してください。失敗した呼び出しは`error.help`・`error.action`・`error.usage`で対処を返し、`help <topic>`の既定の出力はエラー一覧を含みません(`help <topic> --errors`で表示し、`--json`は`errors`の代わりに`errors_command`を返します)。`findings`・`history`・`instructions list`の出力は`based_on`の代わりに`based_on_sha256`を返し、保存する記録は変わりません。これらのJSONの項目で分岐している呼び出し側は更新してください。生成済みのプロンプトは変わらないので、監督を続ける場合は更新後のCLIで生成し直してください。runtime protocolとcapability契約はv1を維持し、Desktopの再起動は不要です。
|
|
13
|
+
|
|
12
14
|
`package.json` は `private` を持たず、`publishConfig` でnpm公式レジストリへのpublic公開を指定しています。公開可能な設定であることと、実際に公開済みであることは別です。
|
|
13
15
|
|
|
14
16
|
公開後の基本的な実行形式は次のとおりです。通常はバージョン指定なしで使えます。監督開始後は保存したCLIを使い続けるため、監督中の一貫性を保つために版を明示する必要はありません。起動側と操作側の製品バージョンも、必要な通信仕様が対応していれば異なっていても使えます。
|
|
@@ -32,25 +34,25 @@ CLIはDesktopを自動終了しません。
|
|
|
32
34
|
|
|
33
35
|
## 監督役が使うCLI
|
|
34
36
|
|
|
35
|
-
既定は以下の保存済みCLI方式です。`supervise <THREAD> --use-path-cli`または`supervise prompt <THREAD> --use-path-cli`を指定すると、本文はPATH上の`codexteer`を使います。このモードではCLI
|
|
37
|
+
既定は以下の保存済みCLI方式です。`supervise <THREAD> --use-path-cli`または`supervise prompt <THREAD> --use-path-cli`を指定すると、本文はPATH上の`codexteer`を使います。このモードではCLIを保存せず起動ファイルも作らず、本文は現在実行中のCLIから生成します。Nodeのパス・版・CODEX_HOMEを埋め込まず、各コマンドは実行環境のPATHとCODEX_HOMEに従います。更新されたCLIは次の実行から使われます。対象Desktopと同じプロファイルで実行してください。--supervisor・--connectionと監督の登録・停止・送信制御は維持します。本文だけの生成はファイルを書き込まず、直接起動では現在のプロファイルを検証・準備して監督を登録します。JSONの`cli_mode`は`path`、`deployment`と`node`は`null`です。既定方式では`cli_mode`は`saved`です。
|
|
36
38
|
|
|
37
39
|
以下は`--use-path-cli`を指定しない場合の動作です。
|
|
38
40
|
|
|
39
|
-
`0.14.1`以降の`supervise`と`supervise prompt`は、開始時のCLI
|
|
41
|
+
`0.14.1`以降の`supervise`と`supervise prompt`は、開始時のCLI本体と依存を内容ハッシュ別の永続配置へコピーし、その保存先を使う実行コマンドを本文に埋め込みます。この版からは、実行コマンドを固定した起動ファイルを生成し、本文にはそのパスを1語で埋め込みます(後述の[起動ファイル](#起動ファイル))。npxで取得したパッケージもソースのチェックアウトも、同じ保存・検証・生成処理を使います。起動経路を推測する環境変数や切り替えオプションは不要です。本文の生成処理自体も保存したCLI一式から読み込みます。
|
|
40
42
|
|
|
41
43
|
両形式で対象IDの後ろに任意の`MESSAGE`を一つの引数として渡せます。省略時は保存したCLIの標準方針を使い、指定時は標準方針全体をその文に置き換えます。必須の共通テンプレートは保存したCLIから常に生成し、対象・実行コマンド・操作時の確認を保ちます。指定文は生成・起動ごとの入力で、永続配置のファイルやマニフェストへ書き込まず、内容ハッシュにも含めません。同じCLIなら異なる方針でも保存先を検証して再利用します。空文字・空白だけの文は保存処理前に`INVALID_SUPERVISION_POLICY`で拒否します。本文の文字列はテンプレートやシェルとして評価しません。
|
|
42
44
|
|
|
43
45
|
直接起動の`supervise`はClaudeを既定にし、`--agent claude`の明示と`--agent codex`にも対応します。監督方針は最初の`--`より前、エージェント側の起動引数はその後ろへ置いてください。
|
|
44
46
|
|
|
45
|
-
監督役の`doctor`・`read`・`watch`・`send
|
|
47
|
+
監督役の`doctor`・`read`・`watch`・`send`等は起動ファイル経由でこのコピーを使います。起動ファイル内のパスはシェル引数として引用し、空白・引用符・コマンド置換に見える文字も文字列として扱います。本文に埋め込むパスに改行や制御文字があれば、`SUPERVISION_PATH_UNSAFE`で拒否します。ヘルプの`codexteer`表記も、監督役には指定された実行コマンドに置き換えるよう指示します。
|
|
46
48
|
|
|
47
|
-
`supervise prompt`も読み取り専用ではなく、IDと引数の検証後にCLI一式の保存・再利用の検証を行ってから本文を出力します。保存・検証に失敗した場合は部分的な本文を出力せず、直接起動の場合もエージェントを起動しません。Desktopへの接続・設定変更・履歴取得・送信は行いません。`--json`には対象ID
|
|
49
|
+
`supervise prompt`も読み取り専用ではなく、IDと引数の検証後にCLI一式の保存・再利用の検証を行ってから本文を出力します。保存・検証に失敗した場合は部分的な本文を出力せず、直接起動の場合もエージェントを起動しません。Desktopへの接続・設定変更・履歴取得・送信は行いません。`--json`には対象IDと本文、実行コマンドの`data.command`に加えて`data.deployment`(元のホームを示す`codex_home`・保存先・版・ハッシュ・再利用の有無)、`data.node`(Nodeの実体パス・版)、`data.supervisor`(session_id・owner・connection)を返します。ヘルプの表示は保存処理を行いません。
|
|
48
50
|
|
|
49
|
-
本文は同じPC
|
|
51
|
+
本文は同じPC向けです。起動ファイルが`CODEX_HOME`を設定し、配置時に検証したホームの実体パスへ固定します。生成時に`CODEX_HOME`が未設定なら、既定の`~/.codex`の実体パスを使います。相対パスやシンボリックリンクも絶対パスに解決するため、貼り付け先の作業ディレクトリや`CODEX_HOME`が異なっても、生成元のruntimeと履歴を使います。別のプロファイルを監督する場合は、そこで本文を生成し直してください。
|
|
50
52
|
|
|
51
53
|
監督中は保存したコピーを保持してください。元のチェックアウトやnpxキャッシュを更新・移動・削除しても、そのコピーは変わりません。同じ製品バージョンでも内容が変われば別の保存先を作り、既存のコピーは検証して再利用します。参照先が使えない場合は介入を止めて理由を報告するよう指示し、別の版の自動取得やPATHへのフォールバックは行いません。
|
|
52
54
|
|
|
53
|
-
Node本体はコピーせず、開始時のNodeの実体への絶対パスと`--require-node-version <version
|
|
55
|
+
Node本体はコピーせず、開始時のNodeの実体への絶対パスと`--require-node-version <version>`を起動ファイルに埋め込みます。このオプションは全コマンドで使え、実行中のNodeバージョンが異なる場合は、操作や保存処理を始める前に`NODE_VERSION_MISMATCH`で拒否します。Nodeを削除した場合も実行できません。同じバージョンのNodeの改変や共有ライブラリまで固定・検証するものではないため、元のNodeは保持し、更新時は新しい環境から監督を開始し直してください。通常のCLI操作にNodeバージョンの一致は要求せず、生成した監督用コマンドでのみ自動指定します。
|
|
54
56
|
|
|
55
57
|
元のパスだけを固定しない理由は、npmキャッシュやチェックアウトの内容が更新されるためです。npm 11.6.2は要求したパッケージ指定からキャッシュ先を計算し、同じ指定の再実行で取得対象が変われば、その保存先でインストールを更新します。新版の公開だけで自動更新されるわけではありません。保存したCLIはこの更新の影響を受けません。[npm 11.6.2のキャッシュ解決・更新実装](https://github.com/npm/cli/blob/v11.6.2/workspaces/libnpmexec/lib/index.js)
|
|
56
58
|
|
|
@@ -101,6 +103,19 @@ Desktop起動時の`CODEX_CLI_PATH`はこの保存先のwrapperを指し、wrapp
|
|
|
101
103
|
これは、信頼する配布物を安全に配置・再利用するための検証です。各操作の実行時に全ファイルを再検証する仕組みや、配布元の真正性を独立した署名で証明する機能ではありません。
|
|
102
104
|
同じOSユーザー権限で任意のコードを実行できる相手や、root権限からの改変を隔離する仕組みでもありません。
|
|
103
105
|
|
|
106
|
+
### 起動ファイル
|
|
107
|
+
|
|
108
|
+
保存済みCLI方式の`supervise`・`supervise prompt`・`orchestrate`・`orchestrate prompt`は、次の起動ファイルを作り、そのパスを本文の実行コマンドにします。
|
|
109
|
+
|
|
110
|
+
```text
|
|
111
|
+
<canonical CODEX_HOME>/codex-steer/bin/codexteer-s-<hash> 監督ごと(--supervisorを含む)
|
|
112
|
+
<canonical CODEX_HOME>/codex-steer/bin/codexteer-p-<hash> オーケストレーションのプロジェクト用
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
起動ファイルは`/bin/sh`のスクリプトで、`CODEX_HOME`を設定し、開始時のNodeで保存したCLIを`--require-node-version`・`--supervisor`・`--connection`(リモートでは`--host`・`--remote-transport`・`--context-thread`も)付きで`exec`し、利用者の引数を後ろに渡します。以前の版の本文の実行コマンドと同じ引数でCLIを起動するため、旧形式のコマンドもそのまま使えます。固定済みのオプションを重ねて指定すると`OPTIONS_INVALID`で拒否します。
|
|
116
|
+
|
|
117
|
+
`<hash>`は内容のSHA-256の先頭12桁です。`bin`は本人所有の0700ディレクトリで、シンボリックリンクを辿りません。起動ファイルは一時ファイルから0700の通常ファイルとして名前を確定し、同じ名前があれば内容と権限を照合して再利用します。一致しなければ上書きせず`LAUNCHER_MODIFIED`で止まります。配置は`bin/.install-<名前>`のロックで排他し、中断したロックは自動で奪いません。生成時に一度`--version`で実行し、noexecのホームやsandboxの拒否で実行できなければ本文を出力せず`LAUNCHER_UNUSABLE`で止まります。その場合は実行できる環境で生成し直すか、`--use-path-cli`を使ってください。監督ごとの起動ファイルは自動削除しません。
|
|
118
|
+
|
|
104
119
|
## 互換性契約
|
|
105
120
|
|
|
106
121
|
runtimeには製品名・版、共通の通信仕様 `codex_steer_protocol`、機能ごとの対応版 `codex_steer_capabilities`、配置を識別する `distribution_sha256` を記録します。
|
package/docs/orchestration.md
CHANGED
|
@@ -14,7 +14,7 @@ codexteer orchestrate --project 'Example Project' '達成したい目標' --agen
|
|
|
14
14
|
|
|
15
15
|
目標は一つの引用した引数か`-`で渡します。`--`で始まる目標はstdinの`-`を使ってください。stdinの目標は起動前に読み取るため、その入力は対話CLIへ再送しません。通常の引数で目標を渡す場合はstdinもそのまま対話CLIへ引き継ぎます。
|
|
16
16
|
|
|
17
|
-
`--use-path-cli`は本文内のcodexteerコマンドをPATH方式にし、保存コピーを作りません。省略時は保存済みCLI・Node版・canonical `CODEX_HOME
|
|
17
|
+
`--use-path-cli`は本文内のcodexteerコマンドをPATH方式にし、保存コピーを作りません。省略時は保存済みCLI・Node版・canonical `CODEX_HOME`・接続指定を固定した起動ファイル(`CODEX_HOME/codex-steer/bin/codexteer-p-<hash>`)のパスを、本文の実行コマンドにします。起動するエージェント自体は、どちらの方式でもPATHから選びます。PATH方式の直接起動でも`CODEX_HOME`の所有者と権限を検証し、必要ならディレクトリを作成します。入力不正や保存コピーの改変、unsafe profileではエージェントを起動しません。
|
|
18
18
|
|
|
19
19
|
起動側はDesktopへ接続せず、本文を受け取ったオーケストレーターがプロジェクト照合・作成・監視を開始します。プロジェクト用の単一スレッド監督IDは作りません。各子の監督登録と制御は本文の手順に従います。
|
|
20
20
|
|
|
@@ -86,13 +86,13 @@ Felix Riesebergの[How to be more ambitious](https://felixrieseberg.com/how-to-b
|
|
|
86
86
|
5. 個別の監督ID、読了cursor、findings、配送照合を使って介入する。必要な継続は同じ委任の未完了作業に限る。
|
|
87
87
|
6. 最終差分と検証・成果物を検収し、統合と統合後の確認を担当へ依頼して全体の目的達成まで追う。
|
|
88
88
|
|
|
89
|
-
作成用コマンドは特定スレッドの `--supervisor`
|
|
89
|
+
作成用コマンドは特定スレッドの `--supervisor` を持ちません。子の観測・送信は、子ごとに生成した監督用の起動ファイル(`supervise prompt --json`の`data.command`)を使います。既定の保存済みCLI方式とPATH方式を子の生成にも引き継ぎます。既存監督IDからの `orchestrate prompt` と、観測専用の `--connection desktop` は拒否します。
|
|
90
90
|
|
|
91
|
-
|
|
91
|
+
担当ごとの生成方針には、目的の継続(idleの担当への`--new-turn`による再開の許可)、監視の終了条件(ユーザーの停止指示か全体の完了)、Codexの独立した判断、三つの観点を含めます。共通手順は方針による再開の許可と終了条件を受け付けますが、単一スレッド監督の標準方針はどちらも定めないため、その挙動は変わりません。
|
|
92
92
|
|
|
93
93
|
## 制御と確認範囲
|
|
94
94
|
|
|
95
|
-
`supervise pause/stop`は個別スレッドの監督制御です。プロジェクト全体の一括pause/stopや常駐スケジューラーは追加していません。オーケストレーターへの監督停止指示は、新規作成・追加送信・自分のMonitor/watch
|
|
95
|
+
`supervise pause/stop`は個別スレッドの監督制御です。プロジェクト全体の一括pause/stopや常駐スケジューラーは追加していません。オーケストレーターへの監督停止指示は、新規作成・追加送信・自分のMonitor/watchを止め、各担当の監督を`supervise stop`で終了する指示として扱い、実行中のCodex担当の作業自体を止める指示とは区別します。全体の完了時も各担当の監督を終了します。
|
|
96
96
|
|
|
97
97
|
`resource`は参加者間の協調用リースで、OSの強制ロックや公平な待ち行列ではありません。利用順はオーケストレーターが調整します。監督登録がactiveでも、継続して監視できていることを証明しません。
|
|
98
98
|
|
package/package.json
CHANGED
package/src/cli.mjs
CHANGED
|
@@ -6,7 +6,7 @@ import { listLocalThreads } from "./thread-store.mjs";
|
|
|
6
6
|
import { sendTrackedMessage, listMessages, getMessage, messageSummary, reconcileMessages, markMessage, listInstructions } from "./journal.mjs";
|
|
7
7
|
import { launchDesktopUpdate, desktopUpdateStatus } from "./update.mjs";
|
|
8
8
|
import { appServerDoctor, startDesktop } from "./launcher.mjs";
|
|
9
|
-
import { VERSION, helpData, renderHelp } from "./help.mjs";
|
|
9
|
+
import { VERSION, helpData, renderHelp, renderErrors, errorRemedy, topicFor } from "./help.mjs";
|
|
10
10
|
import { observeThread, printObservation } from "./observe.mjs";
|
|
11
11
|
import { monitorCommand } from "./monitor.mjs";
|
|
12
12
|
import { notificationOptions } from "./notify.mjs";
|
|
@@ -15,6 +15,8 @@ import { acquireResource, resourceStatus, renewResource, releaseResource, listRe
|
|
|
15
15
|
import { playSendSound } from "./sound.mjs";
|
|
16
16
|
import { prepareSupervisorPrompt, superviseAgent } from "./supervise.mjs";
|
|
17
17
|
import { prepareOrchestrationPrompt, orchestrateAgent } from "./orchestrate.mjs";
|
|
18
|
+
import { rejectRepeatedBinding } from "./prompt-command.mjs";
|
|
19
|
+
import { rejectUnknownOptions } from "./unknown-options.mjs";
|
|
18
20
|
import { supervisorId, registerSupervisor, getSupervisor, assertSupervisor, assertSupervisorRegistration, controlSupervisor, supervisorStatus, listSupervisors } from "./supervision.mjs";
|
|
19
21
|
import { createFinding, findingStatus, listFindings, resolveFinding, dismissFinding, reopenFinding, evaluateFinding, findingStats } from "./findings.mjs";
|
|
20
22
|
import { connectionMode, observationConnection, desktopReadOnly } from "./connection.mjs";
|
|
@@ -34,10 +36,11 @@ function success(command, data, json) {
|
|
|
34
36
|
return data;
|
|
35
37
|
}
|
|
36
38
|
|
|
37
|
-
export function fail(error, json) {
|
|
39
|
+
export function fail(error, json, argv = []) {
|
|
38
40
|
const message = error instanceof Error ? error.message : String(error);
|
|
41
|
+
const remedy = errorRemedy(argv, error.code);
|
|
39
42
|
if (json) console.log(JSON.stringify({ ok: false, ...(error.watch ? { command: "watch", data: error.watch } : {}), error: {
|
|
40
|
-
message, code: error.code, ...hostFields(), delivery_status: error.delivery_status,
|
|
43
|
+
message, code: error.code, ...remedy, ...hostFields(), delivery_status: error.delivery_status,
|
|
41
44
|
operation: error.operation, capability: error.capability,
|
|
42
45
|
expected_connection: error.expected_connection, connection: error.connection,
|
|
43
46
|
...((error.execution_environment === "cloud" || (typeof error.code === "string" && error.code.startsWith("CLOUD_"))) ? {
|
|
@@ -48,7 +51,7 @@ export function fail(error, json) {
|
|
|
48
51
|
} : {}),
|
|
49
52
|
sent: error.sent, thread_id: error.thread_id, rpc_code: error.rpc_code ?? error.rpcCode,
|
|
50
53
|
message_id: error.message_id, client_message_id: error.client_message_id, journal_update_required: error.journal_update_required,
|
|
51
|
-
existing_message_id: error.existing_message_id,
|
|
54
|
+
existing_message_id: error.existing_message_id, unknown_options: error.unknown_options,
|
|
52
55
|
existing_attempt_id: error.existing_attempt_id, existing_receipt_path: error.existing_receipt_path,
|
|
53
56
|
supervision_update_required: error.supervision_update_required,
|
|
54
57
|
history_changed: error.history_changed, backup_path: error.backup_path, receipt_path: error.receipt_path,
|
|
@@ -63,6 +66,8 @@ export function fail(error, json) {
|
|
|
63
66
|
} }));
|
|
64
67
|
else {
|
|
65
68
|
console.error(`codexteer: ${message}`);
|
|
69
|
+
for (const line of remedy?.usage ?? []) console.error(`使い方: codexteer ${line}`);
|
|
70
|
+
if (remedy?.action) console.error(`対処: ${remedy.action}`);
|
|
66
71
|
if (error.execution_environment === "cloud" || (typeof error.code === "string" && error.code.startsWith("DESKTOP_CLOUD_"))) {
|
|
67
72
|
// Recovery metadata must survive an uncertain submission or a stale
|
|
68
73
|
// on-disk receipt. Never print the child error, prompt, or diagnostics.
|
|
@@ -162,9 +167,9 @@ function printSupervisor(data) {
|
|
|
162
167
|
export async function main(argv) {
|
|
163
168
|
const args = [...argv];
|
|
164
169
|
try {
|
|
170
|
+
rejectRepeatedBinding(args);
|
|
165
171
|
const transport = validateRemoteTransport(takeOption(args, "--remote-transport", "native"));
|
|
166
172
|
const explicitHost = takeOption(args, "--host", undefined);
|
|
167
|
-
if (args.slice(0, args.includes("--") ? args.indexOf("--") : args.length).includes("--host")) throw usage("Specify --host only once.");
|
|
168
173
|
if (explicitHost !== undefined) validateHostId(explicitHost);
|
|
169
174
|
const probe = [...args];
|
|
170
175
|
takeFlag(probe, "--json");
|
|
@@ -185,7 +190,7 @@ export async function main(argv) {
|
|
|
185
190
|
const ownArguments = probe.slice(0, probe.includes("--") ? probe.indexOf("--") : probe.length);
|
|
186
191
|
if (isControlTransport(transport) && host === "local" && command !== "remote" && !["help", "--help", "--version"].some(value => ownArguments.includes(value))) throw Object.assign(new Error("--remote-transport control requires a remote hostId link or --host."), { code: "REMOTE_HOST_REQUIRED" });
|
|
187
192
|
return await withTarget(host, contextThread, () => mainOnTarget(args), { transport });
|
|
188
|
-
} catch (error) { fail(error, argv.includes("--json")); }
|
|
193
|
+
} catch (error) { fail(error, argv.includes("--json"), argv); }
|
|
189
194
|
}
|
|
190
195
|
|
|
191
196
|
async function mainOnTarget(argv) {
|
|
@@ -209,12 +214,10 @@ async function mainOnTarget(argv) {
|
|
|
209
214
|
}
|
|
210
215
|
if (args.length === 0 || takeFlag(args, "--help") || args[0] === "help") {
|
|
211
216
|
if (args[0] === "help") args.shift();
|
|
212
|
-
const
|
|
213
|
-
const
|
|
214
|
-
: /^(codex:\/\/|[0-9a-f]{8}-)/i.test(candidate) ? "send" : candidate;
|
|
215
|
-
const data = helpData(topic);
|
|
217
|
+
const errors = takeFlag(args, "--errors");
|
|
218
|
+
const data = helpData(topicFor(args) ?? args[0] ?? "overview", { errors });
|
|
216
219
|
success("help", data, json);
|
|
217
|
-
if (!json) console.log(renderHelp(data));
|
|
220
|
+
if (!json) console.log(errors ? renderErrors(data) : renderHelp(data));
|
|
218
221
|
return;
|
|
219
222
|
}
|
|
220
223
|
|
|
@@ -304,7 +307,7 @@ async function mainOnTarget(argv) {
|
|
|
304
307
|
const agent = takeOption(ownArgs, "--agent", promptOnly ? undefined : "claude");
|
|
305
308
|
const usePathCli = takeFlag(ownArgs, "--use-path-cli");
|
|
306
309
|
if (promptOnly && ownArgs[0] === "--") ownArgs.shift();
|
|
307
|
-
else
|
|
310
|
+
else rejectUnknownOptions(ownArgs, "orchestrate", "See help orchestrate; agent arguments belong after --.", usage);
|
|
308
311
|
if (ownArgs.length !== 1) throw usage("Expected: orchestrate [prompt] --project <ID-or-exact-name> <GOAL>. Quote the goal as one argument, or use - for stdin.");
|
|
309
312
|
const goal = ownArgs[0] === "-" ? readFileSync(0, "utf8") : ownArgs[0];
|
|
310
313
|
if (promptOnly) {
|
|
@@ -579,7 +582,7 @@ async function mainOnTarget(argv) {
|
|
|
579
582
|
options.timeoutMs = Number(options.timeoutMs);
|
|
580
583
|
}
|
|
581
584
|
const literal = args.indexOf("--");
|
|
582
|
-
|
|
585
|
+
rejectUnknownOptions(args.slice(0, literal < 0 ? args.length : literal), "thread create", "Put an instruction that starts with -- after --.", usage);
|
|
583
586
|
const message = readMessage(args);
|
|
584
587
|
const data = await (targetHost() === "local" ? createProjectThread : createRemoteProjectThread)(selector, message, options);
|
|
585
588
|
success("thread.create", data, json);
|
|
@@ -647,7 +650,7 @@ async function mainOnTarget(argv) {
|
|
|
647
650
|
const waitInput = takeOption(args, "--wait-ms", undefined);
|
|
648
651
|
if (backend !== "ui" && (keepFocus || waitInput != null)) throw usage("--keep-focus and --wait-ms require --backend ui.");
|
|
649
652
|
const waitMs = Number(waitInput ?? "1500");
|
|
650
|
-
|
|
653
|
+
rejectUnknownOptions(args.slice(0, args.includes("--") ? args.indexOf("--") : args.length), "send", "Put instruction text that starts with -- after --.", usage);
|
|
651
654
|
const threadInput = args.shift();
|
|
652
655
|
if (!threadInput) throw usage("send requires a thread ID or codex://threads URL.");
|
|
653
656
|
const message = readMessage(args);
|
|
@@ -668,6 +671,6 @@ async function mainOnTarget(argv) {
|
|
|
668
671
|
if (!noSound && !dryRun && data.sent === true && !data.sound.played) console.error(`codexteer: Input was accepted, but the sound could not be played (${data.sound.reason}).`);
|
|
669
672
|
}
|
|
670
673
|
} catch (error) {
|
|
671
|
-
fail(error, json);
|
|
674
|
+
fail(error, json, argv);
|
|
672
675
|
}
|
|
673
676
|
}
|
package/src/cloud-cli.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import { listProjects as listDesktopProjects } from "./projects.mjs";
|
|
|
3
3
|
import { isDesktopCloudTask, desktopCloudId, desktopCloudLink } from "./desktop-cloud-id.mjs";
|
|
4
4
|
import { desktopCloudConnection, desktopCloudEnvironments } from "./desktop-cloud-api.mjs";
|
|
5
5
|
import { createDesktopCloudTask, listDesktopCloudTasks, desktopCloudReceipt } from "./desktop-cloud.mjs";
|
|
6
|
-
import { isCloudTask } from "./task-id.mjs";
|
|
6
|
+
import { isCloudTask, selectedCloudInvocation } from "./task-id.mjs";
|
|
7
7
|
import { cloudTaskId } from "./cloud-id.mjs";
|
|
8
8
|
import { normalizeThreadId } from "./thread-id.mjs";
|
|
9
9
|
import { connectionMismatch } from "./connection-error.mjs";
|
|
@@ -12,6 +12,8 @@ import { observeThread, printObservation } from "./observe.mjs";
|
|
|
12
12
|
import { monitorCommand } from "./monitor.mjs";
|
|
13
13
|
import { notificationOptions } from "./notify.mjs";
|
|
14
14
|
import { prepareSupervisorPrompt, superviseAgent } from "./supervise.mjs";
|
|
15
|
+
import { rejectRepeatedBinding } from "./prompt-command.mjs";
|
|
16
|
+
import { rejectUnknownOptions } from "./unknown-options.mjs";
|
|
15
17
|
import { supervisorId, registerSupervisor, getSupervisor, assertSupervisor, assertSupervisorRegistration, controlSupervisor, supervisorStatus, listSupervisors } from "./supervision.mjs";
|
|
16
18
|
import { createFinding, findingStatus, listFindings, resolveFinding, dismissFinding, reopenFinding, evaluateFinding, findingStats } from "./findings.mjs";
|
|
17
19
|
import { sendTrackedMessage, listMessages, getMessage, messageSummary, reconcileMessages, markMessage, resolveUnknownDelivery, listInstructions } from "./journal.mjs";
|
|
@@ -26,7 +28,6 @@ import { createCheckpoint, listCheckpoints, getCheckpoint, checkpointSummary, ve
|
|
|
26
28
|
import { acquireResource, resourceStatus, renewResource, releaseResource, listResources, runWithResource } from "./resource.mjs";
|
|
27
29
|
|
|
28
30
|
const failure = (message, code = "CLOUD_OPTIONS_INVALID") => Object.assign(new Error(message), { code, execution_environment: "cloud" });
|
|
29
|
-
const values = new Set("--environment --connection --supervisor --require-node-version --host --remote-transport --context-thread --thread --backend --source --kind --evidence --based-on --finding --expires-at --supersedes --checkpoint --limit --max-chars --since --poll-ms --timeout-ms --until --notify --settle-ms --max-hold-ms --owner --key --condition --note --rating --reason --root --path --exclude --command --cwd --artifact --status --by --token --ttl-ms --agent --project --env --branch --title --model --thinking --cursor --attempt".split(" "));
|
|
30
31
|
function option(args, name, fallback) {
|
|
31
32
|
const index = args.indexOf(name), stop = args.indexOf("--");
|
|
32
33
|
if (index < 0 || (stop >= 0 && index > stop)) return fallback;
|
|
@@ -42,31 +43,12 @@ const repeated = (args, name) => { const result = []; let value; while ((value =
|
|
|
42
43
|
const message = args => { if (args[0] === "--") args.shift(); return args.length === 1 && args[0] === "-" ? readFileSync(0, "utf8") : args.join(" "); };
|
|
43
44
|
function exact(args, count) { if (args.length !== count || args.some(arg => arg.startsWith("--"))) throw failure("Unexpected arguments. See the command's help."); }
|
|
44
45
|
|
|
45
|
-
function selectedCloudInvocation(argv) {
|
|
46
|
-
const end = argv.indexOf("--"), own = end < 0 ? argv : argv.slice(0, end);
|
|
47
|
-
const connection = own.indexOf("--connection");
|
|
48
|
-
const positional = [];
|
|
49
|
-
for (let i = 0; i < own.length; i++) {
|
|
50
|
-
if (values.has(own[i])) { i++; continue; }
|
|
51
|
-
if (!own[i].startsWith("--")) positional.push(own[i]);
|
|
52
|
-
}
|
|
53
|
-
const [command, action] = positional;
|
|
54
|
-
if (["help", "--help", "--version"].includes(command) || own.includes("--help") || own.includes("--version")) return false;
|
|
55
|
-
if (connection >= 0 && ["cloud", "desktop-cloud"].includes(own[connection + 1])) return own[connection + 1];
|
|
56
|
-
const thread = own.indexOf("--thread");
|
|
57
|
-
if (["doctor", "resource"].includes(command) && thread >= 0) return isDesktopCloudTask(own[thread + 1]) ? "desktop-cloud" : isCloudTask(own[thread + 1]) ? "cloud" : false;
|
|
58
|
-
if (command === "thread" && action === "create") return false;
|
|
59
|
-
const nested = ["history", "instructions", "findings", "checkpoint", "thread"].includes(command)
|
|
60
|
-
|| (command === "supervise" && ["prompt", "register", "status", "pause", "resume", "stop", "list"].includes(action));
|
|
61
|
-
const target = isCloudTask(command) || isDesktopCloudTask(command) ? command : positional[nested ? 2 : 1];
|
|
62
|
-
return isDesktopCloudTask(target) ? "desktop-cloud" : isCloudTask(target) ? "cloud" : false;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
46
|
export const cloudInvocation = argv => !!selectedCloudInvocation(argv);
|
|
66
47
|
|
|
67
48
|
// Only parsing/routing is backend-specific. Supervision, monitoring, directives,
|
|
68
49
|
// findings, journaling and saved-agent launch use the same local implementation.
|
|
69
50
|
export async function mainCloud(argv) {
|
|
51
|
+
rejectRepeatedBinding(argv);
|
|
70
52
|
const args = [...argv], json = flag(args, "--json"), connection = option(args, "--connection", selectedCloudInvocation(argv) || "cloud");
|
|
71
53
|
const desktopCloud = connection === "desktop-cloud";
|
|
72
54
|
const targetId = desktopCloud ? desktopCloudId : value => {
|
|
@@ -238,7 +220,7 @@ export async function mainCloud(argv) {
|
|
|
238
220
|
args.shift(); if (supervisor) throw failure("A bound supervisor cannot create another task.", "SUPERVISOR_CONTROL_FORBIDDEN");
|
|
239
221
|
const project = option(args, "--project"), requestedBranch = option(args, "--branch"), dryRun = flag(args, "--dry-run");
|
|
240
222
|
if (project === undefined) throw failure("Cloud creation requires --project with an environment ID or exact name.");
|
|
241
|
-
const end = args.includes("--") ? args.indexOf("--") : args.length;
|
|
223
|
+
const end = args.includes("--") ? args.indexOf("--") : args.length; rejectUnknownOptions(args.slice(0, end), "cloud creation", "Explicit model/title/permission overrides are not implemented yet.", failure);
|
|
242
224
|
const body = message(args); if (!body.trim()) throw failure("A non-empty initial instruction is required.");
|
|
243
225
|
const rows = (await cloudEnvironments()).environments, selector = project, matches = rows.filter(e => e.id === selector || e.name === selector);
|
|
244
226
|
if (matches.length !== 1) throw failure("The cloud environment selector must match one accessible ID or exact name.");
|
|
@@ -284,7 +266,7 @@ export async function mainCloud(argv) {
|
|
|
284
266
|
const options = { dryRun, newTurn, supervisor, connection, evidence: repeated(args, "--evidence") };
|
|
285
267
|
for (const [key, name] of Object.entries({ source: "--source", kind: "--kind", basedOn: "--based-on", supersedes: "--supersedes", expiresAt: "--expires-at", checkpoint: "--checkpoint", finding: "--finding" })) { const value = option(args, name); if (value !== undefined) options[key] = value; }
|
|
286
268
|
const id = targetId(args.shift()), end = args.includes("--") ? args.indexOf("--") : args.length;
|
|
287
|
-
|
|
269
|
+
rejectUnknownOptions(args.slice(0, end), "send", "Put instruction text that starts with -- after --.", failure);
|
|
288
270
|
const body = message(args); if (!body.trim()) throw failure("send requires a non-empty message.");
|
|
289
271
|
const receipt = await sendTrackedMessage(id, body, options);
|
|
290
272
|
receipt.sound = noSound ? { played: false, reason: "disabled" } : playSendSound(receipt);
|
|
@@ -309,7 +291,7 @@ async function desktopCloudCommands(command, args, { supervisor, output, bound,
|
|
|
309
291
|
if (action === "create") {
|
|
310
292
|
const environment = option(args, "--environment"), project = option(args, "--project"), title = option(args, "--title"), dryRun = flag(args, "--dry-run");
|
|
311
293
|
const end = args.includes("--") ? args.indexOf("--") : args.length;
|
|
312
|
-
|
|
294
|
+
rejectUnknownOptions(args.slice(0, end), "Desktop Cloud creation", "Put an instruction that starts with -- after --.", failure);
|
|
313
295
|
output("thread.create", await createDesktopCloudTask(environment, message(args), { project, title, dryRun })); return true;
|
|
314
296
|
}
|
|
315
297
|
if (action === "assign") { const project = option(args, "--project"); exact(args, 1); const data = await assignDesktopCloudProject(await bound(args[0]), project); output("thread.assign", data); if (data.verification_status !== "verified") process.exitCode = 1; return true; }
|