oh-my-opencode 2.7.0 → 2.7.1
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/README.ja.md +78 -2
- package/README.ko.md +81 -2
- package/README.md +17 -1
- package/README.zh-cn.md +82 -2
- package/dist/cli/index.js +1 -1
- package/dist/features/builtin-commands/templates/init-deep.d.ts +1 -1
- package/dist/hooks/todo-continuation-enforcer.test.d.ts +1 -0
- package/dist/index.js +188 -180
- package/package.json +1 -1
package/README.ja.md
CHANGED
|
@@ -390,6 +390,39 @@ gh repo star code-yeongyu/oh-my-opencode
|
|
|
390
390
|
</details>
|
|
391
391
|
|
|
392
392
|
|
|
393
|
+
## アンインストール
|
|
394
|
+
|
|
395
|
+
oh-my-opencode を削除するには:
|
|
396
|
+
|
|
397
|
+
1. **OpenCode 設定からプラグインを削除**
|
|
398
|
+
|
|
399
|
+
`~/.config/opencode/opencode.json` (または `opencode.jsonc`) を編集し、`plugin` 配列から `"oh-my-opencode"` を削除します:
|
|
400
|
+
|
|
401
|
+
```bash
|
|
402
|
+
# jq を使用する例
|
|
403
|
+
jq '.plugin = [.plugin[] | select(. != "oh-my-opencode")]' \
|
|
404
|
+
~/.config/opencode/opencode.json > /tmp/oc.json && \
|
|
405
|
+
mv /tmp/oc.json ~/.config/opencode/opencode.json
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
2. **設定ファイルの削除 (オプション)**
|
|
409
|
+
|
|
410
|
+
```bash
|
|
411
|
+
# ユーザー設定を削除
|
|
412
|
+
rm -f ~/.config/opencode/oh-my-opencode.json
|
|
413
|
+
|
|
414
|
+
# プロジェクト設定を削除 (存在する場合)
|
|
415
|
+
rm -f .opencode/oh-my-opencode.json
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
3. **削除の確認**
|
|
419
|
+
|
|
420
|
+
```bash
|
|
421
|
+
opencode --version
|
|
422
|
+
# プラグインがロードされなくなっているはずです
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
|
|
393
426
|
## 機能
|
|
394
427
|
|
|
395
428
|
### Agents: あなたの新しいチームメイト
|
|
@@ -457,6 +490,19 @@ Ask @explore for the policy on this feature
|
|
|
457
490
|
- **ast_grep_search**: AST 認識コードパターン検索 (25言語対応)
|
|
458
491
|
- **ast_grep_replace**: AST 認識コード置換
|
|
459
492
|
|
|
493
|
+
#### セッション管理
|
|
494
|
+
|
|
495
|
+
OpenCode セッション履歴をナビゲートおよび検索するためのツール:
|
|
496
|
+
|
|
497
|
+
- **session_list**: 日付およびリミットでフィルタリングしながらすべての OpenCode セッションを一覧表示
|
|
498
|
+
- **session_read**: 特定のセッションからメッセージと履歴を読み取る
|
|
499
|
+
- **session_search**: セッションメッセージ全体を全文検索
|
|
500
|
+
- **session_info**: セッションに関するメタデータと統計情報を取得
|
|
501
|
+
|
|
502
|
+
これらのツールにより、エージェントは以前の会話を参照し、セッション間の継続性を維持できます。
|
|
503
|
+
|
|
504
|
+
- **call_omo_agent**: 専門的な explore/librarian エージェントを起動。非同期実行のための `run_in_background` パラメータをサポート。
|
|
505
|
+
|
|
460
506
|
#### Context Is All You Need
|
|
461
507
|
- **Directory AGENTS.md / README.md Injector**: ファイルを読み込む際、`AGENTS.md` と `README.md` の内容を自動的に注入します。ファイルディレクトリからプロジェクトルートまで遡り、パス上の **すべて** の `AGENTS.md` ファイルを収集します。ネストされたディレクトリごとの指示をサポートします:
|
|
462
508
|
```
|
|
@@ -619,7 +665,7 @@ Oh My OpenCode は以下の場所からフックを読み込んで実行しま
|
|
|
619
665
|
|
|
620
666
|
| プラットフォーム | ユーザー設定パス |
|
|
621
667
|
|------------------|------------------|
|
|
622
|
-
| **Windows** | `~/.config/opencode/oh-my-opencode.json` (
|
|
668
|
+
| **Windows** | `~/.config/opencode/oh-my-opencode.json` (推奨) または `%APPDATA%\opencode\oh-my-opencode.json` (fallback) |
|
|
623
669
|
| **macOS/Linux** | `~/.config/opencode/oh-my-opencode.json` |
|
|
624
670
|
|
|
625
671
|
スキーマ自動補完がサポートされています:
|
|
@@ -630,6 +676,36 @@ Oh My OpenCode は以下の場所からフックを読み込んで実行しま
|
|
|
630
676
|
}
|
|
631
677
|
```
|
|
632
678
|
|
|
679
|
+
### JSONC のサポート
|
|
680
|
+
|
|
681
|
+
`oh-my-opencode` 設定ファイルは JSONC (コメント付き JSON) をサポートしています:
|
|
682
|
+
- 行コメント: `// コメント`
|
|
683
|
+
- ブロックコメント: `/* コメント */`
|
|
684
|
+
- 末尾のカンマ: `{ "key": "value", }`
|
|
685
|
+
|
|
686
|
+
`oh-my-opencode.jsonc` と `oh-my-opencode.json` の両方が存在する場合、`.jsonc` が優先されます。
|
|
687
|
+
|
|
688
|
+
**コメント付きの例:**
|
|
689
|
+
|
|
690
|
+
```jsonc
|
|
691
|
+
{
|
|
692
|
+
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-opencode/master/assets/oh-my-opencode.schema.json",
|
|
693
|
+
|
|
694
|
+
// Antigravity OAuth 経由で Google Gemini を有効にする
|
|
695
|
+
"google_auth": false,
|
|
696
|
+
|
|
697
|
+
/* エージェントのオーバーライド - 特定のタスクに合わせてモデルをカスタマイズ */
|
|
698
|
+
"agents": {
|
|
699
|
+
"oracle": {
|
|
700
|
+
"model": "openai/gpt-5.2" // 戦略的な推論のための GPT
|
|
701
|
+
},
|
|
702
|
+
"explore": {
|
|
703
|
+
"model": "opencode/grok-code" // 探索のための高速かつ無料のモデル
|
|
704
|
+
},
|
|
705
|
+
},
|
|
706
|
+
}
|
|
707
|
+
```
|
|
708
|
+
|
|
633
709
|
### Google Auth
|
|
634
710
|
|
|
635
711
|
**推奨**: 外部の [`opencode-antigravity-auth`](https://github.com/NoeFabris/opencode-antigravity-auth) プラグインを使用してください。マルチアカウントロードバランシング、より多くのモデル(Antigravity 経由の Claude を含む)、活発なメンテナンスを提供します。[インストール > Google Gemini](#42-google-gemini-antigravity-oauth) を参照。
|
|
@@ -792,7 +868,7 @@ Oh My OpenCode は以下の場所からフックを読み込んで実行しま
|
|
|
792
868
|
}
|
|
793
869
|
```
|
|
794
870
|
|
|
795
|
-
利用可能なフック:`todo-continuation-enforcer`, `context-window-monitor`, `session-recovery`, `session-notification`, `comment-checker`, `grep-output-truncator`, `tool-output-truncator`, `directory-agents-injector`, `directory-readme-injector`, `empty-task-response-detector`, `think-mode`, `anthropic-auto-compact`, `rules-injector`, `background-notification`, `auto-update-checker`, `startup-toast`, `keyword-detector`, `agent-usage-reminder`, `non-interactive-env`, `interactive-bash-session`, `empty-message-sanitizer`
|
|
871
|
+
利用可能なフック:`todo-continuation-enforcer`, `context-window-monitor`, `session-recovery`, `session-notification`, `comment-checker`, `grep-output-truncator`, `tool-output-truncator`, `directory-agents-injector`, `directory-readme-injector`, `empty-task-response-detector`, `think-mode`, `anthropic-auto-compact`, `rules-injector`, `background-notification`, `auto-update-checker`, `startup-toast`, `keyword-detector`, `agent-usage-reminder`, `non-interactive-env`, `interactive-bash-session`, `empty-message-sanitizer`, `preemptive-compaction`, `compaction-context-injector`, `thinking-block-validator`, `claude-code-hooks`
|
|
796
872
|
|
|
797
873
|
**`auto-update-checker`と`startup-toast`について**: `startup-toast` フックは `auto-update-checker` のサブ機能です。アップデートチェックは有効なまま起動トースト通知のみを無効化するには、`disabled_hooks` に `"startup-toast"` を追加してください。すべてのアップデートチェック機能(トーストを含む)を無効化するには、`"auto-update-checker"` を追加してください。
|
|
798
874
|
|
package/README.ko.md
CHANGED
|
@@ -387,6 +387,39 @@ gh repo star code-yeongyu/oh-my-opencode
|
|
|
387
387
|
</details>
|
|
388
388
|
|
|
389
389
|
|
|
390
|
+
## 언인스톨
|
|
391
|
+
|
|
392
|
+
oh-my-opencode를 제거하려면:
|
|
393
|
+
|
|
394
|
+
1. **OpenCode 설정에서 플러그인 제거**
|
|
395
|
+
|
|
396
|
+
`~/.config/opencode/opencode.json` (또는 `opencode.jsonc`)를 편집하여 `plugin` 배열에서 `"oh-my-opencode"`를 제거합니다:
|
|
397
|
+
|
|
398
|
+
```bash
|
|
399
|
+
# jq 사용 예시
|
|
400
|
+
jq '.plugin = [.plugin[] | select(. != "oh-my-opencode")]' \
|
|
401
|
+
~/.config/opencode/opencode.json > /tmp/oc.json && \
|
|
402
|
+
mv /tmp/oc.json ~/.config/opencode/opencode.json
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
2. **설정 파일 삭제 (선택 사항)**
|
|
406
|
+
|
|
407
|
+
```bash
|
|
408
|
+
# 사용자 설정 삭제
|
|
409
|
+
rm -f ~/.config/opencode/oh-my-opencode.json
|
|
410
|
+
|
|
411
|
+
# 프로젝트 설정 삭제 (존재하는 경우)
|
|
412
|
+
rm -f .opencode/oh-my-opencode.json
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
3. **제거 확인**
|
|
416
|
+
|
|
417
|
+
```bash
|
|
418
|
+
opencode --version
|
|
419
|
+
# 플러그인이 더 이상 로드되지 않아야 합니다
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
|
|
390
423
|
## 기능
|
|
391
424
|
|
|
392
425
|
### Agents: 당신의 새로운 팀원들
|
|
@@ -450,6 +483,18 @@ Syntax Highlighting, Autocomplete, Refactoring, Navigation, Analysis, 그리고
|
|
|
450
483
|
- **lsp_code_action_resolve**: 코드 액션 적용
|
|
451
484
|
- **ast_grep_search**: AST 인식 코드 패턴 검색 (25개 언어)
|
|
452
485
|
- **ast_grep_replace**: AST 인식 코드 교체
|
|
486
|
+
- **call_omo_agent**: 전문 explore/librarian 에이전트를 생성합니다. 비동기 실행을 위한 `run_in_background` 파라미터를 지원합니다.
|
|
487
|
+
|
|
488
|
+
#### 세션 관리 (Session Management)
|
|
489
|
+
|
|
490
|
+
OpenCode 세션 히스토리를 탐색하고 검색하기 위한 도구들입니다:
|
|
491
|
+
|
|
492
|
+
- **session_list**: 날짜 및 개수 제한 필터링을 포함한 모든 OpenCode 세션 목록 조회
|
|
493
|
+
- **session_read**: 특정 세션의 메시지 및 히스토리 읽기
|
|
494
|
+
- **session_search**: 세션 메시지 전체 텍스트 검색
|
|
495
|
+
- **session_info**: 세션에 대한 메타데이터 및 통계 정보 조회
|
|
496
|
+
|
|
497
|
+
이 도구들을 통해 에이전트는 이전 대화를 참조하고 세션 간의 연속성을 유지할 수 있습니다.
|
|
453
498
|
|
|
454
499
|
#### Context is all you need.
|
|
455
500
|
- **Directory AGENTS.md / README.md Injector**: 파일을 읽을 때 `AGENTS.md`, `README.md` 내용을 자동으로 주입합니다. 파일 디렉토리부터 프로젝트 루트까지 탐색하며, 경로 상의 **모든** `AGENTS.md` 파일을 수집합니다. 중첩된 디렉토리별 지침을 지원합니다:
|
|
@@ -602,6 +647,10 @@ Oh My OpenCode는 다음 위치의 훅을 읽고 실행합니다:
|
|
|
602
647
|
- **Empty Message Sanitizer**: 빈 채팅 메시지로 인한 API 오류를 방지합니다. 전송 전 메시지 내용을 자동으로 정리합니다.
|
|
603
648
|
- **Grep Output Truncator**: grep은 산더미 같은 텍스트를 반환할 수 있습니다. 남은 컨텍스트 윈도우에 따라 동적으로 출력을 축소합니다—50% 여유 공간 유지, 최대 50k 토큰.
|
|
604
649
|
- **Tool Output Truncator**: 같은 아이디어, 더 넓은 범위. Grep, Glob, LSP 도구, AST-grep의 출력을 축소합니다. 한 번의 장황한 검색이 전체 컨텍스트를 잡아먹는 것을 방지합니다.
|
|
650
|
+
- **선제적 압축 (Preemptive Compaction)**: 세션 토큰 한계에 도달하기 전에 선제적으로 세션을 압축합니다. 문제가 발생하기 전에 미리 실행됩니다.
|
|
651
|
+
- **압축 컨텍스트 주입기 (Compaction Context Injector)**: 세션 압축 중에 중요한 컨텍스트(AGENTS.md, 현재 디렉토리 정보 등)를 유지하여 중요한 상태를 잃지 않도록 합니다.
|
|
652
|
+
- **사고 블록 검증기 (Thinking Block Validator)**: 사고(thinking) 블록의 형식이 올바른지 검증하여 잘못된 형식으로 인한 API 오류를 방지합니다.
|
|
653
|
+
- **Claude Code 훅 (Claude Code Hooks)**: Claude Code의 settings.json에 설정된 훅을 실행합니다. PreToolUse/PostToolUse/UserPromptSubmit/Stop 이벤트를 지원하는 호환성 레이어입니다.
|
|
605
654
|
|
|
606
655
|
## 설정
|
|
607
656
|
|
|
@@ -613,7 +662,7 @@ Oh My OpenCode는 다음 위치의 훅을 읽고 실행합니다:
|
|
|
613
662
|
|
|
614
663
|
| 플랫폼 | 사용자 설정 경로 |
|
|
615
664
|
|--------|------------------|
|
|
616
|
-
| **Windows** | `~/.config/opencode/oh-my-opencode.json` (
|
|
665
|
+
| **Windows** | `~/.config/opencode/oh-my-opencode.json` (권장) 또는 `%APPDATA%\opencode\oh-my-opencode.json` (fallback) |
|
|
617
666
|
| **macOS/Linux** | `~/.config/opencode/oh-my-opencode.json` |
|
|
618
667
|
|
|
619
668
|
Schema 자동 완성이 지원됩니다:
|
|
@@ -624,6 +673,36 @@ Schema 자동 완성이 지원됩니다:
|
|
|
624
673
|
}
|
|
625
674
|
```
|
|
626
675
|
|
|
676
|
+
### JSONC 지원
|
|
677
|
+
|
|
678
|
+
`oh-my-opencode` 설정 파일은 JSONC(주석이 포함된 JSON)를 지원합니다:
|
|
679
|
+
- 한 줄 주석: `// 주석`
|
|
680
|
+
- 블록 주석: `/* 주석 */`
|
|
681
|
+
- 후행 콤마(Trailing commas): `{ "key": "value", }`
|
|
682
|
+
|
|
683
|
+
`oh-my-opencode.jsonc`와 `oh-my-opencode.json` 파일이 모두 존재할 경우, `.jsonc` 파일이 우선순위를 갖습니다.
|
|
684
|
+
|
|
685
|
+
**주석이 포함된 예시:**
|
|
686
|
+
|
|
687
|
+
```jsonc
|
|
688
|
+
{
|
|
689
|
+
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-opencode/master/assets/oh-my-opencode.schema.json",
|
|
690
|
+
|
|
691
|
+
// Antigravity OAuth를 통해 Google Gemini 활성화
|
|
692
|
+
"google_auth": false,
|
|
693
|
+
|
|
694
|
+
/* 에이전트 오버라이드 - 특정 작업에 대한 모델 커스터마이징 */
|
|
695
|
+
"agents": {
|
|
696
|
+
"oracle": {
|
|
697
|
+
"model": "openai/gpt-5.2" // 전략적 추론을 위한 GPT
|
|
698
|
+
},
|
|
699
|
+
"explore": {
|
|
700
|
+
"model": "opencode/grok-code" // 탐색을 위한 빠르고 무료인 모델
|
|
701
|
+
},
|
|
702
|
+
},
|
|
703
|
+
}
|
|
704
|
+
```
|
|
705
|
+
|
|
627
706
|
### Google Auth
|
|
628
707
|
|
|
629
708
|
**권장**: 외부 [`opencode-antigravity-auth`](https://github.com/NoeFabris/opencode-antigravity-auth) 플러그인을 사용하세요. 멀티 계정 로드밸런싱, 더 많은 모델(Antigravity를 통한 Claude 포함), 활발한 유지보수를 제공합니다. [설치 > Google Gemini](#42-google-gemini-antigravity-oauth) 참조.
|
|
@@ -786,7 +865,7 @@ Schema 자동 완성이 지원됩니다:
|
|
|
786
865
|
}
|
|
787
866
|
```
|
|
788
867
|
|
|
789
|
-
사용 가능한 훅: `todo-continuation-enforcer`, `context-window-monitor`, `session-recovery`, `session-notification`, `comment-checker`, `grep-output-truncator`, `tool-output-truncator`, `directory-agents-injector`, `directory-readme-injector`, `empty-task-response-detector`, `think-mode`, `anthropic-auto-compact`, `rules-injector`, `background-notification`, `auto-update-checker`, `startup-toast`, `keyword-detector`, `agent-usage-reminder`, `non-interactive-env`, `interactive-bash-session`, `empty-message-sanitizer`
|
|
868
|
+
사용 가능한 훅: `todo-continuation-enforcer`, `context-window-monitor`, `session-recovery`, `session-notification`, `comment-checker`, `grep-output-truncator`, `tool-output-truncator`, `directory-agents-injector`, `directory-readme-injector`, `empty-task-response-detector`, `think-mode`, `anthropic-auto-compact`, `rules-injector`, `background-notification`, `auto-update-checker`, `startup-toast`, `keyword-detector`, `agent-usage-reminder`, `non-interactive-env`, `interactive-bash-session`, `empty-message-sanitizer`, `preemptive-compaction`, `compaction-context-injector`, `thinking-block-validator`, `claude-code-hooks`
|
|
790
869
|
|
|
791
870
|
**`auto-update-checker`와 `startup-toast`에 대한 참고사항**: `startup-toast` 훅은 `auto-update-checker`의 하위 기능입니다. 업데이트 확인은 유지하면서 시작 토스트 알림만 비활성화하려면 `disabled_hooks`에 `"startup-toast"`를 추가하세요. 모든 업데이트 확인 기능(토스트 포함)을 비활성화하려면 `"auto-update-checker"`를 추가하세요.
|
|
792
871
|
|
package/README.md
CHANGED
|
@@ -522,6 +522,18 @@ Hand your best tools to your best colleagues. Now they can properly refactor, na
|
|
|
522
522
|
- **lsp_code_action_resolve**: Apply code action
|
|
523
523
|
- **ast_grep_search**: AST-aware code pattern search (25 languages)
|
|
524
524
|
- **ast_grep_replace**: AST-aware code replacement
|
|
525
|
+
- **call_omo_agent**: Spawn specialized explore/librarian agents. Supports `run_in_background` parameter for async execution.
|
|
526
|
+
|
|
527
|
+
#### Session Management
|
|
528
|
+
|
|
529
|
+
Tools to navigate and search your OpenCode session history:
|
|
530
|
+
|
|
531
|
+
- **session_list**: List all OpenCode sessions with filtering by date and limit
|
|
532
|
+
- **session_read**: Read messages and history from a specific session
|
|
533
|
+
- **session_search**: Full-text search across session messages
|
|
534
|
+
- **session_info**: Get metadata and statistics about a session
|
|
535
|
+
|
|
536
|
+
These tools enable agents to reference previous conversations and maintain continuity across sessions.
|
|
525
537
|
|
|
526
538
|
#### Context Is All You Need
|
|
527
539
|
- **Directory AGENTS.md / README.md Injector**: Auto-injects `AGENTS.md` and `README.md` when reading files. Walks from file directory to project root, collecting **all** `AGENTS.md` files along the path. Supports nested directory-specific instructions:
|
|
@@ -674,6 +686,10 @@ When agents thrive, you thrive. But I want to help you directly too.
|
|
|
674
686
|
- **Empty Message Sanitizer**: Prevents API errors from empty chat messages by automatically sanitizing message content before sending.
|
|
675
687
|
- **Grep Output Truncator**: Grep can return mountains of text. This dynamically truncates output based on your remaining context window—keeps 50% headroom, caps at 50k tokens.
|
|
676
688
|
- **Tool Output Truncator**: Same idea, broader scope. Truncates output from Grep, Glob, LSP tools, and AST-grep. Prevents one verbose search from eating your entire context.
|
|
689
|
+
- **Preemptive Compaction**: Compacts session proactively before hitting hard token limits. Runs before you get into trouble.
|
|
690
|
+
- **Compaction Context Injector**: Preserves critical context (AGENTS.md, current directory info) during session compaction so you don't lose important state.
|
|
691
|
+
- **Thinking Block Validator**: Validates thinking blocks to ensure proper formatting and prevent API errors from malformed thinking content.
|
|
692
|
+
- **Claude Code Hooks**: Executes hooks from Claude Code's settings.json - this is the compatibility layer that runs PreToolUse/PostToolUse/UserPromptSubmit/Stop hooks.
|
|
677
693
|
|
|
678
694
|
## Configuration
|
|
679
695
|
|
|
@@ -888,7 +904,7 @@ Disable specific built-in hooks via `disabled_hooks` in `~/.config/opencode/oh-m
|
|
|
888
904
|
}
|
|
889
905
|
```
|
|
890
906
|
|
|
891
|
-
Available hooks: `todo-continuation-enforcer`, `context-window-monitor`, `session-recovery`, `session-notification`, `comment-checker`, `grep-output-truncator`, `tool-output-truncator`, `directory-agents-injector`, `directory-readme-injector`, `empty-task-response-detector`, `think-mode`, `anthropic-auto-compact`, `rules-injector`, `background-notification`, `auto-update-checker`, `startup-toast`, `keyword-detector`, `agent-usage-reminder`, `non-interactive-env`, `interactive-bash-session`, `empty-message-sanitizer`
|
|
907
|
+
Available hooks: `todo-continuation-enforcer`, `context-window-monitor`, `session-recovery`, `session-notification`, `comment-checker`, `grep-output-truncator`, `tool-output-truncator`, `directory-agents-injector`, `directory-readme-injector`, `empty-task-response-detector`, `think-mode`, `anthropic-auto-compact`, `rules-injector`, `background-notification`, `auto-update-checker`, `startup-toast`, `keyword-detector`, `agent-usage-reminder`, `non-interactive-env`, `interactive-bash-session`, `empty-message-sanitizer`, `preemptive-compaction`, `compaction-context-injector`, `thinking-block-validator`, `claude-code-hooks`
|
|
892
908
|
|
|
893
909
|
**Note on `auto-update-checker` and `startup-toast`**: The `startup-toast` hook is a sub-feature of `auto-update-checker`. To disable only the startup toast notification while keeping update checking enabled, add `"startup-toast"` to `disabled_hooks`. To disable all update checking features (including the toast), add `"auto-update-checker"` to `disabled_hooks`.
|
|
894
910
|
|
package/README.zh-cn.md
CHANGED
|
@@ -398,6 +398,39 @@ gh repo star code-yeongyu/oh-my-opencode
|
|
|
398
398
|
</details>
|
|
399
399
|
|
|
400
400
|
|
|
401
|
+
## 卸载
|
|
402
|
+
|
|
403
|
+
要移除 oh-my-opencode:
|
|
404
|
+
|
|
405
|
+
1. **从 OpenCode 配置中移除插件**
|
|
406
|
+
|
|
407
|
+
编辑 `~/.config/opencode/opencode.json` (或 `opencode.jsonc`),从 `plugin` 数组中移除 `"oh-my-opencode"`:
|
|
408
|
+
|
|
409
|
+
```bash
|
|
410
|
+
# 使用 jq 的示例
|
|
411
|
+
jq '.plugin = [.plugin[] | select(. != "oh-my-opencode")]' \
|
|
412
|
+
~/.config/opencode/opencode.json > /tmp/oc.json && \
|
|
413
|
+
mv /tmp/oc.json ~/.config/opencode/opencode.json
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
2. **删除配置文件 (可选)**
|
|
417
|
+
|
|
418
|
+
```bash
|
|
419
|
+
# 删除用户配置
|
|
420
|
+
rm -f ~/.config/opencode/oh-my-opencode.json
|
|
421
|
+
|
|
422
|
+
# 删除项目配置 (如果存在)
|
|
423
|
+
rm -f .opencode/oh-my-opencode.json
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
3. **确认移除**
|
|
427
|
+
|
|
428
|
+
```bash
|
|
429
|
+
opencode --version
|
|
430
|
+
# 插件不应再被加载
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
|
|
401
434
|
## 功能
|
|
402
435
|
|
|
403
436
|
### Agents:你的神队友
|
|
@@ -461,6 +494,18 @@ OhMyOpenCode 让这些成为可能。
|
|
|
461
494
|
- **lsp_code_action_resolve**:应用代码操作
|
|
462
495
|
- **ast_grep_search**:AST 感知代码搜索(支持 25 种语言)
|
|
463
496
|
- **ast_grep_replace**:AST 感知代码替换
|
|
497
|
+
- **call_omo_agent**: 产生专门的 explore/librarian Agent。支持用于异步执行的 `run_in_background` 参数。
|
|
498
|
+
|
|
499
|
+
#### 会话管理 (Session Management)
|
|
500
|
+
|
|
501
|
+
用于导航和搜索 OpenCode 会话历史的工具:
|
|
502
|
+
|
|
503
|
+
- **session_list**: 列出所有 OpenCode 会话,支持按日期和数量限制进行过滤
|
|
504
|
+
- **session_read**: 读取特定会话的消息和历史记录
|
|
505
|
+
- **session_search**: 在会话消息中进行全文搜索
|
|
506
|
+
- **session_info**: 获取有关会话的元数据和统计信息
|
|
507
|
+
|
|
508
|
+
这些工具使 Agent 能够引用之前的对话并保持跨会话的连续性。
|
|
464
509
|
|
|
465
510
|
#### 上下文就是一切 (Context is all you need)
|
|
466
511
|
- **Directory AGENTS.md / README.md 注入器**:读文件时自动把 `AGENTS.md` 和 `README.md` 塞进去。从当前目录一路往上找,路径上**所有** `AGENTS.md` 全都带上。支持嵌套指令:
|
|
@@ -620,7 +665,12 @@ Agent 爽了,你自然也爽。但我还想直接让你爽。
|
|
|
620
665
|
|
|
621
666
|
配置文件(优先级从高到低):
|
|
622
667
|
1. `.opencode/oh-my-opencode.json`(项目级)
|
|
623
|
-
2.
|
|
668
|
+
2. 用户配置(按平台):
|
|
669
|
+
|
|
670
|
+
| 平台 | 用户配置路径 |
|
|
671
|
+
|----------|------------------|
|
|
672
|
+
| **Windows** | `~/.config/opencode/oh-my-opencode.json` (首选) 或 `%APPDATA%\opencode\oh-my-opencode.json` (备选) |
|
|
673
|
+
| **macOS/Linux** | `~/.config/opencode/oh-my-opencode.json` |
|
|
624
674
|
|
|
625
675
|
支持 Schema 自动补全:
|
|
626
676
|
|
|
@@ -630,6 +680,36 @@ Agent 爽了,你自然也爽。但我还想直接让你爽。
|
|
|
630
680
|
}
|
|
631
681
|
```
|
|
632
682
|
|
|
683
|
+
### JSONC 支持
|
|
684
|
+
|
|
685
|
+
`oh-my-opencode` 配置文件支持 JSONC(带注释的 JSON):
|
|
686
|
+
- 行注释:`// 注释`
|
|
687
|
+
- 块注释:`/* 注释 */`
|
|
688
|
+
- 尾随逗号:`{ "key": "value", }`
|
|
689
|
+
|
|
690
|
+
当 `oh-my-opencode.jsonc` 和 `oh-my-opencode.json` 文件同时存在时,`.jsonc` 优先。
|
|
691
|
+
|
|
692
|
+
**带注释的示例:**
|
|
693
|
+
|
|
694
|
+
```jsonc
|
|
695
|
+
{
|
|
696
|
+
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-opencode/master/assets/oh-my-opencode.schema.json",
|
|
697
|
+
|
|
698
|
+
// 通过 Antigravity OAuth 启用 Google Gemini
|
|
699
|
+
"google_auth": false,
|
|
700
|
+
|
|
701
|
+
/* Agent 覆盖 - 为特定任务自定义模型 */
|
|
702
|
+
"agents": {
|
|
703
|
+
"oracle": {
|
|
704
|
+
"model": "openai/gpt-5.2" // 用于战略推理的 GPT
|
|
705
|
+
},
|
|
706
|
+
"explore": {
|
|
707
|
+
"model": "opencode/grok-code" // 快速且免费的搜索模型
|
|
708
|
+
},
|
|
709
|
+
},
|
|
710
|
+
}
|
|
711
|
+
```
|
|
712
|
+
|
|
633
713
|
### Google Auth
|
|
634
714
|
|
|
635
715
|
**强推**:用外部 [`opencode-antigravity-auth`](https://github.com/NoeFabris/opencode-antigravity-auth) 插件。多账号负载均衡、更多模型(包括 Antigravity 版 Claude)、有人维护。看 [安装 > Google Gemini](#42-google-gemini-antigravity-oauth)。
|
|
@@ -792,7 +872,7 @@ Sisyphus Agent 也能自定义:
|
|
|
792
872
|
}
|
|
793
873
|
```
|
|
794
874
|
|
|
795
|
-
可关的 hook:`todo-continuation-enforcer`、`context-window-monitor`、`session-recovery`、`session-notification`、`comment-checker`、`grep-output-truncator`、`tool-output-truncator`、`directory-agents-injector`、`directory-readme-injector`、`empty-task-response-detector`、`think-mode`、`anthropic-auto-compact`、`rules-injector`、`background-notification`、`auto-update-checker`、`startup-toast`、`keyword-detector`、`agent-usage-reminder`、`non-interactive-env`、`interactive-bash-session`、`empty-message-sanitizer`
|
|
875
|
+
可关的 hook:`todo-continuation-enforcer`、`context-window-monitor`、`session-recovery`、`session-notification`、`comment-checker`、`grep-output-truncator`、`tool-output-truncator`、`directory-agents-injector`、`directory-readme-injector`、`empty-task-response-detector`、`think-mode`、`anthropic-auto-compact`、`rules-injector`、`background-notification`、`auto-update-checker`、`startup-toast`、`keyword-detector`、`agent-usage-reminder`、`non-interactive-env`、`interactive-bash-session`、`empty-message-sanitizer`、`preemptive-compaction`、`compaction-context-injector`、`thinking-block-validator`、`claude-code-hooks`
|
|
796
876
|
|
|
797
877
|
**关于 `auto-update-checker` 和 `startup-toast`**: `startup-toast` hook 是 `auto-update-checker` 的子功能。若想保持更新检查但只禁用启动提示通知,在 `disabled_hooks` 中添加 `"startup-toast"`。若要禁用所有更新检查功能(包括提示),添加 `"auto-update-checker"`。
|
|
798
878
|
|
package/dist/cli/index.js
CHANGED
|
@@ -2244,7 +2244,7 @@ var require_picocolors = __commonJS((exports, module) => {
|
|
|
2244
2244
|
var require_package = __commonJS((exports, module) => {
|
|
2245
2245
|
module.exports = {
|
|
2246
2246
|
name: "oh-my-opencode",
|
|
2247
|
-
version: "2.
|
|
2247
|
+
version: "2.7.0",
|
|
2248
2248
|
description: "OpenCode plugin - custom agents (oracle, librarian) and enhanced features",
|
|
2249
2249
|
main: "dist/index.js",
|
|
2250
2250
|
types: "dist/index.d.ts",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const INIT_DEEP_TEMPLATE = "# Initialize Deep Knowledge Base\n\nGenerate comprehensive AGENTS.md files across project hierarchy. Combines root-level project knowledge (gen-knowledge) with complexity-based subdirectory documentation (gen-knowledge-deep).\n\n## Usage\n\n```\n/init-deep # Analyze and generate hierarchical AGENTS.md\n/init-deep --create-new # Force create from scratch (ignore existing)\n/init-deep --max-depth=2 # Limit to N directory levels (default: 3)\n```\n\n---\n\n## Core Principles\n\n- **Telegraphic Style**: Sacrifice grammar for concision (\"Project uses React\" \u2192 \"React 18\")\n- **Predict-then-Compare**: Predict standard \u2192 find actual \u2192 document ONLY deviations\n- **Hierarchy Aware**: Parent covers general, children cover specific\n- **No Redundancy**: Child AGENTS.md NEVER repeats parent content\n\n---\n\n## Process\n\n<critical>\n**MANDATORY: TodoWrite for ALL phases. Mark in_progress \u2192 completed in real-time.**\n</critical>\n\n### Phase 0: Initialize\n\n```\nTodoWrite([\n { id: \"p1-analysis\", content: \"Parallel project structure & complexity analysis\", status: \"pending\", priority: \"high\" },\n { id: \"p2-scoring\", content: \"Score directories, determine AGENTS.md locations\", status: \"pending\", priority: \"high\" },\n { id: \"p3-root\", content: \"Generate root AGENTS.md with Predict-then-Compare\", status: \"pending\", priority: \"high\" },\n { id: \"p4-subdirs\", content: \"Generate subdirectory AGENTS.md files in parallel\", status: \"pending\", priority: \"high\" },\n { id: \"p5-review\", content: \"Review, deduplicate, validate all files\", status: \"pending\", priority: \"medium\" }\n])\n```\n\n---\n\n## Phase 1: Parallel Project Analysis\n\n**Mark \"p1-analysis\" as in_progress.**\n\nLaunch **ALL tasks simultaneously**:\n\n<parallel-tasks>\n\n### Structural Analysis (bash - run in parallel)\n```bash\n# Task A: Directory depth analysis\nfind . -type d -not -path '*/\\.*' -not -path '*/node_modules/*' -not -path '*/venv/*' -not -path '*/__pycache__/*' -not -path '*/dist/*' -not -path '*/build/*' | awk -F/ '{print NF-1}' | sort -n | uniq -c\n\n# Task B: File count per directory \nfind . -type f -not -path '*/\\.*' -not -path '*/node_modules/*' -not -path '*/venv/*' -not -path '*/__pycache__/*' | sed 's|/[^/]*$||' | sort | uniq -c | sort -rn | head -30\n\n# Task C: Code concentration\nfind . -type f \\( -name \"*.py\" -o -name \"*.ts\" -o -name \"*.tsx\" -o -name \"*.js\" -o -name \"*.jsx\" -o -name \"*.go\" -o -name \"*.rs\" -o -name \"*.java\" \\) -not -path '*/node_modules/*' -not -path '*/venv/*' | sed 's|/[^/]*$||' | sort | uniq -c | sort -rn | head -20\n\n# Task D: Existing knowledge files\nfind . -type f \\( -name \"AGENTS.md\" -o -name \"CLAUDE.md\" \\) -not -path '*/node_modules/*' 2>/dev/null\n```\n\n### Context Gathering (Explore agents - background_task in parallel)\n\n```\nbackground_task(agent=\"explore\", prompt=\"Project structure: PREDICT standard {lang} patterns \u2192 FIND package.json/pyproject.toml/go.mod \u2192 REPORT deviations only\")\n\nbackground_task(agent=\"explore\", prompt=\"Entry points: PREDICT typical (main.py, index.ts) \u2192 FIND actual \u2192 REPORT non-standard organization\")\n\nbackground_task(agent=\"explore\", prompt=\"Conventions: FIND .cursor/rules, .cursorrules, eslintrc, pyproject.toml \u2192 REPORT project-specific rules DIFFERENT from defaults\")\n\nbackground_task(agent=\"explore\", prompt=\"Anti-patterns: FIND comments with 'DO NOT', 'NEVER', 'ALWAYS', 'LEGACY', 'DEPRECATED' \u2192 REPORT forbidden patterns\")\n\nbackground_task(agent=\"explore\", prompt=\"Build/CI: FIND .github/workflows, Makefile, justfile \u2192 REPORT non-standard build/deploy patterns\")\n\nbackground_task(agent=\"explore\", prompt=\"Test patterns: FIND pytest.ini, jest.config, test structure \u2192 REPORT unique testing conventions\")\n```\n\n</parallel-tasks>\n\n**Collect all results. Mark \"p1-analysis\" as completed.**\n\n---\n\n## Phase 2: Complexity Scoring & Location Decision\n\n**Mark \"p2-scoring\" as in_progress.**\n\n### Scoring Matrix\n\n| Factor | Weight | Threshold |\n|--------|--------|-----------|\n| File count | 3x | >20 files = high |\n| Subdirectory count | 2x | >5 subdirs = high |\n| Code file ratio | 2x | >70% code = high |\n| Unique patterns | 1x | Has own config |\n| Module boundary | 2x | Has __init__.py/index.ts |\n\n### Decision Rules\n\n| Score | Action |\n|-------|--------|\n| **Root (.)** | ALWAYS create AGENTS.md |\n| **High (>15)** | Create dedicated AGENTS.md |\n| **Medium (8-15)** | Create if distinct domain |\n| **Low (<8)** | Skip, parent sufficient |\n\n### Output Format\n\n```\nAGENTS_LOCATIONS = [\n { path: \".\", type: \"root\" },\n { path: \"src/api\", score: 18, reason: \"high complexity, 45 files\" },\n { path: \"src/hooks\", score: 12, reason: \"distinct domain, unique patterns\" },\n]\n```\n\n**Mark \"p2-scoring\" as completed.**\n\n---\n\n## Phase 3: Generate Root AGENTS.md\n\n**Mark \"p3-root\" as in_progress.**\n\nRoot AGENTS.md gets **full treatment** with Predict-then-Compare synthesis.\n\n### Required Sections\n\n```markdown\n# PROJECT KNOWLEDGE BASE\n\n**Generated:** {TIMESTAMP}\n**Commit:** {SHORT_SHA}\n**Branch:** {BRANCH}\n\n## OVERVIEW\n\n{1-2 sentences: what project does, core tech stack}\n\n## STRUCTURE\n\n\\`\\`\\`\n{project-root}/\n\u251C\u2500\u2500 {dir}/ # {non-obvious purpose only}\n\u2514\u2500\u2500 {entry} # entry point\n\\`\\`\\`\n\n## WHERE TO LOOK\n\n| Task | Location | Notes |\n|------|----------|-------|\n| Add feature X | \\`src/x/\\` | {pattern hint} |\n\n## CONVENTIONS\n\n{ONLY deviations from standard - skip generic advice}\n\n- **{rule}**: {specific detail}\n\n## ANTI-PATTERNS (THIS PROJECT)\n\n{Things explicitly forbidden HERE}\n\n- **{pattern}**: {why} \u2192 {alternative}\n\n## UNIQUE STYLES\n\n{Project-specific coding styles}\n\n- **{style}**: {how different}\n\n## COMMANDS\n\n\\`\\`\\`bash\n{dev-command}\n{test-command}\n{build-command}\n\\`\\`\\`\n\n## NOTES\n\n{Gotchas, non-obvious info}\n```\n\n### Quality Gates\n\n- [ ] Size: 50-150 lines\n- [ ] No generic advice (\"write clean code\")\n- [ ] No obvious info (\"tests/ has tests\")\n- [ ] Every item is project-specific\n\n**Mark \"p3-root\" as completed.**\n\n---\n\n## Phase 4: Generate Subdirectory AGENTS.md\n\n**Mark \"p4-subdirs\" as in_progress.**\n\nFor each location in AGENTS_LOCATIONS (except root), launch **parallel document-writer agents**:\n\n```typescript\nfor (const loc of AGENTS_LOCATIONS.filter(l => l.path !== \".\")) {\n background_task({\n agent: \"document-writer\",\n prompt: \\`\n Generate AGENTS.md for: ${loc.path}\n \n CONTEXT:\n - Complexity reason: ${loc.reason}\n - Parent AGENTS.md: ./AGENTS.md (already covers project overview)\n \n CRITICAL RULES:\n 1. Focus ONLY on this directory's specific context\n 2. NEVER repeat parent AGENTS.md content\n 3. Shorter is better - 30-80 lines max\n 4. Telegraphic style - sacrifice grammar\n \n REQUIRED SECTIONS:\n - OVERVIEW (1 line: what this directory does)\n - STRUCTURE (only if >5 subdirs)\n - WHERE TO LOOK (directory-specific tasks)\n - CONVENTIONS (only if DIFFERENT from root)\n - ANTI-PATTERNS (directory-specific only)\n \n OUTPUT: Write to ${loc.path}/AGENTS.md\n \\`\n })\n}\n```\n\n**Wait for all agents. Mark \"p4-subdirs\" as completed.**\n\n---\n\n## Phase 5: Review & Deduplicate\n\n**Mark \"p5-review\" as in_progress.**\n\n### Validation Checklist\n\nFor EACH generated AGENTS.md:\n\n| Check | Action if Fail |\n|-------|----------------|\n| Contains generic advice | REMOVE the line |\n| Repeats parent content | REMOVE the line |\n| Missing required section | ADD it |\n| Over 150 lines (root) / 80 lines (subdir) | TRIM |\n| Verbose explanations | REWRITE telegraphic |\n\n### Cross-Reference Validation\n\n```\nFor each child AGENTS.md:\n For each line in child:\n If similar line exists in parent:\n REMOVE from child (parent already covers)\n```\n\n**Mark \"p5-review\" as completed.**\n\n---\n\n## Final Report\n\n```\n=== init-deep Complete ===\n\nFiles Generated:\n \u2713 ./AGENTS.md (root, {N} lines)\n \u2713 ./src/hooks/AGENTS.md ({N} lines)\n \u2713 ./src/tools/AGENTS.md ({N} lines)\n\nDirectories Analyzed: {N}\nAGENTS.md Created: {N}\nTotal Lines: {N}\n\nHierarchy:\n ./AGENTS.md\n \u251C\u2500\u2500 src/hooks/AGENTS.md\n \u2514\u2500\u2500 src/tools/AGENTS.md\n```\n\n---\n\n## Anti-Patterns for THIS Command\n\n- **Over-documenting**: Not every directory needs AGENTS.md\n- **Redundancy**: Child must NOT repeat parent\n- **Generic content**: Remove anything that applies to ALL projects\n- **Sequential execution**: MUST use parallel agents\n- **Deep nesting**: Rarely need AGENTS.md at depth 4+\n- **Verbose style**: \"This directory contains...\" \u2192 just list it";
|
|
1
|
+
export declare const INIT_DEEP_TEMPLATE = "# Initialize Deep Knowledge Base\n\nGenerate comprehensive AGENTS.md files across project hierarchy. Combines root-level project knowledge (gen-knowledge) with complexity-based subdirectory documentation (gen-knowledge-deep).\n\n## Usage\n\n```\n/init-deep # Analyze and generate hierarchical AGENTS.md\n/init-deep --create-new # Force create from scratch (ignore existing)\n/init-deep --max-depth=2 # Limit to N directory levels (default: 3)\n```\n\n---\n\n## Core Principles\n\n- **Telegraphic Style**: Sacrifice grammar for concision (\"Project uses React\" \u2192 \"React 18\")\n- **Predict-then-Compare**: Predict standard \u2192 find actual \u2192 document ONLY deviations\n- **Hierarchy Aware**: Parent covers general, children cover specific\n- **No Redundancy**: Child AGENTS.md NEVER repeats parent content\n- **LSP-First**: Use LSP tools for accurate code intelligence when available (semantic > text search)\n\n---\n\n## Process\n\n<critical>\n**MANDATORY: TodoWrite for ALL phases. Mark in_progress \u2192 completed in real-time.**\n</critical>\n\n### Phase 0: Initialize\n\n```\nTodoWrite([\n { id: \"p1-analysis\", content: \"Parallel project structure & complexity analysis\", status: \"pending\", priority: \"high\" },\n { id: \"p2-scoring\", content: \"Score directories, determine AGENTS.md locations\", status: \"pending\", priority: \"high\" },\n { id: \"p3-root\", content: \"Generate root AGENTS.md with Predict-then-Compare\", status: \"pending\", priority: \"high\" },\n { id: \"p4-subdirs\", content: \"Generate subdirectory AGENTS.md files in parallel\", status: \"pending\", priority: \"high\" },\n { id: \"p5-review\", content: \"Review, deduplicate, validate all files\", status: \"pending\", priority: \"medium\" }\n])\n```\n\n---\n\n## Phase 1: Parallel Project Analysis\n\n**Mark \"p1-analysis\" as in_progress.**\n\nLaunch **ALL tasks simultaneously**:\n\n<parallel-tasks>\n\n### Structural Analysis (bash - run in parallel)\n```bash\n# Task A: Directory depth analysis\nfind . -type d -not -path '*/\\.*' -not -path '*/node_modules/*' -not -path '*/venv/*' -not -path '*/__pycache__/*' -not -path '*/dist/*' -not -path '*/build/*' | awk -F/ '{print NF-1}' | sort -n | uniq -c\n\n# Task B: File count per directory \nfind . -type f -not -path '*/\\.*' -not -path '*/node_modules/*' -not -path '*/venv/*' -not -path '*/__pycache__/*' | sed 's|/[^/]*$||' | sort | uniq -c | sort -rn | head -30\n\n# Task C: Code concentration\nfind . -type f \\( -name \"*.py\" -o -name \"*.ts\" -o -name \"*.tsx\" -o -name \"*.js\" -o -name \"*.jsx\" -o -name \"*.go\" -o -name \"*.rs\" -o -name \"*.java\" \\) -not -path '*/node_modules/*' -not -path '*/venv/*' | sed 's|/[^/]*$||' | sort | uniq -c | sort -rn | head -20\n\n# Task D: Existing knowledge files\nfind . -type f \\( -name \"AGENTS.md\" -o -name \"CLAUDE.md\" \\) -not -path '*/node_modules/*' 2>/dev/null\n```\n\n### Context Gathering (Explore agents - background_task in parallel)\n\n```\nbackground_task(agent=\"explore\", prompt=\"Project structure: PREDICT standard {lang} patterns \u2192 FIND package.json/pyproject.toml/go.mod \u2192 REPORT deviations only\")\n\nbackground_task(agent=\"explore\", prompt=\"Entry points: PREDICT typical (main.py, index.ts) \u2192 FIND actual \u2192 REPORT non-standard organization\")\n\nbackground_task(agent=\"explore\", prompt=\"Conventions: FIND .cursor/rules, .cursorrules, eslintrc, pyproject.toml \u2192 REPORT project-specific rules DIFFERENT from defaults\")\n\nbackground_task(agent=\"explore\", prompt=\"Anti-patterns: FIND comments with 'DO NOT', 'NEVER', 'ALWAYS', 'LEGACY', 'DEPRECATED' \u2192 REPORT forbidden patterns\")\n\nbackground_task(agent=\"explore\", prompt=\"Build/CI: FIND .github/workflows, Makefile, justfile \u2192 REPORT non-standard build/deploy patterns\")\n\nbackground_task(agent=\"explore\", prompt=\"Test patterns: FIND pytest.ini, jest.config, test structure \u2192 REPORT unique testing conventions\")\n```\n\n### Code Intelligence Analysis (LSP tools - run in parallel)\n\nLSP provides semantic understanding beyond text search. Use for accurate code mapping.\n\n```\n# Step 1: Check LSP availability\nlsp_servers() # Verify language server is available\n\n# Step 2: Analyze entry point files (run in parallel)\n# Find entry points first, then analyze each with lsp_document_symbols\nlsp_document_symbols(filePath=\"src/index.ts\") # Main entry\nlsp_document_symbols(filePath=\"src/main.py\") # Python entry\nlsp_document_symbols(filePath=\"cmd/main.go\") # Go entry\n\n# Step 3: Discover key symbols across workspace (run in parallel)\nlsp_workspace_symbols(filePath=\".\", query=\"class\") # All classes\nlsp_workspace_symbols(filePath=\".\", query=\"interface\") # All interfaces\nlsp_workspace_symbols(filePath=\".\", query=\"function\") # Top-level functions\nlsp_workspace_symbols(filePath=\".\", query=\"type\") # Type definitions\n\n# Step 4: Analyze symbol centrality (for top 5-10 key symbols)\n# High reference count = central/important concept\nlsp_find_references(filePath=\"src/index.ts\", line=X, character=Y) # Main export\n```\n\n#### LSP Analysis Output Format\n\n```\nCODE_INTELLIGENCE = {\n entry_points: [\n { file: \"src/index.ts\", exports: [\"Plugin\", \"createHook\"], symbol_count: 12 }\n ],\n key_symbols: [\n { name: \"Plugin\", type: \"class\", file: \"src/index.ts\", refs: 45, role: \"Central orchestrator\" },\n { name: \"createHook\", type: \"function\", file: \"src/utils.ts\", refs: 23, role: \"Hook factory\" }\n ],\n module_boundaries: [\n { dir: \"src/hooks\", exports: 21, imports_from: [\"shared/\"] },\n { dir: \"src/tools\", exports: 15, imports_from: [\"shared/\", \"hooks/\"] }\n ]\n}\n```\n\n<critical>\n**LSP Fallback**: If LSP unavailable (no server installed), skip this section and rely on explore agents + AST-grep patterns.\n</critical>\n\n</parallel-tasks>\n\n**Collect all results. Mark \"p1-analysis\" as completed.**\n\n---\n\n## Phase 2: Complexity Scoring & Location Decision\n\n**Mark \"p2-scoring\" as in_progress.**\n\n### Scoring Matrix\n\n| Factor | Weight | Threshold | Source |\n|--------|--------|-----------|--------|\n| File count | 3x | >20 files = high | bash |\n| Subdirectory count | 2x | >5 subdirs = high | bash |\n| Code file ratio | 2x | >70% code = high | bash |\n| Unique patterns | 1x | Has own config | explore |\n| Module boundary | 2x | Has __init__.py/index.ts | bash |\n| **Symbol density** | 2x | >30 symbols = high | LSP |\n| **Export count** | 2x | >10 exports = high | LSP |\n| **Reference centrality** | 3x | Symbols with >20 refs | LSP |\n\n<lsp-scoring>\n**LSP-Enhanced Scoring** (if available):\n\n```\nFor each directory in candidates:\n symbols = lsp_document_symbols(dir/index.ts or dir/__init__.py)\n \n symbol_score = len(symbols) > 30 ? 6 : len(symbols) > 15 ? 3 : 0\n export_score = count(exported symbols) > 10 ? 4 : 0\n \n # Check if this module is central (many things depend on it)\n for each exported symbol:\n refs = lsp_find_references(symbol)\n if refs > 20: centrality_score += 3\n \n total_score += symbol_score + export_score + centrality_score\n```\n</lsp-scoring>\n\n### Decision Rules\n\n| Score | Action |\n|-------|--------|\n| **Root (.)** | ALWAYS create AGENTS.md |\n| **High (>15)** | Create dedicated AGENTS.md |\n| **Medium (8-15)** | Create if distinct domain |\n| **Low (<8)** | Skip, parent sufficient |\n\n### Output Format\n\n```\nAGENTS_LOCATIONS = [\n { path: \".\", type: \"root\" },\n { path: \"src/api\", score: 18, reason: \"high complexity, 45 files\" },\n { path: \"src/hooks\", score: 12, reason: \"distinct domain, unique patterns\" },\n]\n```\n\n**Mark \"p2-scoring\" as completed.**\n\n---\n\n## Phase 3: Generate Root AGENTS.md\n\n**Mark \"p3-root\" as in_progress.**\n\nRoot AGENTS.md gets **full treatment** with Predict-then-Compare synthesis.\n\n### Required Sections\n\n```markdown\n# PROJECT KNOWLEDGE BASE\n\n**Generated:** {TIMESTAMP}\n**Commit:** {SHORT_SHA}\n**Branch:** {BRANCH}\n\n## OVERVIEW\n\n{1-2 sentences: what project does, core tech stack}\n\n## STRUCTURE\n\n\\`\\`\\`\n{project-root}/\n\u251C\u2500\u2500 {dir}/ # {non-obvious purpose only}\n\u2514\u2500\u2500 {entry} # entry point\n\\`\\`\\`\n\n## WHERE TO LOOK\n\n| Task | Location | Notes |\n|------|----------|-------|\n| Add feature X | \\`src/x/\\` | {pattern hint} |\n\n## CODE MAP\n\n{Generated from LSP analysis - shows key symbols and their relationships}\n\n| Symbol | Type | Location | Refs | Role |\n|--------|------|----------|------|------|\n| {MainClass} | Class | \\`src/index.ts\\` | {N} | {Central orchestrator} |\n| {createX} | Function | \\`src/utils.ts\\` | {N} | {Factory pattern} |\n| {Config} | Interface | \\`src/types.ts\\` | {N} | {Configuration contract} |\n\n### Module Dependencies\n\n\\`\\`\\`\n{entry} \u2500\u2500imports\u2500\u2500> {core/}\n \u2502 \u2502\n \u2514\u2500\u2500imports\u2500\u2500> {utils/} <\u2500\u2500imports\u2500\u2500 {features/}\n\\`\\`\\`\n\n<code-map-note>\n**Skip CODE MAP if**: LSP unavailable OR project too small (<10 files) OR no clear module boundaries.\n</code-map-note>\n\n## CONVENTIONS\n\n{ONLY deviations from standard - skip generic advice}\n\n- **{rule}**: {specific detail}\n\n## ANTI-PATTERNS (THIS PROJECT)\n\n{Things explicitly forbidden HERE}\n\n- **{pattern}**: {why} \u2192 {alternative}\n\n## UNIQUE STYLES\n\n{Project-specific coding styles}\n\n- **{style}**: {how different}\n\n## COMMANDS\n\n\\`\\`\\`bash\n{dev-command}\n{test-command}\n{build-command}\n\\`\\`\\`\n\n## NOTES\n\n{Gotchas, non-obvious info}\n```\n\n### Quality Gates\n\n- [ ] Size: 50-150 lines\n- [ ] No generic advice (\"write clean code\")\n- [ ] No obvious info (\"tests/ has tests\")\n- [ ] Every item is project-specific\n\n**Mark \"p3-root\" as completed.**\n\n---\n\n## Phase 4: Generate Subdirectory AGENTS.md\n\n**Mark \"p4-subdirs\" as in_progress.**\n\nFor each location in AGENTS_LOCATIONS (except root), launch **parallel document-writer agents**:\n\n```typescript\nfor (const loc of AGENTS_LOCATIONS.filter(l => l.path !== \".\")) {\n background_task({\n agent: \"document-writer\",\n prompt: \\`\n Generate AGENTS.md for: ${loc.path}\n \n CONTEXT:\n - Complexity reason: ${loc.reason}\n - Parent AGENTS.md: ./AGENTS.md (already covers project overview)\n \n CRITICAL RULES:\n 1. Focus ONLY on this directory's specific context\n 2. NEVER repeat parent AGENTS.md content\n 3. Shorter is better - 30-80 lines max\n 4. Telegraphic style - sacrifice grammar\n \n REQUIRED SECTIONS:\n - OVERVIEW (1 line: what this directory does)\n - STRUCTURE (only if >5 subdirs)\n - WHERE TO LOOK (directory-specific tasks)\n - CONVENTIONS (only if DIFFERENT from root)\n - ANTI-PATTERNS (directory-specific only)\n \n OUTPUT: Write to ${loc.path}/AGENTS.md\n \\`\n })\n}\n```\n\n**Wait for all agents. Mark \"p4-subdirs\" as completed.**\n\n---\n\n## Phase 5: Review & Deduplicate\n\n**Mark \"p5-review\" as in_progress.**\n\n### Validation Checklist\n\nFor EACH generated AGENTS.md:\n\n| Check | Action if Fail |\n|-------|----------------|\n| Contains generic advice | REMOVE the line |\n| Repeats parent content | REMOVE the line |\n| Missing required section | ADD it |\n| Over 150 lines (root) / 80 lines (subdir) | TRIM |\n| Verbose explanations | REWRITE telegraphic |\n\n### Cross-Reference Validation\n\n```\nFor each child AGENTS.md:\n For each line in child:\n If similar line exists in parent:\n REMOVE from child (parent already covers)\n```\n\n**Mark \"p5-review\" as completed.**\n\n---\n\n## Final Report\n\n```\n=== init-deep Complete ===\n\nFiles Generated:\n \u2713 ./AGENTS.md (root, {N} lines)\n \u2713 ./src/hooks/AGENTS.md ({N} lines)\n \u2713 ./src/tools/AGENTS.md ({N} lines)\n\nDirectories Analyzed: {N}\nAGENTS.md Created: {N}\nTotal Lines: {N}\n\nHierarchy:\n ./AGENTS.md\n \u251C\u2500\u2500 src/hooks/AGENTS.md\n \u2514\u2500\u2500 src/tools/AGENTS.md\n```\n\n---\n\n## Anti-Patterns for THIS Command\n\n- **Over-documenting**: Not every directory needs AGENTS.md\n- **Redundancy**: Child must NOT repeat parent\n- **Generic content**: Remove anything that applies to ALL projects\n- **Sequential execution**: MUST use parallel agents\n- **Deep nesting**: Rarely need AGENTS.md at depth 4+\n- **Verbose style**: \"This directory contains...\" \u2192 just list it\n- **Ignoring LSP**: If LSP available, USE IT - semantic analysis > text grep\n- **LSP without fallback**: Always have explore agent backup if LSP unavailable\n- **Over-referencing**: Don't trace refs for EVERY symbol - focus on exports only";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/index.js
CHANGED
|
@@ -4382,7 +4382,7 @@ Incomplete tasks remain in your todo list. Continue working on the next pending
|
|
|
4382
4382
|
- Do not stop until all tasks are done`;
|
|
4383
4383
|
var COUNTDOWN_SECONDS = 2;
|
|
4384
4384
|
var TOAST_DURATION_MS = 900;
|
|
4385
|
-
var
|
|
4385
|
+
var ERROR_COOLDOWN_MS = 3000;
|
|
4386
4386
|
function getMessageDir(sessionID) {
|
|
4387
4387
|
if (!existsSync6(MESSAGE_STORAGE))
|
|
4388
4388
|
return null;
|
|
@@ -4396,7 +4396,7 @@ function getMessageDir(sessionID) {
|
|
|
4396
4396
|
}
|
|
4397
4397
|
return null;
|
|
4398
4398
|
}
|
|
4399
|
-
function
|
|
4399
|
+
function isAbortError(error) {
|
|
4400
4400
|
if (!error)
|
|
4401
4401
|
return false;
|
|
4402
4402
|
if (typeof error === "object") {
|
|
@@ -4422,47 +4422,41 @@ function getIncompleteCount(todos) {
|
|
|
4422
4422
|
function createTodoContinuationEnforcer(ctx, options = {}) {
|
|
4423
4423
|
const { backgroundManager } = options;
|
|
4424
4424
|
const sessions = new Map;
|
|
4425
|
-
function
|
|
4425
|
+
function getState(sessionID) {
|
|
4426
4426
|
let state2 = sessions.get(sessionID);
|
|
4427
4427
|
if (!state2) {
|
|
4428
|
-
state2 = {
|
|
4428
|
+
state2 = {};
|
|
4429
4429
|
sessions.set(sessionID, state2);
|
|
4430
4430
|
}
|
|
4431
4431
|
return state2;
|
|
4432
4432
|
}
|
|
4433
|
-
function
|
|
4434
|
-
if (state2.timer) {
|
|
4435
|
-
clearTimeout(state2.timer);
|
|
4436
|
-
state2.timer = undefined;
|
|
4437
|
-
}
|
|
4438
|
-
}
|
|
4439
|
-
function invalidate(sessionID, reason) {
|
|
4433
|
+
function cancelCountdown(sessionID) {
|
|
4440
4434
|
const state2 = sessions.get(sessionID);
|
|
4441
4435
|
if (!state2)
|
|
4442
4436
|
return;
|
|
4443
|
-
if (state2.
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
if (state2.
|
|
4448
|
-
|
|
4449
|
-
state2.
|
|
4437
|
+
if (state2.countdownTimer) {
|
|
4438
|
+
clearTimeout(state2.countdownTimer);
|
|
4439
|
+
state2.countdownTimer = undefined;
|
|
4440
|
+
}
|
|
4441
|
+
if (state2.countdownInterval) {
|
|
4442
|
+
clearInterval(state2.countdownInterval);
|
|
4443
|
+
state2.countdownInterval = undefined;
|
|
4450
4444
|
}
|
|
4451
4445
|
}
|
|
4452
|
-
function
|
|
4453
|
-
|
|
4454
|
-
|
|
4446
|
+
function cleanup(sessionID) {
|
|
4447
|
+
cancelCountdown(sessionID);
|
|
4448
|
+
sessions.delete(sessionID);
|
|
4455
4449
|
}
|
|
4456
4450
|
const markRecovering = (sessionID) => {
|
|
4457
|
-
const state2 =
|
|
4458
|
-
|
|
4459
|
-
|
|
4451
|
+
const state2 = getState(sessionID);
|
|
4452
|
+
state2.isRecovering = true;
|
|
4453
|
+
cancelCountdown(sessionID);
|
|
4460
4454
|
log(`[${HOOK_NAME}] Session marked as recovering`, { sessionID });
|
|
4461
4455
|
};
|
|
4462
4456
|
const markRecoveryComplete = (sessionID) => {
|
|
4463
4457
|
const state2 = sessions.get(sessionID);
|
|
4464
|
-
if (state2
|
|
4465
|
-
state2.
|
|
4458
|
+
if (state2) {
|
|
4459
|
+
state2.isRecovering = false;
|
|
4466
4460
|
log(`[${HOOK_NAME}] Session recovery complete`, { sessionID });
|
|
4467
4461
|
}
|
|
4468
4462
|
};
|
|
@@ -4476,101 +4470,51 @@ function createTodoContinuationEnforcer(ctx, options = {}) {
|
|
|
4476
4470
|
}
|
|
4477
4471
|
}).catch(() => {});
|
|
4478
4472
|
}
|
|
4479
|
-
async function
|
|
4473
|
+
async function injectContinuation(sessionID, incompleteCount, total) {
|
|
4480
4474
|
const state2 = sessions.get(sessionID);
|
|
4481
|
-
if (
|
|
4482
|
-
|
|
4483
|
-
if (state2.version !== capturedVersion) {
|
|
4484
|
-
log(`[${HOOK_NAME}] Injection aborted: version mismatch`, {
|
|
4485
|
-
sessionID,
|
|
4486
|
-
capturedVersion,
|
|
4487
|
-
currentVersion: state2.version
|
|
4488
|
-
});
|
|
4475
|
+
if (state2?.isRecovering) {
|
|
4476
|
+
log(`[${HOOK_NAME}] Skipped injection: in recovery`, { sessionID });
|
|
4489
4477
|
return;
|
|
4490
4478
|
}
|
|
4491
|
-
if (state2.
|
|
4492
|
-
log(`[${HOOK_NAME}]
|
|
4493
|
-
sessionID,
|
|
4494
|
-
mode: state2.mode
|
|
4495
|
-
});
|
|
4479
|
+
if (state2?.lastErrorAt && Date.now() - state2.lastErrorAt < ERROR_COOLDOWN_MS) {
|
|
4480
|
+
log(`[${HOOK_NAME}] Skipped injection: recent error`, { sessionID });
|
|
4496
4481
|
return;
|
|
4497
4482
|
}
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
sessionID,
|
|
4503
|
-
elapsedMs: elapsed,
|
|
4504
|
-
minIntervalMs: MIN_INJECTION_INTERVAL_MS
|
|
4505
|
-
});
|
|
4506
|
-
state2.mode = "idle";
|
|
4507
|
-
return;
|
|
4508
|
-
}
|
|
4483
|
+
const hasRunningBgTasks = backgroundManager ? backgroundManager.getTasksByParentSession(sessionID).some((t) => t.status === "running") : false;
|
|
4484
|
+
if (hasRunningBgTasks) {
|
|
4485
|
+
log(`[${HOOK_NAME}] Skipped injection: background tasks running`, { sessionID });
|
|
4486
|
+
return;
|
|
4509
4487
|
}
|
|
4510
|
-
state2.mode = "injecting";
|
|
4511
4488
|
let todos = [];
|
|
4512
4489
|
try {
|
|
4513
4490
|
const response = await ctx.client.session.todo({ path: { id: sessionID } });
|
|
4514
4491
|
todos = response.data ?? response;
|
|
4515
4492
|
} catch (err) {
|
|
4516
|
-
log(`[${HOOK_NAME}] Failed to fetch todos
|
|
4517
|
-
state2.mode = "idle";
|
|
4518
|
-
return;
|
|
4519
|
-
}
|
|
4520
|
-
if (state2.version !== capturedVersion) {
|
|
4521
|
-
log(`[${HOOK_NAME}] Injection aborted after todo fetch: version mismatch`, { sessionID });
|
|
4522
|
-
state2.mode = "idle";
|
|
4493
|
+
log(`[${HOOK_NAME}] Failed to fetch todos`, { sessionID, error: String(err) });
|
|
4523
4494
|
return;
|
|
4524
4495
|
}
|
|
4525
|
-
const
|
|
4526
|
-
if (
|
|
4527
|
-
log(`[${HOOK_NAME}]
|
|
4528
|
-
state2.mode = "idle";
|
|
4529
|
-
return;
|
|
4530
|
-
}
|
|
4531
|
-
const hasRunningBgTasks = backgroundManager ? backgroundManager.getTasksByParentSession(sessionID).some((t) => t.status === "running") : false;
|
|
4532
|
-
if (hasRunningBgTasks) {
|
|
4533
|
-
log(`[${HOOK_NAME}] Skipped: background tasks still running`, { sessionID });
|
|
4534
|
-
state2.mode = "idle";
|
|
4496
|
+
const freshIncompleteCount = getIncompleteCount(todos);
|
|
4497
|
+
if (freshIncompleteCount === 0) {
|
|
4498
|
+
log(`[${HOOK_NAME}] Skipped injection: no incomplete todos`, { sessionID });
|
|
4535
4499
|
return;
|
|
4536
4500
|
}
|
|
4537
4501
|
const messageDir = getMessageDir(sessionID);
|
|
4538
4502
|
const prevMessage = messageDir ? findNearestMessageWithFields(messageDir) : null;
|
|
4539
|
-
const
|
|
4540
|
-
if (!
|
|
4541
|
-
log(`[${HOOK_NAME}] Skipped: agent lacks write permission`, {
|
|
4542
|
-
sessionID,
|
|
4543
|
-
agent: prevMessage?.agent,
|
|
4544
|
-
tools: prevMessage?.tools
|
|
4545
|
-
});
|
|
4546
|
-
state2.mode = "idle";
|
|
4503
|
+
const hasWritePermission = !prevMessage?.tools || prevMessage.tools.write !== false && prevMessage.tools.edit !== false;
|
|
4504
|
+
if (!hasWritePermission) {
|
|
4505
|
+
log(`[${HOOK_NAME}] Skipped: agent lacks write permission`, { sessionID, agent: prevMessage?.agent });
|
|
4547
4506
|
return;
|
|
4548
4507
|
}
|
|
4549
4508
|
const agentName = prevMessage?.agent?.toLowerCase() ?? "";
|
|
4550
|
-
|
|
4551
|
-
|
|
4552
|
-
log(`[${HOOK_NAME}] Skipped: plan mode agent detected`, {
|
|
4553
|
-
sessionID,
|
|
4554
|
-
agent: prevMessage?.agent
|
|
4555
|
-
});
|
|
4556
|
-
state2.mode = "idle";
|
|
4509
|
+
if (agentName === "plan" || agentName === "planner-sisyphus") {
|
|
4510
|
+
log(`[${HOOK_NAME}] Skipped: plan mode agent`, { sessionID, agent: prevMessage?.agent });
|
|
4557
4511
|
return;
|
|
4558
4512
|
}
|
|
4559
4513
|
const prompt = `${CONTINUATION_PROMPT}
|
|
4560
4514
|
|
|
4561
|
-
[Status: ${todos.length -
|
|
4562
|
-
if (state2.version !== capturedVersion) {
|
|
4563
|
-
log(`[${HOOK_NAME}] Injection aborted: version changed before API call`, { sessionID });
|
|
4564
|
-
state2.mode = "idle";
|
|
4565
|
-
return;
|
|
4566
|
-
}
|
|
4567
|
-
state2.lastAttemptedAt = Date.now();
|
|
4515
|
+
[Status: ${todos.length - freshIncompleteCount}/${todos.length} completed, ${freshIncompleteCount} remaining]`;
|
|
4568
4516
|
try {
|
|
4569
|
-
log(`[${HOOK_NAME}] Injecting continuation
|
|
4570
|
-
sessionID,
|
|
4571
|
-
agent: prevMessage?.agent,
|
|
4572
|
-
incompleteCount
|
|
4573
|
-
});
|
|
4517
|
+
log(`[${HOOK_NAME}] Injecting continuation`, { sessionID, agent: prevMessage?.agent, incompleteCount: freshIncompleteCount });
|
|
4574
4518
|
await ctx.client.session.prompt({
|
|
4575
4519
|
path: { id: sessionID },
|
|
4576
4520
|
body: {
|
|
@@ -4579,41 +4523,27 @@ function createTodoContinuationEnforcer(ctx, options = {}) {
|
|
|
4579
4523
|
},
|
|
4580
4524
|
query: { directory: ctx.directory }
|
|
4581
4525
|
});
|
|
4582
|
-
log(`[${HOOK_NAME}]
|
|
4526
|
+
log(`[${HOOK_NAME}] Injection successful`, { sessionID });
|
|
4583
4527
|
} catch (err) {
|
|
4584
|
-
log(`[${HOOK_NAME}]
|
|
4528
|
+
log(`[${HOOK_NAME}] Injection failed`, { sessionID, error: String(err) });
|
|
4585
4529
|
}
|
|
4586
|
-
state2.mode = "idle";
|
|
4587
4530
|
}
|
|
4588
|
-
function startCountdown(sessionID, incompleteCount) {
|
|
4589
|
-
const state2 =
|
|
4590
|
-
|
|
4591
|
-
state2.version++;
|
|
4592
|
-
state2.mode = "countingDown";
|
|
4593
|
-
const capturedVersion = state2.version;
|
|
4594
|
-
log(`[${HOOK_NAME}] Starting countdown`, {
|
|
4595
|
-
sessionID,
|
|
4596
|
-
seconds: COUNTDOWN_SECONDS,
|
|
4597
|
-
version: capturedVersion,
|
|
4598
|
-
incompleteCount
|
|
4599
|
-
});
|
|
4600
|
-
showCountdownToast(COUNTDOWN_SECONDS, incompleteCount);
|
|
4531
|
+
function startCountdown(sessionID, incompleteCount, total) {
|
|
4532
|
+
const state2 = getState(sessionID);
|
|
4533
|
+
cancelCountdown(sessionID);
|
|
4601
4534
|
let secondsRemaining = COUNTDOWN_SECONDS;
|
|
4602
|
-
|
|
4603
|
-
|
|
4604
|
-
clearInterval(toastInterval);
|
|
4605
|
-
return;
|
|
4606
|
-
}
|
|
4535
|
+
showCountdownToast(secondsRemaining, incompleteCount);
|
|
4536
|
+
state2.countdownInterval = setInterval(() => {
|
|
4607
4537
|
secondsRemaining--;
|
|
4608
4538
|
if (secondsRemaining > 0) {
|
|
4609
4539
|
showCountdownToast(secondsRemaining, incompleteCount);
|
|
4610
4540
|
}
|
|
4611
4541
|
}, 1000);
|
|
4612
|
-
state2.
|
|
4613
|
-
|
|
4614
|
-
|
|
4615
|
-
executeInjection(sessionID, capturedVersion);
|
|
4542
|
+
state2.countdownTimer = setTimeout(() => {
|
|
4543
|
+
cancelCountdown(sessionID);
|
|
4544
|
+
injectContinuation(sessionID, incompleteCount, total);
|
|
4616
4545
|
}, COUNTDOWN_SECONDS * 1000);
|
|
4546
|
+
log(`[${HOOK_NAME}] Countdown started`, { sessionID, seconds: COUNTDOWN_SECONDS, incompleteCount });
|
|
4617
4547
|
}
|
|
4618
4548
|
const handler = async ({ event }) => {
|
|
4619
4549
|
const props = event.properties;
|
|
@@ -4621,33 +4551,34 @@ function createTodoContinuationEnforcer(ctx, options = {}) {
|
|
|
4621
4551
|
const sessionID = props?.sessionID;
|
|
4622
4552
|
if (!sessionID)
|
|
4623
4553
|
return;
|
|
4624
|
-
const
|
|
4625
|
-
|
|
4626
|
-
|
|
4627
|
-
|
|
4628
|
-
log(`[${HOOK_NAME}] session.error received`, { sessionID, isInterrupt, error: props?.error });
|
|
4554
|
+
const state2 = getState(sessionID);
|
|
4555
|
+
state2.lastErrorAt = Date.now();
|
|
4556
|
+
cancelCountdown(sessionID);
|
|
4557
|
+
log(`[${HOOK_NAME}] session.error`, { sessionID, isAbort: isAbortError(props?.error) });
|
|
4629
4558
|
return;
|
|
4630
4559
|
}
|
|
4631
4560
|
if (event.type === "session.idle") {
|
|
4632
4561
|
const sessionID = props?.sessionID;
|
|
4633
4562
|
if (!sessionID)
|
|
4634
4563
|
return;
|
|
4635
|
-
log(`[${HOOK_NAME}] session.idle
|
|
4636
|
-
|
|
4564
|
+
log(`[${HOOK_NAME}] session.idle`, { sessionID });
|
|
4565
|
+
const mainSessionID2 = getMainSessionID();
|
|
4566
|
+
if (mainSessionID2 && sessionID !== mainSessionID2) {
|
|
4637
4567
|
log(`[${HOOK_NAME}] Skipped: not main session`, { sessionID });
|
|
4638
4568
|
return;
|
|
4639
4569
|
}
|
|
4640
|
-
const state2 =
|
|
4641
|
-
if (state2.
|
|
4642
|
-
log(`[${HOOK_NAME}] Skipped:
|
|
4570
|
+
const state2 = getState(sessionID);
|
|
4571
|
+
if (state2.isRecovering) {
|
|
4572
|
+
log(`[${HOOK_NAME}] Skipped: in recovery`, { sessionID });
|
|
4643
4573
|
return;
|
|
4644
4574
|
}
|
|
4645
|
-
if (state2.
|
|
4646
|
-
log(`[${HOOK_NAME}] Skipped: error
|
|
4575
|
+
if (state2.lastErrorAt && Date.now() - state2.lastErrorAt < ERROR_COOLDOWN_MS) {
|
|
4576
|
+
log(`[${HOOK_NAME}] Skipped: recent error (cooldown)`, { sessionID });
|
|
4647
4577
|
return;
|
|
4648
4578
|
}
|
|
4649
|
-
|
|
4650
|
-
|
|
4579
|
+
const hasRunningBgTasks = backgroundManager ? backgroundManager.getTasksByParentSession(sessionID).some((t) => t.status === "running") : false;
|
|
4580
|
+
if (hasRunningBgTasks) {
|
|
4581
|
+
log(`[${HOOK_NAME}] Skipped: background tasks running`, { sessionID });
|
|
4651
4582
|
return;
|
|
4652
4583
|
}
|
|
4653
4584
|
let todos = [];
|
|
@@ -4655,54 +4586,37 @@ function createTodoContinuationEnforcer(ctx, options = {}) {
|
|
|
4655
4586
|
const response = await ctx.client.session.todo({ path: { id: sessionID } });
|
|
4656
4587
|
todos = response.data ?? response;
|
|
4657
4588
|
} catch (err) {
|
|
4658
|
-
log(`[${HOOK_NAME}] Todo
|
|
4589
|
+
log(`[${HOOK_NAME}] Todo fetch failed`, { sessionID, error: String(err) });
|
|
4659
4590
|
return;
|
|
4660
4591
|
}
|
|
4661
4592
|
if (!todos || todos.length === 0) {
|
|
4662
|
-
log(`[${HOOK_NAME}] No todos
|
|
4593
|
+
log(`[${HOOK_NAME}] No todos`, { sessionID });
|
|
4663
4594
|
return;
|
|
4664
4595
|
}
|
|
4665
4596
|
const incompleteCount = getIncompleteCount(todos);
|
|
4666
4597
|
if (incompleteCount === 0) {
|
|
4667
|
-
log(`[${HOOK_NAME}] All todos
|
|
4598
|
+
log(`[${HOOK_NAME}] All todos complete`, { sessionID, total: todos.length });
|
|
4668
4599
|
return;
|
|
4669
4600
|
}
|
|
4670
|
-
|
|
4671
|
-
if (hasRunningBgTasks) {
|
|
4672
|
-
log(`[${HOOK_NAME}] Skipped: background tasks still running`, { sessionID });
|
|
4673
|
-
return;
|
|
4674
|
-
}
|
|
4675
|
-
log(`[${HOOK_NAME}] Found incomplete todos`, {
|
|
4676
|
-
sessionID,
|
|
4677
|
-
incomplete: incompleteCount,
|
|
4678
|
-
total: todos.length
|
|
4679
|
-
});
|
|
4680
|
-
startCountdown(sessionID, incompleteCount);
|
|
4601
|
+
startCountdown(sessionID, incompleteCount, todos.length);
|
|
4681
4602
|
return;
|
|
4682
4603
|
}
|
|
4683
4604
|
if (event.type === "message.updated") {
|
|
4684
4605
|
const info = props?.info;
|
|
4685
4606
|
const sessionID = info?.sessionID;
|
|
4686
4607
|
const role = info?.role;
|
|
4687
|
-
const finish = info?.finish;
|
|
4688
4608
|
if (!sessionID)
|
|
4689
4609
|
return;
|
|
4690
4610
|
if (role === "user") {
|
|
4691
4611
|
const state2 = sessions.get(sessionID);
|
|
4692
|
-
if (state2
|
|
4693
|
-
state2.
|
|
4694
|
-
log(`[${HOOK_NAME}] User message cleared errorBypass mode`, { sessionID });
|
|
4612
|
+
if (state2) {
|
|
4613
|
+
state2.lastErrorAt = undefined;
|
|
4695
4614
|
}
|
|
4696
|
-
|
|
4697
|
-
|
|
4615
|
+
cancelCountdown(sessionID);
|
|
4616
|
+
log(`[${HOOK_NAME}] User message: cleared error state`, { sessionID });
|
|
4698
4617
|
}
|
|
4699
|
-
if (role === "assistant"
|
|
4700
|
-
|
|
4701
|
-
return;
|
|
4702
|
-
}
|
|
4703
|
-
if (role === "assistant" && finish) {
|
|
4704
|
-
log(`[${HOOK_NAME}] Assistant turn finished`, { sessionID, finish });
|
|
4705
|
-
return;
|
|
4618
|
+
if (role === "assistant") {
|
|
4619
|
+
cancelCountdown(sessionID);
|
|
4706
4620
|
}
|
|
4707
4621
|
return;
|
|
4708
4622
|
}
|
|
@@ -4711,26 +4625,22 @@ function createTodoContinuationEnforcer(ctx, options = {}) {
|
|
|
4711
4625
|
const sessionID = info?.sessionID;
|
|
4712
4626
|
const role = info?.role;
|
|
4713
4627
|
if (sessionID && role === "assistant") {
|
|
4714
|
-
|
|
4628
|
+
cancelCountdown(sessionID);
|
|
4715
4629
|
}
|
|
4716
4630
|
return;
|
|
4717
4631
|
}
|
|
4718
4632
|
if (event.type === "tool.execute.before" || event.type === "tool.execute.after") {
|
|
4719
4633
|
const sessionID = props?.sessionID;
|
|
4720
4634
|
if (sessionID) {
|
|
4721
|
-
|
|
4635
|
+
cancelCountdown(sessionID);
|
|
4722
4636
|
}
|
|
4723
4637
|
return;
|
|
4724
4638
|
}
|
|
4725
4639
|
if (event.type === "session.deleted") {
|
|
4726
4640
|
const sessionInfo = props?.info;
|
|
4727
4641
|
if (sessionInfo?.id) {
|
|
4728
|
-
|
|
4729
|
-
|
|
4730
|
-
clearTimer(state2);
|
|
4731
|
-
}
|
|
4732
|
-
sessions.delete(sessionInfo.id);
|
|
4733
|
-
log(`[${HOOK_NAME}] Session deleted, state cleaned up`, { sessionID: sessionInfo.id });
|
|
4642
|
+
cleanup(sessionInfo.id);
|
|
4643
|
+
log(`[${HOOK_NAME}] Session deleted: cleaned up`, { sessionID: sessionInfo.id });
|
|
4734
4644
|
}
|
|
4735
4645
|
return;
|
|
4736
4646
|
}
|
|
@@ -11080,8 +10990,11 @@ function createEmptyMessageSanitizerHook() {
|
|
|
11080
10990
|
return {
|
|
11081
10991
|
"experimental.chat.messages.transform": async (_input, output) => {
|
|
11082
10992
|
const { messages } = output;
|
|
11083
|
-
for (
|
|
11084
|
-
|
|
10993
|
+
for (let i = 0;i < messages.length; i++) {
|
|
10994
|
+
const message = messages[i];
|
|
10995
|
+
const isLastMessage = i === messages.length - 1;
|
|
10996
|
+
const isAssistant = message.info.role === "assistant";
|
|
10997
|
+
if (isLastMessage && isAssistant)
|
|
11085
10998
|
continue;
|
|
11086
10999
|
const parts = message.parts;
|
|
11087
11000
|
if (!hasValidContent(parts)) {
|
|
@@ -13135,6 +13048,7 @@ Generate comprehensive AGENTS.md files across project hierarchy. Combines root-l
|
|
|
13135
13048
|
- **Predict-then-Compare**: Predict standard \u2192 find actual \u2192 document ONLY deviations
|
|
13136
13049
|
- **Hierarchy Aware**: Parent covers general, children cover specific
|
|
13137
13050
|
- **No Redundancy**: Child AGENTS.md NEVER repeats parent content
|
|
13051
|
+
- **LSP-First**: Use LSP tools for accurate code intelligence when available (semantic > text search)
|
|
13138
13052
|
|
|
13139
13053
|
---
|
|
13140
13054
|
|
|
@@ -13197,6 +13111,53 @@ background_task(agent="explore", prompt="Build/CI: FIND .github/workflows, Makef
|
|
|
13197
13111
|
background_task(agent="explore", prompt="Test patterns: FIND pytest.ini, jest.config, test structure \u2192 REPORT unique testing conventions")
|
|
13198
13112
|
\`\`\`
|
|
13199
13113
|
|
|
13114
|
+
### Code Intelligence Analysis (LSP tools - run in parallel)
|
|
13115
|
+
|
|
13116
|
+
LSP provides semantic understanding beyond text search. Use for accurate code mapping.
|
|
13117
|
+
|
|
13118
|
+
\`\`\`
|
|
13119
|
+
# Step 1: Check LSP availability
|
|
13120
|
+
lsp_servers() # Verify language server is available
|
|
13121
|
+
|
|
13122
|
+
# Step 2: Analyze entry point files (run in parallel)
|
|
13123
|
+
# Find entry points first, then analyze each with lsp_document_symbols
|
|
13124
|
+
lsp_document_symbols(filePath="src/index.ts") # Main entry
|
|
13125
|
+
lsp_document_symbols(filePath="src/main.py") # Python entry
|
|
13126
|
+
lsp_document_symbols(filePath="cmd/main.go") # Go entry
|
|
13127
|
+
|
|
13128
|
+
# Step 3: Discover key symbols across workspace (run in parallel)
|
|
13129
|
+
lsp_workspace_symbols(filePath=".", query="class") # All classes
|
|
13130
|
+
lsp_workspace_symbols(filePath=".", query="interface") # All interfaces
|
|
13131
|
+
lsp_workspace_symbols(filePath=".", query="function") # Top-level functions
|
|
13132
|
+
lsp_workspace_symbols(filePath=".", query="type") # Type definitions
|
|
13133
|
+
|
|
13134
|
+
# Step 4: Analyze symbol centrality (for top 5-10 key symbols)
|
|
13135
|
+
# High reference count = central/important concept
|
|
13136
|
+
lsp_find_references(filePath="src/index.ts", line=X, character=Y) # Main export
|
|
13137
|
+
\`\`\`
|
|
13138
|
+
|
|
13139
|
+
#### LSP Analysis Output Format
|
|
13140
|
+
|
|
13141
|
+
\`\`\`
|
|
13142
|
+
CODE_INTELLIGENCE = {
|
|
13143
|
+
entry_points: [
|
|
13144
|
+
{ file: "src/index.ts", exports: ["Plugin", "createHook"], symbol_count: 12 }
|
|
13145
|
+
],
|
|
13146
|
+
key_symbols: [
|
|
13147
|
+
{ name: "Plugin", type: "class", file: "src/index.ts", refs: 45, role: "Central orchestrator" },
|
|
13148
|
+
{ name: "createHook", type: "function", file: "src/utils.ts", refs: 23, role: "Hook factory" }
|
|
13149
|
+
],
|
|
13150
|
+
module_boundaries: [
|
|
13151
|
+
{ dir: "src/hooks", exports: 21, imports_from: ["shared/"] },
|
|
13152
|
+
{ dir: "src/tools", exports: 15, imports_from: ["shared/", "hooks/"] }
|
|
13153
|
+
]
|
|
13154
|
+
}
|
|
13155
|
+
\`\`\`
|
|
13156
|
+
|
|
13157
|
+
<critical>
|
|
13158
|
+
**LSP Fallback**: If LSP unavailable (no server installed), skip this section and rely on explore agents + AST-grep patterns.
|
|
13159
|
+
</critical>
|
|
13160
|
+
|
|
13200
13161
|
</parallel-tasks>
|
|
13201
13162
|
|
|
13202
13163
|
**Collect all results. Mark "p1-analysis" as completed.**
|
|
@@ -13209,13 +13170,35 @@ background_task(agent="explore", prompt="Test patterns: FIND pytest.ini, jest.co
|
|
|
13209
13170
|
|
|
13210
13171
|
### Scoring Matrix
|
|
13211
13172
|
|
|
13212
|
-
| Factor | Weight | Threshold |
|
|
13213
|
-
|
|
13214
|
-
| File count | 3x | >20 files = high |
|
|
13215
|
-
| Subdirectory count | 2x | >5 subdirs = high |
|
|
13216
|
-
| Code file ratio | 2x | >70% code = high |
|
|
13217
|
-
| Unique patterns | 1x | Has own config |
|
|
13218
|
-
| Module boundary | 2x | Has __init__.py/index.ts |
|
|
13173
|
+
| Factor | Weight | Threshold | Source |
|
|
13174
|
+
|--------|--------|-----------|--------|
|
|
13175
|
+
| File count | 3x | >20 files = high | bash |
|
|
13176
|
+
| Subdirectory count | 2x | >5 subdirs = high | bash |
|
|
13177
|
+
| Code file ratio | 2x | >70% code = high | bash |
|
|
13178
|
+
| Unique patterns | 1x | Has own config | explore |
|
|
13179
|
+
| Module boundary | 2x | Has __init__.py/index.ts | bash |
|
|
13180
|
+
| **Symbol density** | 2x | >30 symbols = high | LSP |
|
|
13181
|
+
| **Export count** | 2x | >10 exports = high | LSP |
|
|
13182
|
+
| **Reference centrality** | 3x | Symbols with >20 refs | LSP |
|
|
13183
|
+
|
|
13184
|
+
<lsp-scoring>
|
|
13185
|
+
**LSP-Enhanced Scoring** (if available):
|
|
13186
|
+
|
|
13187
|
+
\`\`\`
|
|
13188
|
+
For each directory in candidates:
|
|
13189
|
+
symbols = lsp_document_symbols(dir/index.ts or dir/__init__.py)
|
|
13190
|
+
|
|
13191
|
+
symbol_score = len(symbols) > 30 ? 6 : len(symbols) > 15 ? 3 : 0
|
|
13192
|
+
export_score = count(exported symbols) > 10 ? 4 : 0
|
|
13193
|
+
|
|
13194
|
+
# Check if this module is central (many things depend on it)
|
|
13195
|
+
for each exported symbol:
|
|
13196
|
+
refs = lsp_find_references(symbol)
|
|
13197
|
+
if refs > 20: centrality_score += 3
|
|
13198
|
+
|
|
13199
|
+
total_score += symbol_score + export_score + centrality_score
|
|
13200
|
+
\`\`\`
|
|
13201
|
+
</lsp-scoring>
|
|
13219
13202
|
|
|
13220
13203
|
### Decision Rules
|
|
13221
13204
|
|
|
@@ -13273,6 +13256,28 @@ Root AGENTS.md gets **full treatment** with Predict-then-Compare synthesis.
|
|
|
13273
13256
|
|------|----------|-------|
|
|
13274
13257
|
| Add feature X | \\\`src/x/\\\` | {pattern hint} |
|
|
13275
13258
|
|
|
13259
|
+
## CODE MAP
|
|
13260
|
+
|
|
13261
|
+
{Generated from LSP analysis - shows key symbols and their relationships}
|
|
13262
|
+
|
|
13263
|
+
| Symbol | Type | Location | Refs | Role |
|
|
13264
|
+
|--------|------|----------|------|------|
|
|
13265
|
+
| {MainClass} | Class | \\\`src/index.ts\\\` | {N} | {Central orchestrator} |
|
|
13266
|
+
| {createX} | Function | \\\`src/utils.ts\\\` | {N} | {Factory pattern} |
|
|
13267
|
+
| {Config} | Interface | \\\`src/types.ts\\\` | {N} | {Configuration contract} |
|
|
13268
|
+
|
|
13269
|
+
### Module Dependencies
|
|
13270
|
+
|
|
13271
|
+
\\\`\\\`\\\`
|
|
13272
|
+
{entry} \u2500\u2500imports\u2500\u2500> {core/}
|
|
13273
|
+
\u2502 \u2502
|
|
13274
|
+
\u2514\u2500\u2500imports\u2500\u2500> {utils/} <\u2500\u2500imports\u2500\u2500 {features/}
|
|
13275
|
+
\\\`\\\`\\\`
|
|
13276
|
+
|
|
13277
|
+
<code-map-note>
|
|
13278
|
+
**Skip CODE MAP if**: LSP unavailable OR project too small (<10 files) OR no clear module boundaries.
|
|
13279
|
+
</code-map-note>
|
|
13280
|
+
|
|
13276
13281
|
## CONVENTIONS
|
|
13277
13282
|
|
|
13278
13283
|
{ONLY deviations from standard - skip generic advice}
|
|
@@ -13413,7 +13418,10 @@ Hierarchy:
|
|
|
13413
13418
|
- **Generic content**: Remove anything that applies to ALL projects
|
|
13414
13419
|
- **Sequential execution**: MUST use parallel agents
|
|
13415
13420
|
- **Deep nesting**: Rarely need AGENTS.md at depth 4+
|
|
13416
|
-
- **Verbose style**: "This directory contains..." \u2192 just list it
|
|
13421
|
+
- **Verbose style**: "This directory contains..." \u2192 just list it
|
|
13422
|
+
- **Ignoring LSP**: If LSP available, USE IT - semantic analysis > text grep
|
|
13423
|
+
- **LSP without fallback**: Always have explore agent backup if LSP unavailable
|
|
13424
|
+
- **Over-referencing**: Don't trace refs for EVERY symbol - focus on exports only`;
|
|
13417
13425
|
|
|
13418
13426
|
// src/features/builtin-commands/commands.ts
|
|
13419
13427
|
var BUILTIN_COMMAND_DEFINITIONS = {
|