omnilane 0.14.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/.claude-plugin/marketplace.json +27 -0
- package/.claude-plugin/plugin.json +9 -0
- package/CHANGELOG.md +71 -1
- package/README.ja.md +50 -0
- package/README.ko.md +48 -0
- package/README.md +65 -0
- package/README.zh-CN.md +45 -0
- package/README.zh-TW.md +45 -0
- package/VERSION +1 -1
- package/hooks/hooks.json +33 -0
- package/hooks/record-foreman-session.sh +57 -0
- package/hooks/report-completions.sh +134 -0
- package/hooks/routing-instruction.md +18 -0
- package/package.json +6 -2
- package/plugin.json +6 -0
- package/scripts/dispatch.sh +57 -2
- package/scripts/doctor.sh +126 -0
- package/scripts/jobs.sh +149 -8
- package/scripts/lib/common.sh +107 -0
- package/scripts/lib/i18n.sh +8 -0
- package/scripts/lib/job-worker.sh +173 -4
- package/scripts/runners/run-claude.sh +106 -0
- package/scripts/runners/run-codex.sh +22 -5
- package/skills/omnilane/SKILL.md +172 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "omnilane",
|
|
3
|
+
"owner": {
|
|
4
|
+
"name": "Vincent Wang",
|
|
5
|
+
"url": "https://github.com/Seraphim0916/omnilane"
|
|
6
|
+
},
|
|
7
|
+
"metadata": {
|
|
8
|
+
"description": "One routing table, cross-vendor dispatch, foreman completion inbox.",
|
|
9
|
+
"version": "0.20.0"
|
|
10
|
+
},
|
|
11
|
+
"plugins": [
|
|
12
|
+
{
|
|
13
|
+
"name": "omnilane",
|
|
14
|
+
"source": "./",
|
|
15
|
+
"description": "Route each subtask to the model that fits, dispatch it to any vendor CLI, and have finished dispatches report back into the foreman's next prompt.",
|
|
16
|
+
"version": "0.20.0",
|
|
17
|
+
"category": "development",
|
|
18
|
+
"keywords": [
|
|
19
|
+
"routing",
|
|
20
|
+
"dispatch",
|
|
21
|
+
"multi-model",
|
|
22
|
+
"codex",
|
|
23
|
+
"orchestration"
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "omnilane",
|
|
3
|
+
"version": "0.20.0",
|
|
4
|
+
"description": "One routing table, every harness: classify subtasks into lanes and auto-dispatch each lane to the best vendor CLI (Codex, Claude Code, Grok Build, Antigravity) with background jobs, depth guard, and serialized codex dispatch.",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Seraphim0916"
|
|
7
|
+
},
|
|
8
|
+
"skills": "./skills/"
|
|
9
|
+
}
|
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,72 @@ semantic version tags.
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.20.0] - 2026-08-30
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- `docs/roadmap.md` plans threaded dispatch (continue a job instead of
|
|
14
|
+
restarting it) and a live mailbox (message a job while it runs), with a
|
|
15
|
+
per-vendor session capability matrix. `docs/experiments/live-inbox-probe.sh`
|
|
16
|
+
is the probe backing the mailbox claim.
|
|
17
|
+
|
|
18
|
+
- Finished dispatches now report themselves to the foreman. Each completed job
|
|
19
|
+
writes a private record under `$OMNILANE_HOME/inbox/`, and the bundled Claude
|
|
20
|
+
Code `UserPromptSubmit` hook delivers matching records into the foreman's next
|
|
21
|
+
prompt, so a background dispatch no longer has to be polled. Records are
|
|
22
|
+
scoped by the dispatch `workdir` and, when available, its foreman session,
|
|
23
|
+
claimed at most once, and moved to `inbox/consumed/`. Worker-output tails are
|
|
24
|
+
framed as indented data and stripped of control characters and Unicode
|
|
25
|
+
`U+2028`/`U+2029` separators, so they cannot forge a header or issue
|
|
26
|
+
instructions. Set `OMNILANE_INBOX=0` to disable record creation.
|
|
27
|
+
- `.claude-plugin/marketplace.json` makes the repository installable as a Claude
|
|
28
|
+
Code plugin, which is the install path the completion notice needs:
|
|
29
|
+
`claude plugin marketplace add <repo>` then `claude plugin install
|
|
30
|
+
omnilane@omnilane`.
|
|
31
|
+
- The published package now ships `hooks/`, `skills/` and `.claude-plugin/`, so
|
|
32
|
+
an npm install carries the hook script instead of only the CLI.
|
|
33
|
+
- `install.sh` reports whether the completion notice is active and, when it is
|
|
34
|
+
not, prints the exact commands that enable it; the skill symlink alone does
|
|
35
|
+
not deliver notices.
|
|
36
|
+
- `doctor` answers whether the completion notice is live, reading the
|
|
37
|
+
`hooks/hooks.json` of the current checkout rather than the state recorded at
|
|
38
|
+
install time — checking out a branch without the hook silently disables the
|
|
39
|
+
notice while the plugin still reports itself as enabled.
|
|
40
|
+
- Claude background dispatches can now stay resident as a live mailbox. A live
|
|
41
|
+
job accepts `jobs.sh send`, `watch`, `tail`, `close`, and `retry`, and records
|
|
42
|
+
lifecycle events in `events.jsonl`. Other vendors explicitly fall back to
|
|
43
|
+
single-shot mode with a `stderr` and `mode-notice.txt` notice; `jobs.sh wait`
|
|
44
|
+
now prints `done exit=N` when the job finishes.
|
|
45
|
+
- Foreman completion records are now bound to the Claude session that launched
|
|
46
|
+
the dispatch. The `SessionStart` hook records the `session_id` against the
|
|
47
|
+
parent PID and its start time, making PID reuse safe; dispatch finds that
|
|
48
|
+
identity by walking its ancestors and stamps `foreman_session` into
|
|
49
|
+
`meta.json` and completion records. The inbox consumes a session match first
|
|
50
|
+
and falls back to `workdir` for legacy records, preventing two foremen in one
|
|
51
|
+
repository from taking each other's notices.
|
|
52
|
+
|
|
53
|
+
## [0.15.0] - 2026-08-28
|
|
54
|
+
|
|
55
|
+
### Added
|
|
56
|
+
|
|
57
|
+
- Timed-out Codex jobs now print the absolute path to the matching
|
|
58
|
+
`rollout-*.jsonl` session file, resolved from the first progress event's
|
|
59
|
+
`thread_id`, so an interrupted conversation remains directly inspectable.
|
|
60
|
+
|
|
61
|
+
### Changed
|
|
62
|
+
|
|
63
|
+
- Codex runner now invokes `codex exec --json`, streaming JSONL events to
|
|
64
|
+
`out.txt.progress.log` before the run exits or times out. `out.txt` and the
|
|
65
|
+
Jobs display, which reads only `out.txt` and `stderr.log`, remain unchanged.
|
|
66
|
+
|
|
67
|
+
### Fixed
|
|
68
|
+
|
|
69
|
+
- Timeout diagnostics no longer blame a usage-limit retry loop without evidence.
|
|
70
|
+
They now state that a timeout does not identify its cause, provide a
|
|
71
|
+
three-step check, and clarify that an empty progress log does not prove the
|
|
72
|
+
run made no progress.
|
|
73
|
+
|
|
74
|
+
|
|
9
75
|
## [0.14.0] - 2026-08-10
|
|
10
76
|
|
|
11
77
|
### Added
|
|
@@ -594,7 +660,11 @@ work to the wrong model, and records the evidence behind the shipped defaults.
|
|
|
594
660
|
- Initial shared routing table, cross-vendor dispatcher, runners, installer,
|
|
595
661
|
and baseline lint fixes.
|
|
596
662
|
|
|
597
|
-
[Unreleased]: https://github.com/Seraphim0916/omnilane/compare/v0.
|
|
663
|
+
[Unreleased]: https://github.com/Seraphim0916/omnilane/compare/v0.20.0...HEAD
|
|
664
|
+
|
|
665
|
+
[0.20.0]: https://github.com/Seraphim0916/omnilane/compare/v0.15.0...v0.20.0
|
|
666
|
+
|
|
667
|
+
[0.15.0]: https://github.com/Seraphim0916/omnilane/compare/v0.14.0...v0.15.0
|
|
598
668
|
|
|
599
669
|
[0.14.0]: https://github.com/Seraphim0916/omnilane/compare/v0.13.0...v0.14.0
|
|
600
670
|
[0.13.0]: https://github.com/Seraphim0916/omnilane/compare/v0.12.0...v0.13.0
|
package/README.ja.md
CHANGED
|
@@ -364,6 +364,24 @@ configure.sh set|get|unset|list|diff LANE [SPEC] # routing.local.yaml を非
|
|
|
364
364
|
記録し、`jobs.sh status` が `dead` を報告。
|
|
365
365
|
- **ペイロード上限** — 巨大なタスクテキストは自動で頭尾トランケート。
|
|
366
366
|
|
|
367
|
+
## 📬 ライブメールボックス
|
|
368
|
+
|
|
369
|
+
ライブメールボックスは、1 回で完結するディスパッチとは別の、Claude 専用の常駐バックグラウンド実行です。フォアマンが `--background` で開始し、実行中にも追加の指示を送れます。終わったらフォアマンが `jobs.sh close ID` で閉じます。放置しても常駐し続けるわけではなく、設定済みのジョブ全体タイムアウト(`--job-timeout`)に達すれば終了します。
|
|
370
|
+
|
|
371
|
+
```bash
|
|
372
|
+
scripts/dispatch.sh --background --vendor claude hard-judgment "タイムアウトしたテストを確認する"
|
|
373
|
+
# dispatch が表示したジョブ ID を $ID として保存
|
|
374
|
+
scripts/jobs.sh send "$ID" "リトライ経路も確認してください。"
|
|
375
|
+
scripts/jobs.sh watch "$ID"
|
|
376
|
+
scripts/jobs.sh tail "$ID" --lines 20
|
|
377
|
+
scripts/jobs.sh close "$ID"
|
|
378
|
+
scripts/jobs.sh retry "$ID" --background
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
`watch` は `$JOB_DIR/events.jsonl` を追跡し、`tail` は公開出力の `out.txt` を読みます。ライブメールボックスを使えるのは現時点で Claude だけです。ほかのベンダーは通常の単発ディスパッチへフォールバックしますが、無通知ではありません。stderr と `$JOB_DIR/mode-notice.txt` に通知が残り、`jobs.sh status ID` にも表示されます。
|
|
382
|
+
|
|
383
|
+
アイドル中は API 呼び出しも料金も発生しませんが、ジョブ全体タイムアウトの時間は進みます。やり取りが終わったら `close` してください。終了済み、またはライブでないジョブへの `jobs.sh send` は明確なエラーで失敗します。送った後に追跡しない作業、ライブ対応していないベンダー、クリーンな状態からの再実行が必要な場合には使わず、新しいディスパッチ(または完了後の `retry`)を使ってください。
|
|
384
|
+
|
|
367
385
|
## ❓ FAQ
|
|
368
386
|
|
|
369
387
|
<details>
|
|
@@ -516,6 +534,38 @@ scripts/dispatch.sh --dry-run hardest-coding "…" # 解決済みプラン、
|
|
|
516
534
|
|
|
517
535
|
## 📜 リリース履歴
|
|
518
536
|
|
|
537
|
+
## v0.20.0 の新機能
|
|
538
|
+
|
|
539
|
+
- **フォアマン完了インボックス。** バックグラウンド dispatch の完了時に非公開の
|
|
540
|
+
完了レコードを書き込み、同梱の Claude Code プラグインが一致するレコードを
|
|
541
|
+
フォアマンの次のプロンプトへ届けます。出力末尾はプロンプト注入対策済みで、
|
|
542
|
+
制御文字と `U+2028`/`U+2029` を除去し、ワーカー出力をインデントしたデータ
|
|
543
|
+
として枠付けます。
|
|
544
|
+
- **インストール可能な Claude Code プラグイン。**
|
|
545
|
+
`.claude-plugin/marketplace.json` は自己参照 source を使い、公開 npm tarball
|
|
546
|
+
には `hooks/`、`skills/`、`.claude-plugin/` も含まれます。
|
|
547
|
+
- **Claude のライブメールボックス。** 常駐バックグラウンド Claude ジョブは
|
|
548
|
+
実行中にメッセージを受け取り、`events.jsonl` を記録します。操作は
|
|
549
|
+
[📬 ライブメールボックス](#-ライブメールボックス) を参照してください。
|
|
550
|
+
他ベンダーは `stderr` と `mode-notice.txt` の通知付きで明示的に単発実行へ
|
|
551
|
+
フォールバックし、`jobs.sh wait` は `done exit=N` で完了します。
|
|
552
|
+
- **フォアマンのセッション識別。** `SessionStart` hook は Claude `session_id` を
|
|
553
|
+
PID と開始時刻へ結び付け、PID 再利用にも安全です。dispatch は親プロセスを
|
|
554
|
+
たどって `foreman_session` を `meta.json` と完了レコードへ記録します。
|
|
555
|
+
インボックスはセッション一致を優先し、旧レコードでは `workdir` に
|
|
556
|
+
フォールバックするため、同一リポジトリ内の複数フォアマンが互いの通知を
|
|
557
|
+
取得しません。
|
|
558
|
+
|
|
559
|
+
## v0.15.0 の新機能
|
|
560
|
+
|
|
561
|
+
- **Codex の進捗証跡をストリーミング保存** — `codex exec --json` が JSONL イベントを
|
|
562
|
+
`out.txt.progress.log` へ逐次書き込むため、タイムアウト時にも最後に到達した手順を残せます。
|
|
563
|
+
`out.txt` と Jobs の表示は変わりません。
|
|
564
|
+
- **証拠に基づくタイムアウト診断** — タイムアウト自体では原因を特定できないことを明示し、
|
|
565
|
+
三段階の確認手順と、空の進捗ログが Codex の未進行を示す証拠ではないことを案内します。
|
|
566
|
+
- **rollout 記録への直接パス** — 最初の進捗イベントの `thread_id` から対応する
|
|
567
|
+
`rollout-*.jsonl` の絶対パスをタイムアウト出力に表示し、中断された会話履歴を確認できます。
|
|
568
|
+
|
|
519
569
|
## v0.14.0 の新機能
|
|
520
570
|
|
|
521
571
|
- **根拠に基づくルーティング提案**:`jobs recommend` と MCP `jobs_recommend` は公開ジョブメタデータだけを読み、ルーティングを自動変更しません。
|
package/README.ko.md
CHANGED
|
@@ -351,6 +351,24 @@ CLI 를 사용할 수 없음, `5` 1라운드 성공 투표자 부족, `6` 2라
|
|
|
351
351
|
`jobs.sh status` 가 `dead` 를 보고.
|
|
352
352
|
- **페이로드 상한** — 과대한 태스크 텍스트는 머리/꼬리만 남기고 자동 절단.
|
|
353
353
|
|
|
354
|
+
## 📬 라이브 메일함
|
|
355
|
+
|
|
356
|
+
라이브 메일함은 일회성 dispatch와 다른 Claude 전용 상주 백그라운드 실행입니다. 포어맨이 `--background`로 열고, 실행 중에도 추가 지시를 보낼 수 있으며, 끝나면 `jobs.sh close ID`로 닫을 책임이 있습니다. 방치해도 영구히 남아 있지는 않습니다. 설정된 전체 작업 시간 제한(`--job-timeout`)에 도달하면 종료됩니다.
|
|
357
|
+
|
|
358
|
+
```bash
|
|
359
|
+
scripts/dispatch.sh --background --vendor claude hard-judgment "시간 제한 테스트 실패를 확인해 주세요"
|
|
360
|
+
# dispatch가 출력한 작업 ID를 $ID로 저장
|
|
361
|
+
scripts/jobs.sh send "$ID" "재시도 경로도 확인해 주세요."
|
|
362
|
+
scripts/jobs.sh watch "$ID"
|
|
363
|
+
scripts/jobs.sh tail "$ID" --lines 20
|
|
364
|
+
scripts/jobs.sh close "$ID"
|
|
365
|
+
scripts/jobs.sh retry "$ID" --background
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
`watch`는 `$JOB_DIR/events.jsonl`을 따라가고, `tail`은 공개 `out.txt`를 읽습니다. 라이브 메일함은 현재 Claude만 지원합니다. 다른 벤더는 일반 일회성 dispatch로 내려가지만 조용히 처리되지는 않습니다. stderr와 `$JOB_DIR/mode-notice.txt`에 알림이 남고, `jobs.sh status ID`에도 표시됩니다.
|
|
369
|
+
|
|
370
|
+
유휴 상태에서는 API 호출이나 비용이 발생하지 않지만 전체 작업 시간 제한은 계속 소모됩니다. 대화가 끝나면 `close`하세요. 끝났거나 라이브가 아닌 작업에 `jobs.sh send`를 실행하면 명확한 오류와 함께 실패합니다. 보낸 뒤 추적하지 않을 작업, 라이브 지원이 없는 벤더, 깨끗한 상태에서 다시 실행해야 하는 경우에는 쓰지 말고 새 dispatch 또는 완료 뒤 `retry`를 사용하세요.
|
|
371
|
+
|
|
354
372
|
## ❓ FAQ
|
|
355
373
|
|
|
356
374
|
<details>
|
|
@@ -499,6 +517,36 @@ scripts/dispatch.sh --dry-run hardest-coding "…" # 완전히 해석된 계
|
|
|
499
517
|
|
|
500
518
|
## 📜 릴리스 기록
|
|
501
519
|
|
|
520
|
+
## v0.20.0 새 기능
|
|
521
|
+
|
|
522
|
+
- **Foreman 완료 수신함.** 백그라운드 디스패치가 끝나면 비공개 완료 레코드를
|
|
523
|
+
쓰고, 함께 제공되는 Claude Code 플러그인이 일치하는 레코드를 Foreman의 다음
|
|
524
|
+
프롬프트에 전달합니다. 출력 꼬리에는 프롬프트 주입 방어가 적용되어 제어 문자와
|
|
525
|
+
`U+2028`/`U+2029`를 제거하고 작업자 출력을 들여쓴 데이터로 감쌉니다.
|
|
526
|
+
- **설치 가능한 Claude Code 플러그인.** `.claude-plugin/marketplace.json`은
|
|
527
|
+
자기 참조 source를 사용하며, 배포 npm tarball에는 `hooks/`, `skills/`,
|
|
528
|
+
`.claude-plugin/`도 포함됩니다.
|
|
529
|
+
- **Claude 라이브 메일함.** 상주 백그라운드 Claude 작업은 실행 중 메시지를
|
|
530
|
+
받을 수 있고 `events.jsonl`을 기록합니다. 사용법은
|
|
531
|
+
[📬 라이브 메일함](#-라이브-메일함)을 참조하세요. 다른 벤더는 `stderr`와
|
|
532
|
+
`mode-notice.txt` 알림을 남긴 채 명시적으로 단발 실행으로 폴백하며,
|
|
533
|
+
`jobs.sh wait`는 `done exit=N`으로 끝납니다.
|
|
534
|
+
- **Foreman 세션 식별.** `SessionStart` hook은 Claude `session_id`를 PID와
|
|
535
|
+
시작 시각에 연결하여 PID 재사용에도 안전합니다. 디스패치는 부모 프로세스를
|
|
536
|
+
따라 `foreman_session`을 `meta.json`과 완료 레코드에 기록합니다. 수신함은
|
|
537
|
+
세션 일치를 우선하고 레거시 레코드에서만 `workdir`로 폴백하므로, 한 repository의
|
|
538
|
+
여러 Foreman이 서로의 알림을 가져가지 않습니다.
|
|
539
|
+
|
|
540
|
+
## v0.15.0 새 기능
|
|
541
|
+
|
|
542
|
+
- **Codex 진행 증거의 스트리밍 보존** — `codex exec --json`이 JSONL 이벤트를
|
|
543
|
+
`out.txt.progress.log`에 순차 기록하므로 시간 초과가 나도 마지막으로 도달한 단계를 남깁니다.
|
|
544
|
+
`out.txt`와 Jobs 표시는 그대로입니다.
|
|
545
|
+
- **증거 기반 시간 초과 진단** — 시간 초과 자체로 원인을 특정하지 않는다고 밝히고,
|
|
546
|
+
세 단계 점검 목록과 빈 진행 로그가 Codex 미진행의 증거가 아니라는 점을 안내합니다.
|
|
547
|
+
- **rollout 기록으로 가는 직접 경로** — 첫 진행 이벤트의 `thread_id`로 찾은
|
|
548
|
+
`rollout-*.jsonl`의 절대 경로를 시간 초과 출력에 표시하여, 중단된 대화 이력을 확인할 수 있습니다.
|
|
549
|
+
|
|
502
550
|
## v0.14.0 새 기능
|
|
503
551
|
|
|
504
552
|
- **근거 기반 라우팅 제안**: `jobs recommend`와 MCP `jobs_recommend`는 공개 작업 메타데이터만 읽고 라우팅을 자동 변경하지 않습니다.
|
package/README.md
CHANGED
|
@@ -205,6 +205,10 @@ header overrides that and the choice is remembered locally.
|
|
|
205
205
|
|
|
206
206
|
Core routing does not need Python; only this UI requires Python 3.9 or newer.
|
|
207
207
|
|
|
208
|
+
### Foreman completion inbox
|
|
209
|
+
|
|
210
|
+
Finished dispatches write a private completion record under `$OMNILANE_HOME/inbox/`. A Claude Code `SessionStart` hook binds each foreman's hook-provided session ID to its live process ancestry, and the bundled `UserPromptSubmit` hook atomically delivers up to ten records owned by that session on the foreman's next prompt. Older records without a session ID still use the original dispatch `workdir` scope; claimed records move to `inbox/consumed/`. Set `OMNILANE_INBOX=0` on a dispatch to disable record creation; the default is enabled.
|
|
211
|
+
|
|
208
212
|
## 📦 Install
|
|
209
213
|
|
|
210
214
|
Requirements: the vendor CLIs you want to route to, logged in (`codex`,
|
|
@@ -224,6 +228,15 @@ each CLI's instruction file (`~/.claude/CLAUDE.md`, `~/.codex/AGENTS.md`,
|
|
|
224
228
|
versions) so the main loop remembers to consult the table; non-interactive
|
|
225
229
|
installs can pass `OMNILANE_HOOKS=all|none|claude,codex`.
|
|
226
230
|
|
|
231
|
+
The foreman completion notice requires the Claude Code plugin install; the
|
|
232
|
+
skill-only symlink path does not deliver completion notices. Install the plugin
|
|
233
|
+
from this checkout with:
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
claude plugin marketplace add <path to this repo>
|
|
237
|
+
claude plugin install omnilane@omnilane
|
|
238
|
+
```
|
|
239
|
+
|
|
227
240
|
Use `./install.sh --check` for a read-only drift report. Add `--dry-run` to an
|
|
228
241
|
install or `--uninstall` to preview every checkout-owned file action.
|
|
229
242
|
Rollback the installer-owned links and marked reminders with
|
|
@@ -408,6 +421,24 @@ code passes through.
|
|
|
408
421
|
- **Payload caps** — oversized task text is truncated head+tail before it can
|
|
409
422
|
blow a worker's context.
|
|
410
423
|
|
|
424
|
+
## 📬 Live mailbox
|
|
425
|
+
|
|
426
|
+
A live mailbox is a resident Claude background dispatch, not a one-shot dispatch. The foreman opens it with `--background`, can send another instruction while it is still running, and is responsible for closing it with `jobs.sh close ID`. Leaving it unattended does not make it permanent: the configured whole-job timeout (`--job-timeout`) still ends it.
|
|
427
|
+
|
|
428
|
+
```bash
|
|
429
|
+
scripts/dispatch.sh --background --vendor claude hard-judgment "Review the timeout failure"
|
|
430
|
+
# save the printed job ID as $ID
|
|
431
|
+
scripts/jobs.sh send "$ID" "Also inspect the retry path."
|
|
432
|
+
scripts/jobs.sh watch "$ID"
|
|
433
|
+
scripts/jobs.sh tail "$ID" --lines 20
|
|
434
|
+
scripts/jobs.sh close "$ID"
|
|
435
|
+
scripts/jobs.sh retry "$ID" --background
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
`watch` follows `$JOB_DIR/events.jsonl`; `tail` reads the public `out.txt`. Live mailbox support is Claude-only today. Any other vendor runs as a normal one-shot dispatch, with a degradation notice sent to stderr and stored in `$JOB_DIR/mode-notice.txt`; `jobs.sh status ID` prints that notice as well.
|
|
439
|
+
|
|
440
|
+
An idle mailbox makes no API calls and incurs no API spend, but it keeps consuming its job-timeout window. Close it when its exchange is finished. `jobs.sh send` to a finished job or a job that is not live fails with a clear error. Do not use this for fire-and-forget work, vendors without live support, or a clean-slate rerun; start a fresh dispatch (or retry a completed job) instead.
|
|
441
|
+
|
|
411
442
|
## ❓ FAQ
|
|
412
443
|
|
|
413
444
|
<details>
|
|
@@ -565,6 +596,40 @@ working notes, including per-benchmark caveats, live in
|
|
|
565
596
|
|
|
566
597
|
## 📜 Release history
|
|
567
598
|
|
|
599
|
+
## What's new in v0.20.0
|
|
600
|
+
|
|
601
|
+
- **Foreman completion inbox.** Finished background dispatches write a private
|
|
602
|
+
completion record, and the bundled Claude Code plugin delivers matching
|
|
603
|
+
records into the foreman's next prompt. The output tail is injection-hardened:
|
|
604
|
+
control characters and `U+2028`/`U+2029` are removed, and worker output is
|
|
605
|
+
framed as indented data.
|
|
606
|
+
- **Installable Claude Code plugin.** `.claude-plugin/marketplace.json` uses a
|
|
607
|
+
self-referencing source, and the published npm tarball includes `hooks/`,
|
|
608
|
+
`skills/`, and `.claude-plugin/`.
|
|
609
|
+
- **Claude live mailbox.** Resident background Claude jobs can receive messages
|
|
610
|
+
while they run and record `events.jsonl`. For operations, see
|
|
611
|
+
[📬 Live mailbox](#-live-mailbox); other vendors explicitly fall back to
|
|
612
|
+
single-shot mode with a `stderr` and `mode-notice.txt` notice, and
|
|
613
|
+
`jobs.sh wait` ends with `done exit=N`.
|
|
614
|
+
- **Foreman session identity.** The `SessionStart` hook binds a Claude
|
|
615
|
+
`session_id` to a PID plus start time, making PID reuse safe. Dispatch walks
|
|
616
|
+
its ancestors to stamp `foreman_session` into `meta.json` and completion
|
|
617
|
+
records; the inbox prefers a session match and falls back to `workdir` for
|
|
618
|
+
legacy records, so two foremen in one repository do not take each other's
|
|
619
|
+
notices.
|
|
620
|
+
|
|
621
|
+
## What's new in v0.15.0
|
|
622
|
+
|
|
623
|
+
- **Streaming Codex progress evidence** — `codex exec --json` now streams JSONL
|
|
624
|
+
events into `out.txt.progress.log`, so a timeout still records its last known
|
|
625
|
+
step. `out.txt` and the Jobs display remain unchanged.
|
|
626
|
+
- **Evidence-led timeout diagnostics** — timeouts now state that they do not
|
|
627
|
+
identify the cause, list a three-step check, and clarify that an empty
|
|
628
|
+
progress log does not prove Codex made no progress.
|
|
629
|
+
- **Direct rollout recovery path** — timeout output now prints the absolute path
|
|
630
|
+
to the matching `rollout-*.jsonl`, found from the first progress event's
|
|
631
|
+
`thread_id`, so the interrupted conversation history can be inspected.
|
|
632
|
+
|
|
568
633
|
## What's new in v0.14.0
|
|
569
634
|
|
|
570
635
|
- **Evidence-based routing recommendations** — `jobs recommend` and MCP
|
package/README.zh-CN.md
CHANGED
|
@@ -333,6 +333,24 @@ configure.sh set|get|unset|list|diff LANE [SPEC] # 非交互编辑/查看 rou
|
|
|
333
333
|
而不是永远显示 `running`。
|
|
334
334
|
- **任务载荷上限** — 过大的任务文本自动头尾截断,防止撑爆工作端上下文。
|
|
335
335
|
|
|
336
|
+
## 📬 实时邮箱
|
|
337
|
+
|
|
338
|
+
实时邮箱是 Claude 专用的常驻后台派发,不是一次性派发。派发方以 `--background` 打开后,运行中仍可追加指令,并负责用 `jobs.sh close ID` 收尾。即使无人处理,它也不会永久存在:已配置的整个作业超时(`--job-timeout`)到期后仍会终止它。
|
|
339
|
+
|
|
340
|
+
```bash
|
|
341
|
+
scripts/dispatch.sh --background --vendor claude hard-judgment "检查超时测试失败的原因"
|
|
342
|
+
# 将 dispatch 显示的作业 ID 保存为 $ID
|
|
343
|
+
scripts/jobs.sh send "$ID" "再检查重试路径。"
|
|
344
|
+
scripts/jobs.sh watch "$ID"
|
|
345
|
+
scripts/jobs.sh tail "$ID" --lines 20
|
|
346
|
+
scripts/jobs.sh close "$ID"
|
|
347
|
+
scripts/jobs.sh retry "$ID" --background
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
`watch` 会跟随 `$JOB_DIR/events.jsonl`;`tail` 读取公开的 `out.txt`。目前只有 Claude 支持实时邮箱。其他供应商都会降级为普通的一次性派发,但不是静默发生:stderr 和 `$JOB_DIR/mode-notice.txt` 都会留下提示,`jobs.sh status ID` 也会显示该提示。
|
|
351
|
+
|
|
352
|
+
空闲时不会发出 API 调用,也不会产生 API 费用,但整个作业超时的时间仍在流逝。处理结束就应执行 `close`。向已结束或不是实时邮箱的作业执行 `jobs.sh send` 会明确报错并失败。即发即忘的工作、没有实时支持的供应商,或需要从干净状态重新运行的情况都不适用;请新建一次派发,或在作业完成后使用 `retry`。
|
|
353
|
+
|
|
336
354
|
## ❓ 常见问题
|
|
337
355
|
|
|
338
356
|
<details>
|
|
@@ -473,6 +491,33 @@ vendor 一律当成 `work`,而且它只能逐次明确指定,永远不是 lane
|
|
|
473
491
|
|
|
474
492
|
## 📜 版本历程
|
|
475
493
|
|
|
494
|
+
## v0.20.0 新功能
|
|
495
|
+
|
|
496
|
+
- **Foreman 完成收件箱。** 后台派发完成后会写入私有完成记录,内置 Claude
|
|
497
|
+
Code 插件会在 Foreman 的下一次提示中递交匹配记录。输出尾段已做提示注入防护:
|
|
498
|
+
移除控制字符及 `U+2028`/`U+2029`,并将工作器输出框为缩进数据。
|
|
499
|
+
- **可安装的 Claude Code 插件。** `.claude-plugin/marketplace.json` 使用自指
|
|
500
|
+
来源,已发布的 npm tarball 也包含 `hooks/`、`skills/` 和
|
|
501
|
+
`.claude-plugin/`。
|
|
502
|
+
- **Claude 实时邮箱。** 常驻后台 Claude 作业可在运行时接收消息,并写入
|
|
503
|
+
`events.jsonl`。操作方式请见 [📬 实时邮箱](#-实时邮箱);其他供应商会明确
|
|
504
|
+
降级为单次模式,并留下 `stderr` 与 `mode-notice.txt` 通知;`jobs.sh wait`
|
|
505
|
+
最后会输出 `done exit=N`。
|
|
506
|
+
- **Foreman 会话身份。** `SessionStart` hook 会将 Claude `session_id` 绑定到
|
|
507
|
+
PID 与启动时间,避免 PID 重用误判。派发会沿父进程向上查找,将
|
|
508
|
+
`foreman_session` 写入 `meta.json` 与完成记录;收件箱优先按会话匹配,旧记录
|
|
509
|
+
才回退至 `workdir`,避免同一 repository 的两个 Foreman 互取通知。
|
|
510
|
+
|
|
511
|
+
## v0.15.0 新功能
|
|
512
|
+
|
|
513
|
+
- **流式保留 Codex 进度证据**:`codex exec --json` 会将 JSONL 事件逐条写入
|
|
514
|
+
`out.txt.progress.log`,即使超时也会留下最后执行到哪一步。`out.txt` 与任务列表显示保持不变。
|
|
515
|
+
- **超时诊断回归证据**:超时提示明确说明它本身不足以判定原因,提供三步检查清单,并说明空的
|
|
516
|
+
进度日志不是 Codex 从未推进的证据。
|
|
517
|
+
- **直接给出 rollout 记录位置**:超时输出会根据第一条进度事件的 `thread_id`,打印
|
|
518
|
+
${CODEX_HOME:-$HOME/.codex}/sessions 下对应 `rollout-*.jsonl` 的绝对路径,便于查看
|
|
519
|
+
被中断而未回报的完整对话历程。
|
|
520
|
+
|
|
476
521
|
## v0.14.0 新功能
|
|
477
522
|
|
|
478
523
|
- **基于证据的路由建议**:`jobs recommend` 与 MCP `jobs_recommend` 只读取公开作业元数据,并且不会自动修改路由。
|
package/README.zh-TW.md
CHANGED
|
@@ -360,6 +360,24 @@ codex/claude/grok/gemini 自選 1-4 個評審。開了之後,同一個問題丟
|
|
|
360
360
|
而不是永遠顯示 `running`。
|
|
361
361
|
- **任務酬載上限** — 過大的任務文字自動頭尾截斷,防止撐爆工作端脈絡。
|
|
362
362
|
|
|
363
|
+
## 📬 即時信箱
|
|
364
|
+
|
|
365
|
+
即時信箱是 Claude 專用的常駐背景派工,不是一次性派工。派工者以 `--background` 開啟後,執行中仍能補傳指示,並負責用 `jobs.sh close ID` 收尾。即使沒人處理,也不會永久存在:設定的整體工作逾時(`--job-timeout`)一到就會結束。
|
|
366
|
+
|
|
367
|
+
```bash
|
|
368
|
+
scripts/dispatch.sh --background --vendor claude hard-judgment "檢查逾時測試失敗的原因"
|
|
369
|
+
# 將 dispatch 顯示的工作 ID 存成 $ID
|
|
370
|
+
scripts/jobs.sh send "$ID" "再確認重試路徑。"
|
|
371
|
+
scripts/jobs.sh watch "$ID"
|
|
372
|
+
scripts/jobs.sh tail "$ID" --lines 20
|
|
373
|
+
scripts/jobs.sh close "$ID"
|
|
374
|
+
scripts/jobs.sh retry "$ID" --background
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
`watch` 追隨 `$JOB_DIR/events.jsonl`;`tail` 讀取公開的 `out.txt`。目前只有 Claude 支援即時信箱。其他供應商都會降級成一般的一次性派工,但通知不會被隱藏:stderr 與 `$JOB_DIR/mode-notice.txt` 都會留下提示,`jobs.sh status ID` 也會顯示它。
|
|
378
|
+
|
|
379
|
+
閒置時不會發出 API 呼叫,也不會增加 API 費用,但仍會持續消耗整體工作逾時的時間。處理完成就應執行 `close`。對已結束或不是即時信箱的工作使用 `jobs.sh send`,會明確報錯並失敗。送出後不需追蹤的工作、沒有即時支援的供應商,或必須從乾淨狀態重跑的情況都不適用;請改用新的派工,或在工作完成後使用 `retry`。
|
|
380
|
+
|
|
363
381
|
## ❓ 常見問題
|
|
364
382
|
|
|
365
383
|
<details>
|
|
@@ -497,6 +515,33 @@ vendor 一律當成 `work`,而且它只能逐次明確指定,永遠不是 lane
|
|
|
497
515
|
|
|
498
516
|
## 📜 版本歷程
|
|
499
517
|
|
|
518
|
+
## v0.20.0 新功能
|
|
519
|
+
|
|
520
|
+
- **Foreman 完成收件匣。** 背景派工完成後會寫入私有完成紀錄,內建的 Claude
|
|
521
|
+
Code 外掛會在 Foreman 的下一個提示中遞交相符紀錄。輸出尾段已做提示注入防護:
|
|
522
|
+
移除控制字元與 `U+2028`/`U+2029`,並把工作者輸出框成縮排資料。
|
|
523
|
+
- **可安裝的 Claude Code 外掛。** `.claude-plugin/marketplace.json` 使用自指
|
|
524
|
+
來源,已發布的 npm tarball 也會包含 `hooks/`、`skills/` 和
|
|
525
|
+
`.claude-plugin/`。
|
|
526
|
+
- **Claude 即時信箱。** 常駐背景 Claude 工作可在執行時接收訊息,並寫入
|
|
527
|
+
`events.jsonl`。操作方式請見 [📬 即時信箱](#-即時信箱);其他供應商會明確
|
|
528
|
+
退化成單次模式,留下 `stderr` 與 `mode-notice.txt` 通知;`jobs.sh wait`
|
|
529
|
+
最後會印出 `done exit=N`。
|
|
530
|
+
- **Foreman 工作階段身分。** `SessionStart` hook 會把 Claude `session_id` 綁定
|
|
531
|
+
至 PID 與開始時間,避免 PID 重用誤判。派工會往上走訪父程序,將
|
|
532
|
+
`foreman_session` 寫入 `meta.json` 與完成紀錄;收件匣先比對工作階段,舊紀錄
|
|
533
|
+
才回退到 `workdir`,避免同一 repository 的兩個 Foreman 互拿通知。
|
|
534
|
+
|
|
535
|
+
## v0.15.0 新功能
|
|
536
|
+
|
|
537
|
+
- **串流保留 Codex 進度證據**:`codex exec --json` 會把 JSONL 事件逐筆寫入
|
|
538
|
+
`out.txt.progress.log`,即使逾時也能留下最後做到哪一步。`out.txt` 與工作清單顯示維持不變。
|
|
539
|
+
- **逾時診斷回到證據**:逾時訊息明示它本身不足以判定原因,提供三步檢查清單,並說明空的
|
|
540
|
+
進度日誌不是 Codex 未曾前進的證據。
|
|
541
|
+
- **直接指出 rollout 記錄位置**:逾時輸出會依第一筆進度事件的 `thread_id`,印出
|
|
542
|
+
${CODEX_HOME:-$HOME/.codex}/sessions 下對應 `rollout-*.jsonl` 的絕對路徑,方便查看
|
|
543
|
+
被中斷而未回報的完整對話歷程。
|
|
544
|
+
|
|
500
545
|
## v0.14.0 新功能
|
|
501
546
|
|
|
502
547
|
- **依證據產生路由建議**:`jobs recommend` 與 MCP `jobs_recommend` 只用已完成工作的
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.20.0
|
package/hooks/hooks.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"hooks": {
|
|
3
|
+
"SessionStart": [
|
|
4
|
+
{
|
|
5
|
+
"matcher": "startup|resume|clear",
|
|
6
|
+
"hooks": [
|
|
7
|
+
{
|
|
8
|
+
"type": "command",
|
|
9
|
+
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/record-foreman-session.sh",
|
|
10
|
+
"timeout": 5
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"type": "command",
|
|
14
|
+
"command": "cat",
|
|
15
|
+
"args": ["${CLAUDE_PLUGIN_ROOT}/hooks/routing-instruction.md"],
|
|
16
|
+
"timeout": 5
|
|
17
|
+
}
|
|
18
|
+
]
|
|
19
|
+
}
|
|
20
|
+
],
|
|
21
|
+
"UserPromptSubmit": [
|
|
22
|
+
{
|
|
23
|
+
"hooks": [
|
|
24
|
+
{
|
|
25
|
+
"type": "command",
|
|
26
|
+
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/report-completions.sh",
|
|
27
|
+
"timeout": 5
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Fail-open SessionStart hook: bind Claude's session_id to its process identity.
|
|
3
|
+
set -uo pipefail
|
|
4
|
+
|
|
5
|
+
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." 2>/dev/null && pwd -P)" || exit 0
|
|
6
|
+
# shellcheck source=../scripts/lib/common.sh
|
|
7
|
+
source "$ROOT/scripts/lib/common.sh" >/dev/null 2>&1 || exit 0
|
|
8
|
+
|
|
9
|
+
record_foreman_session() {
|
|
10
|
+
local session_id parent_pid start_time sessions entry tmp old_umask rc=0
|
|
11
|
+
session_id="$(perl -MJSON::PP -0777 -e '
|
|
12
|
+
use strict;
|
|
13
|
+
use warnings;
|
|
14
|
+
my $payload = eval { decode_json(<STDIN>) };
|
|
15
|
+
exit 1 unless ref($payload) eq "HASH";
|
|
16
|
+
my $id = $payload->{session_id};
|
|
17
|
+
exit 1 if ref($id) || !defined($id) ||
|
|
18
|
+
$id !~ /\A[A-Za-z0-9._:-]{1,256}\z/;
|
|
19
|
+
print $id;
|
|
20
|
+
' 2>/dev/null)" || return 0
|
|
21
|
+
|
|
22
|
+
parent_pid="$PPID"
|
|
23
|
+
[[ "$parent_pid" =~ ^[1-9][0-9]{0,9}$ ]] || return 0
|
|
24
|
+
start_time="$(process_start_time "$parent_pid")" || return 0
|
|
25
|
+
sessions="$OMNILANE_HOME/sessions"
|
|
26
|
+
prepare_private_store "$sessions" "session identity store" || return 0
|
|
27
|
+
entry="$sessions/$parent_pid.json"
|
|
28
|
+
tmp="$sessions/.$parent_pid.tmp.$$-$RANDOM"
|
|
29
|
+
|
|
30
|
+
old_umask="$(umask)"
|
|
31
|
+
umask 077
|
|
32
|
+
PID_VALUE="$parent_pid" START_VALUE="$start_time" SESSION_VALUE="$session_id" \
|
|
33
|
+
perl -MJSON::PP -e '
|
|
34
|
+
use strict;
|
|
35
|
+
use warnings;
|
|
36
|
+
my $entry = {
|
|
37
|
+
pid => 0 + $ENV{PID_VALUE},
|
|
38
|
+
start_time => $ENV{START_VALUE},
|
|
39
|
+
session_id => $ENV{SESSION_VALUE},
|
|
40
|
+
};
|
|
41
|
+
print JSON::PP->new->canonical->encode($entry), "\n";
|
|
42
|
+
' > "$tmp" || rc=$?
|
|
43
|
+
if [[ "$rc" -eq 0 ]]; then
|
|
44
|
+
chmod 600 "$tmp" || rc=$?
|
|
45
|
+
fi
|
|
46
|
+
if [[ "$rc" -eq 0 ]]; then
|
|
47
|
+
mv "$tmp" "$entry" || rc=$?
|
|
48
|
+
fi
|
|
49
|
+
umask "$old_umask"
|
|
50
|
+
if [[ "$rc" -ne 0 ]]; then
|
|
51
|
+
rm "$tmp" 2>/dev/null || true
|
|
52
|
+
fi
|
|
53
|
+
return 0
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
record_foreman_session || true
|
|
57
|
+
exit 0
|