agestra 4.13.0 → 4.13.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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/README.ja.md +34 -12
- package/README.ko.md +44 -61
- package/README.md +42 -61
- package/README.zh.md +34 -12
- package/agents/agestra-designer.md +1 -1
- package/agents/agestra-ideator.md +1 -1
- package/agents/agestra-moderator.md +1 -2
- package/agents/agestra-qa.md +1 -1
- package/agents/agestra-reviewer.md +1 -1
- package/agents/agestra-security.md +1 -1
- package/agents/agestra-team-lead.md +5 -3
- package/dist/bundle.js +1 -1
- package/package.json +1 -1
- package/scripts/host-assets/categories.mjs +156 -0
package/README.ja.md
CHANGED
|
@@ -50,7 +50,7 @@ npm install -g agestra
|
|
|
50
50
|
agestra-install gemini --assets --scope user
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
-
Gemini ではリポジトリ直下の [GEMINI.md](GEMINI.md)
|
|
53
|
+
Gemini ではリポジトリ直下の [GEMINI.md](GEMINI.md)、[`.gemini/commands/agestra/`](.gemini/commands/agestra)、生成された skills を一緒に使います。project scope の `--assets` は管理ファイルを書き込み、user scope の `--assets` は Agestra Gemini native extension をインストールします。MCP 登録だけでよい場合は `npm run install:gemini` または `agestra-install gemini` を使ってください。`npm run install:gemini:assets` はデフォルトで user scope を使うため、チェックアウトから project-scope の管理ファイルを入れる場合は `node scripts/install-host-mcp.mjs gemini --assets --scope project` を実行してください。
|
|
54
54
|
|
|
55
55
|
セットアップ後に利用できる Gemini コマンド:
|
|
56
56
|
|
|
@@ -59,6 +59,8 @@ Gemini ではリポジトリ直下の [GEMINI.md](GEMINI.md) と、[`.gemini/com
|
|
|
59
59
|
- `/agestra:design`
|
|
60
60
|
- `/agestra:idea`
|
|
61
61
|
- `/agestra:implement`
|
|
62
|
+
- `/agestra:qa`
|
|
63
|
+
- `/agestra:security`
|
|
62
64
|
|
|
63
65
|
### 前提条件
|
|
64
66
|
|
|
@@ -83,9 +85,9 @@ Gemini ではリポジトリ直下の [GEMINI.md](GEMINI.md) と、[`.gemini/com
|
|
|
83
85
|
|
|
84
86
|
| ホスト | 自然な入口 |
|
|
85
87
|
|--------|------------|
|
|
86
|
-
| Claude Code | `/agestra review`, `/agestra design`, `/agestra idea`, `/agestra implement` |
|
|
88
|
+
| Claude Code | `/agestra setup`, `/agestra review`, `/agestra qa`, `/agestra security`, `/agestra design`, `/agestra idea`, `/agestra implement` |
|
|
87
89
|
| Codex CLI | `AGENTS.md` に沿った自然言語リクエスト |
|
|
88
|
-
| Gemini CLI | `/agestra:review`, `/agestra:design`, `/agestra:idea`, `/agestra:implement` |
|
|
90
|
+
| Gemini CLI | `/agestra:setup`, `/agestra:review`, `/agestra:qa`, `/agestra:security`, `/agestra:design`, `/agestra:idea`, `/agestra:implement` |
|
|
89
91
|
|
|
90
92
|
3 つのホストはすべて同じ MCP サーバーと `commands/*.md` の共通ワークフロー仕様を利用します。
|
|
91
93
|
|
|
@@ -93,24 +95,29 @@ Gemini ではリポジトリ直下の [GEMINI.md](GEMINI.md) と、[`.gemini/com
|
|
|
93
95
|
|
|
94
96
|
| コマンド | 説明 |
|
|
95
97
|
|----------|------|
|
|
98
|
+
| `/agestra setup` | 初期 AI プロバイダー選択とセットアップ |
|
|
96
99
|
| `/agestra review [target]` | コード品質、セキュリティ、統合の完成度をレビュー |
|
|
100
|
+
| `/agestra qa [target]` | 実装結果を検証し、PASS/FAIL の根拠を生成 |
|
|
101
|
+
| `/agestra security [target]` | 専用のセキュリティレビューを実行 |
|
|
97
102
|
| `/agestra idea [topic]` | 類似プロジェクトとの比較から改善案を発見 |
|
|
98
103
|
| `/agestra design [subject]` | 実装前にアーキテクチャと設計上のトレードオフを探索 |
|
|
99
|
-
| `/agestra setup` | 初期 AI プロバイダー選択とセットアップ |
|
|
100
104
|
| `/agestra implement [task]` | Claude only または Multi-AI モードで実装を進める |
|
|
101
105
|
|
|
102
|
-
|
|
106
|
+
外部プロバイダーが利用可能な場合、review、QA、security、design、idea ワークフローは team-lead を通じてマルチ AI クロスバリデーションへルーティングされます。プロバイダーが検出されない場合、現在のホストのローカル specialist agent が自動的に処理します。
|
|
103
107
|
|
|
104
108
|
## エージェント
|
|
105
109
|
|
|
106
110
|
| エージェント | モデル | 役割 |
|
|
107
111
|
|--------------|--------|------|
|
|
108
112
|
| `agestra-team-lead` | Sonnet | フルオーケストレーター — 環境チェック、品質ベースのプロバイダー選択、作業モード選定、CLI ワーカー監督、QA ループ |
|
|
113
|
+
| `agestra-implementer` | Sonnet | スコープ付き実装実行役 — コード変更、テスト更新、ローカル検証 |
|
|
114
|
+
| `agestra-e2e-writer` | Sonnet | 永続 E2E テスト作成役 — 承認済みブラウザフローテストのみ作成 |
|
|
109
115
|
| `agestra-reviewer` | Opus | 厳格な品質検証役 — セキュリティ、孤立コード、仕様逸脱、テスト不足を確認 |
|
|
110
116
|
| `agestra-designer` | Opus | アーキテクチャ探索役 — ソクラテス式質問、トレードオフ分析 |
|
|
111
117
|
| `agestra-ideator` | Sonnet | 改善案発見役 — Web 調査、競合分析 |
|
|
112
118
|
| `agestra-moderator` | Sonnet | マルチモード進行役 — 合意検出付きディベート、独立集約、ドキュメントレビュー、衝突解決 |
|
|
113
119
|
| `agestra-qa` | Opus | QA 検証役 — 設計準拠の確認、PASS/FAIL 判定 |
|
|
120
|
+
| `agestra-security` | Opus | セキュリティレビュー役 — 脅威モデル、認証/データフローリスク、依存関係とシークレット衛生 |
|
|
114
121
|
|
|
115
122
|
## スキル
|
|
116
123
|
|
|
@@ -125,6 +132,9 @@ Gemini ではリポジトリ直下の [GEMINI.md](GEMINI.md) と、[`.gemini/com
|
|
|
125
132
|
| `design` | Multi-AI モード選択を含む設計探索ワークフロー |
|
|
126
133
|
| `idea` | Multi-AI モード選択を含む改善案発見ワークフロー |
|
|
127
134
|
| `review` | Multi-AI モード選択を含むコード品質・セキュリティ・ハードコーディングレビューワークフロー |
|
|
135
|
+
| `qa` | 設計契約検証と PASS/FAIL 根拠生成ワークフロー |
|
|
136
|
+
| `security` | 専用セキュリティレビューワークフロー |
|
|
137
|
+
| `e2e` | 永続ブラウザ E2E テスト作成ワークフロー |
|
|
128
138
|
| `leader` | マルチAI/プロバイダーオーケストレーションのエントリーポイント — 明示的なプロバイダー、ディベート、合意形成、相互検証シグナルを検知し、ドメイン分類後 `agestra-team-lead` へ委譲 |
|
|
129
139
|
|
|
130
140
|
---
|
|
@@ -147,7 +157,7 @@ Turborepo モノレポで、8 パッケージ構成です:
|
|
|
147
157
|
|
|
148
158
|
- **Provider abstraction** — すべてのバックエンドは `AIProvider`(`chat`, `healthCheck`, `getCapabilities`)を実装します。新規プロバイダー追加は専用パッケージとファクトリ登録に分離されます。
|
|
149
159
|
- **Zero-config** — プロバイダーは起動時に自動検出されます。手動設定は不要です。
|
|
150
|
-
- **Host-native** — Claude はプラグインバンドル、Codex は `AGENTS.md
|
|
160
|
+
- **Host-native** — Claude はプラグインバンドル、Codex は `AGENTS.md` と custom agents、Gemini は `GEMINI.md`、commands、skills、または native extension を使います。すべてのホストは同じ MCP サーバーとワークフローコアを共有します。
|
|
151
161
|
- **Modular dispatch** — 各ツールカテゴリは `getTools()` + `handleTool()` を持つ独立モジュールです。サーバーが動的に収集してディスパッチします。
|
|
152
162
|
- **Atomic writes** — すべてのファイル操作は一時ファイルへの書き込み後に rename する方式で、破損を防ぎます。
|
|
153
163
|
- **Dead-end tracking** — 失敗したアプローチは記録され、今後のプロンプトに注入されます。
|
|
@@ -155,11 +165,11 @@ Turborepo モノレポで、8 パッケージ構成です:
|
|
|
155
165
|
|
|
156
166
|
### 作業モード
|
|
157
167
|
|
|
158
|
-
**Text work
|
|
168
|
+
**Text work**(レビュー、QA、セキュリティ、設計、アイデア): プロバイダーあり → 徹底討論モード; なし → Claude only
|
|
159
169
|
|
|
160
170
|
**Implementation work**(team-lead orchestration):
|
|
161
|
-
- **Claude
|
|
162
|
-
-
|
|
171
|
+
- **Claude のみ** — Claude がプロジェクト/グローバルエージェントを使って直接実装します。
|
|
172
|
+
- **他の AI と併用** — CLI ワーカー(Codex/Gemini)が分離された git worktree で自律的にコーディングし、Ollama が簡単なタスクを担当し、Claude が監督・統合します。
|
|
163
173
|
|
|
164
174
|
---
|
|
165
175
|
|
|
@@ -237,7 +247,7 @@ Turborepo モノレポで、8 パッケージ構成です:
|
|
|
237
247
|
|
|
238
248
|
| ツール | 説明 |
|
|
239
249
|
|--------|------|
|
|
240
|
-
| `host_assets_status` | Codex custom agents などの生成済みホストネイティブアセットを確認 |
|
|
250
|
+
| `host_assets_status` | Codex custom agents や Gemini assets などの生成済みホストネイティブアセットを確認 |
|
|
241
251
|
| `host_assets_install` | 管理対象のホストネイティブアセットを明示的にインストールまたは更新 |
|
|
242
252
|
| `host_assets_uninstall` | Agestra が追跡する管理対象ホストネイティブアセットを削除 |
|
|
243
253
|
|
|
@@ -326,21 +336,30 @@ agestra/
|
|
|
326
336
|
├── .gemini/
|
|
327
337
|
│ └── commands/
|
|
328
338
|
│ └── agestra/
|
|
339
|
+
│ ├── setup.toml # Gemini CLI の /agestra:setup
|
|
329
340
|
│ ├── review.toml # Gemini CLI の /agestra:review
|
|
330
341
|
│ ├── design.toml # Gemini CLI の /agestra:design
|
|
331
342
|
│ ├── idea.toml # Gemini CLI の /agestra:idea
|
|
332
|
-
│
|
|
343
|
+
│ ├── implement.toml # Gemini CLI の /agestra:implement
|
|
344
|
+
│ ├── qa.toml # Gemini CLI の /agestra:qa
|
|
345
|
+
│ └── security.toml # Gemini CLI の /agestra:security
|
|
333
346
|
├── commands/
|
|
347
|
+
│ ├── setup.md # /agestra setup — プロバイダー設定
|
|
334
348
|
│ ├── review.md # /agestra review — 品質検証
|
|
349
|
+
│ ├── qa.md # /agestra qa — PASS/FAIL 検証
|
|
350
|
+
│ ├── security.md # /agestra security — セキュリティレビュー
|
|
335
351
|
│ ├── idea.md # /agestra idea — 改善案探索
|
|
336
352
|
│ ├── design.md # /agestra design — アーキテクチャ探索
|
|
337
353
|
│ └── implement.md # /agestra implement — 実装ワークフロー
|
|
338
354
|
├── agents/
|
|
355
|
+
│ ├── agestra-implementer.md # スコープ付き実装実行役(Sonnet)
|
|
356
|
+
│ ├── agestra-e2e-writer.md # 永続 E2E テスト作成役(Sonnet)
|
|
339
357
|
│ ├── agestra-reviewer.md # 厳格な品質検証役(Opus)
|
|
340
358
|
│ ├── agestra-designer.md # アーキテクチャ探索役(Opus)
|
|
341
359
|
│ ├── agestra-ideator.md # 改善案発見役(Sonnet)
|
|
342
360
|
│ ├── agestra-moderator.md # マルチモード進行役(Sonnet)
|
|
343
361
|
│ ├── agestra-qa.md # QA 検証役(Opus、コード書き込みなし)
|
|
362
|
+
│ ├── agestra-security.md # セキュリティレビュー役(Opus)
|
|
344
363
|
│ └── agestra-team-lead.md # フルオーケストレーター(Sonnet、コード書き込みなし)
|
|
345
364
|
├── skills/
|
|
346
365
|
│ ├── provider-guide.md # プロバイダー選択とモード参照
|
|
@@ -352,6 +371,9 @@ agestra/
|
|
|
352
371
|
│ ├── design.md # 設計探索ワークフロー
|
|
353
372
|
│ ├── idea.md # 改善案発見ワークフロー
|
|
354
373
|
│ ├── review.md # コード品質レビューワークフロー
|
|
374
|
+
│ ├── qa.md # 設計契約 QA ワークフロー
|
|
375
|
+
│ ├── security.md # 専用セキュリティレビューワークフロー
|
|
376
|
+
│ ├── e2e.md # 永続 E2E テスト作成ワークフロー
|
|
355
377
|
│ └── leader.md # マルチAIオーケストレーションルーター
|
|
356
378
|
├── hooks/
|
|
357
379
|
│ └── user-prompt-submit.md # ツール推奨フック
|
|
@@ -403,7 +425,7 @@ npm run uninstall:gemini
|
|
|
403
425
|
npm run uninstall:gemini:assets
|
|
404
426
|
```
|
|
405
427
|
|
|
406
|
-
`*:assets`
|
|
428
|
+
`*:assets` のアンインストールは、ホスト登録と未変更の生成済みホスト資産を一緒に削除します。Codex assets は custom-agent ファイルです。Gemini project-scope assets は管理ファイルで、Gemini user-scope assets は `gemini extensions uninstall agestra` で削除されます。ユーザーが生成済み資産を編集していた場合、Agestra はそのファイルを残して報告します。グローバル npm インストールでは `agestra-uninstall codex --assets` または `agestra-uninstall gemini --assets --scope user` を使ってください。
|
|
407
429
|
|
|
408
430
|
生成済みのプロジェクトデータも削除したい場合は、`.agestra/` ディレクトリを手動で削除してください。
|
|
409
431
|
|
package/README.ko.md
CHANGED
|
@@ -11,70 +11,34 @@ Agestra는 Claude 호스트, Ollama(로컬), Gemini CLI, Codex CLI를 플러그
|
|
|
11
11
|
|
|
12
12
|
## 빠른 시작
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
먼저 사용할 호스트를 고르세요. 호스트 네이티브 커맨드/에이전트까지 설치하려면 `--assets` 경로를 쓰고, 서버 연결만 필요하면 MCP-only 등록을 쓰면 됩니다.
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
/plugin install agestra@agestra
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
Claude는 기존 플러그인 설치 UX를 그대로 유지합니다. Agestra가 첫 사용 시 `environment_check`로 사용 가능한 공급자(Claude 호스트, Ollama, Gemini CLI, Codex CLI)를 자동 감지합니다.
|
|
22
|
-
|
|
23
|
-
### Codex CLI
|
|
16
|
+
| 호스트 | 이 저장소에서 설치 | 전역 npm 패키지에서 설치 | `--assets`가 추가하는 것 |
|
|
17
|
+
|--------|--------------------|--------------------------|--------------------------|
|
|
18
|
+
| Claude Code | `/plugin marketplace add mua-vtuber/Agestra` 후 `/plugin install agestra@agestra` | 같은 플러그인 흐름 | 플러그인 번들, 커맨드, 에이전트, hook, MCP 서버 |
|
|
19
|
+
| Codex CLI | `npm run bundle` 후 `npm run install:codex:assets` | `npm install -g agestra` 후 `agestra-install codex --assets` | `.codex/agents/` 아래 생성형 custom agent |
|
|
20
|
+
| Gemini CLI | `npm run bundle` 후 `npm run install:gemini:assets` | `npm install -g agestra` 후 `agestra-install gemini --assets --scope user` | project scope에서는 관리 파일, user scope에서는 native `agestra` Gemini extension |
|
|
24
21
|
|
|
25
|
-
|
|
22
|
+
MCP-only 등록도 가능합니다:
|
|
26
23
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
npm run install:codex:
|
|
30
|
-
|
|
24
|
+
| 호스트 | 저장소 패키지 | 체크아웃에서 전역 패키지 등록 |
|
|
25
|
+
|--------|---------------|-------------------------------|
|
|
26
|
+
| Codex CLI | `npm run install:codex` | `npm run install:codex:global` |
|
|
27
|
+
| Gemini CLI | `npm run install:gemini` | `npm run install:gemini:global` |
|
|
31
28
|
|
|
32
|
-
|
|
29
|
+
Claude는 네이티브 플러그인 UX를 그대로 사용합니다. Codex는 [AGENTS.md](AGENTS.md), 생성된 custom agent, 등록된 `agestra` MCP 서버를 함께 사용합니다. Gemini는 [GEMINI.md](GEMINI.md), `.gemini/commands/agestra/`, 생성된 skills, 그리고 project-scope 관리 파일 또는 user-scope native extension을 함께 사용합니다.
|
|
33
30
|
|
|
34
|
-
|
|
35
|
-
npm install -g agestra
|
|
36
|
-
agestra-install codex --assets
|
|
37
|
-
```
|
|
31
|
+
참고: `npm run install:gemini:assets`는 기본적으로 user scope를 사용합니다. 체크아웃에서 project-scope Gemini 관리 파일을 설치하려면 `node scripts/install-host-mcp.mjs gemini --assets --scope project`를 실행하세요.
|
|
38
32
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
```
|
|
42
|
-
npm run install:codex:global
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
Codex는 저장소 루트의 [AGENTS.md](AGENTS.md)와 등록된 `agestra` MCP 서버를 함께 사용합니다. 생성형 Codex custom agent에는 `--assets` 경로가 필요하며, 이 경로가 `.codex/agents/` 아래에 agent를 설치하고 Agestra host-asset manifest에 기록합니다. custom agent 없이 MCP만 등록하려면 `npm run install:codex` 또는 `agestra-install codex`를 사용하세요.
|
|
46
|
-
|
|
47
|
-
### Gemini CLI
|
|
48
|
-
|
|
49
|
-
저장소 체크아웃 기준:
|
|
50
|
-
|
|
51
|
-
```
|
|
52
|
-
npm run bundle
|
|
53
|
-
npm run install:gemini:assets
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
전역 npm 패키지 기준:
|
|
57
|
-
|
|
58
|
-
```
|
|
59
|
-
npm install -g agestra
|
|
60
|
-
agestra-install gemini --assets --scope user
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
저장소에서 작업 중이지만 전역 npm 패키지를 MCP만 등록하고 싶다면:
|
|
64
|
-
|
|
65
|
-
```
|
|
66
|
-
npm run install:gemini:global
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
Gemini는 저장소 루트의 [GEMINI.md](GEMINI.md)와 [`.gemini/commands/agestra/`](.gemini/commands/agestra) 프로젝트 커맨드를 함께 사용합니다. user scope의 `--assets` 경로는 Agestra Gemini native extension을 설치합니다. MCP만 등록하려면 `npm run install:gemini` 또는 `agestra-install gemini`를 사용하세요.
|
|
70
|
-
|
|
71
|
-
설치 후 Gemini에서 사용할 수 있는 명령:
|
|
33
|
+
Assets 설치 후 Gemini에서 사용할 수 있는 명령:
|
|
72
34
|
|
|
73
35
|
- `/agestra:setup`
|
|
74
36
|
- `/agestra:review`
|
|
75
37
|
- `/agestra:design`
|
|
76
38
|
- `/agestra:idea`
|
|
77
39
|
- `/agestra:implement`
|
|
40
|
+
- `/agestra:qa`
|
|
41
|
+
- `/agestra:security`
|
|
78
42
|
|
|
79
43
|
### 사전 요구사항
|
|
80
44
|
|
|
@@ -110,9 +74,9 @@ winget install BurntSushi.ripgrep.MSVC
|
|
|
110
74
|
|
|
111
75
|
| 호스트 | 자연스러운 진입 방식 |
|
|
112
76
|
|--------|----------------------|
|
|
113
|
-
| Claude Code | `/agestra review`, `/agestra design`, `/agestra idea`, `/agestra implement` |
|
|
77
|
+
| Claude Code | `/agestra setup`, `/agestra review`, `/agestra qa`, `/agestra security`, `/agestra design`, `/agestra idea`, `/agestra implement` |
|
|
114
78
|
| Codex CLI | `AGENTS.md`에 맞춘 자연어 요청 |
|
|
115
|
-
| Gemini CLI | `/agestra:review`, `/agestra:design`, `/agestra:idea`, `/agestra:implement` |
|
|
79
|
+
| Gemini CLI | `/agestra:setup`, `/agestra:review`, `/agestra:qa`, `/agestra:security`, `/agestra:design`, `/agestra:idea`, `/agestra:implement` |
|
|
116
80
|
|
|
117
81
|
세 호스트 모두 같은 MCP 서버와 `commands/*.md` 공유 워크플로우를 사용합니다.
|
|
118
82
|
|
|
@@ -120,24 +84,29 @@ winget install BurntSushi.ripgrep.MSVC
|
|
|
120
84
|
|
|
121
85
|
| 커맨드 | 설명 |
|
|
122
86
|
|--------|------|
|
|
87
|
+
| `/agestra setup` | 초기 AI 공급자 선택 및 설정 |
|
|
123
88
|
| `/agestra review [대상]` | 코드 품질, 보안, 통합 완성도 검증 |
|
|
89
|
+
| `/agestra qa [대상]` | 구현 결과를 검증하고 PASS/FAIL 근거 생성 |
|
|
90
|
+
| `/agestra security [대상]` | 전용 보안 리뷰 실행 |
|
|
124
91
|
| `/agestra idea [주제]` | 유사 프로젝트 비교를 통한 개선점 발굴 |
|
|
125
92
|
| `/agestra design [주제]` | 구현 전 아키텍처 및 설계 트레이드오프 탐색 |
|
|
126
|
-
| `/agestra setup` | 초기 AI 공급자 선택 및 설정 |
|
|
127
93
|
| `/agestra implement [작업]` | Claude only 또는 Multi-AI 모드로 실제 구현 진행 |
|
|
128
94
|
|
|
129
|
-
외부 공급자가 있으면
|
|
95
|
+
외부 공급자가 있으면 review, QA, security, design, idea 워크플로우는 team-lead를 통해 멀티 AI 교차 검증으로 라우팅됩니다. 공급자가 없으면 현재 호스트의 로컬 specialist agent가 자동으로 처리합니다.
|
|
130
96
|
|
|
131
97
|
## 에이전트
|
|
132
98
|
|
|
133
99
|
| 에이전트 | 모델 | 역할 |
|
|
134
100
|
|----------|------|------|
|
|
135
101
|
| `agestra-team-lead` | Sonnet | 풀 오케스트레이터 — 환경 체크, 품질 기반 공급자 라우팅, 작업 모드 선택, CLI 워커 감독, QA 루프 |
|
|
102
|
+
| `agestra-implementer` | Sonnet | 제한된 구현 실행자 — 코드 수정, 테스트 갱신, 로컬 검증 |
|
|
103
|
+
| `agestra-e2e-writer` | Sonnet | 지속 E2E 테스트 작성자 — 승인된 브라우저 플로우 테스트만 작성 |
|
|
136
104
|
| `agestra-reviewer` | Opus | 엄격한 품질 검증 — 보안, 고아 시스템, 스펙 이탈, 테스트 공백 |
|
|
137
105
|
| `agestra-designer` | Opus | 아키텍처 탐색 — 소크라테스식 질문, 트레이드오프 분석 |
|
|
138
106
|
| `agestra-ideator` | Sonnet | 개선점 발굴 — 웹 리서치, 경쟁 분석 |
|
|
139
107
|
| `agestra-moderator` | Sonnet | 다목적 진행자 — 합의 검출 토론, 독립 취합, 문서 라운드 리뷰, 충돌 해결 |
|
|
140
108
|
| `agestra-qa` | Opus | QA 검증 — 설계 준수, PASS/FAIL 판정 |
|
|
109
|
+
| `agestra-security` | Opus | 보안 리뷰 — 위협 모델, 인증/데이터 흐름 위험, 의존성·시크릿 위생 |
|
|
141
110
|
|
|
142
111
|
## 스킬
|
|
143
112
|
|
|
@@ -152,6 +121,9 @@ winget install BurntSushi.ripgrep.MSVC
|
|
|
152
121
|
| `design` | 멀티 AI 모드 선택이 포함된 아키텍처 탐색 워크플로우 |
|
|
153
122
|
| `idea` | 멀티 AI 모드 선택이 포함된 개선점 발굴 워크플로우 |
|
|
154
123
|
| `review` | 멀티 AI 모드 선택이 포함된 코드 품질·보안·하드코딩 리뷰 워크플로우 |
|
|
124
|
+
| `qa` | 설계 계약 검증 및 PASS/FAIL 근거 생성 워크플로우 |
|
|
125
|
+
| `security` | 전용 보안 리뷰 워크플로우 |
|
|
126
|
+
| `e2e` | 지속 브라우저 E2E 테스트 작성 워크플로우 |
|
|
155
127
|
| `leader` | 멀티 AI/프로바이더 오케스트레이션 진입점 — 명시적인 프로바이더, 토론, 합의, 교차 검증 신호를 잡아 도메인을 분류한 뒤 `agestra-team-lead`에 위임 |
|
|
156
128
|
|
|
157
129
|
---
|
|
@@ -174,7 +146,7 @@ Turborepo 모노레포, 8개 패키지:
|
|
|
174
146
|
|
|
175
147
|
- **공급자 추상화** — 모든 백엔드가 `AIProvider`(`chat`, `healthCheck`, `getCapabilities`)를 구현. 새 공급자 추가는 전용 패키지 구현과 팩토리 등록으로 분리됩니다.
|
|
176
148
|
- **제로 설정** — 시작 시 공급자를 자동 감지. 수동 설정 불필요.
|
|
177
|
-
- **호스트 네이티브** — Claude는 플러그인 번들을, Codex는 `AGENTS.md
|
|
149
|
+
- **호스트 네이티브** — Claude는 플러그인 번들을, Codex는 `AGENTS.md`와 custom agents를, Gemini는 `GEMINI.md`, commands, skills 또는 native extension을 사용합니다. 모든 호스트는 같은 MCP 서버와 워크플로우 코어를 공유합니다.
|
|
178
150
|
- **모듈형 디스패치** — 각 도구 카테고리가 `getTools()` + `handleTool()`을 내보내는 독립 모듈. 서버가 동적으로 수집·디스패치.
|
|
179
151
|
- **원자적 쓰기** — 모든 파일 연산이 임시 파일 → rename 방식. 크래시 시 손상 방지.
|
|
180
152
|
- **실패 추적** — 실패한 접근법이 자동 기록, 이후 프롬프트에 주입.
|
|
@@ -182,7 +154,7 @@ Turborepo 모노레포, 8개 패키지:
|
|
|
182
154
|
|
|
183
155
|
### 작업 모드
|
|
184
156
|
|
|
185
|
-
**텍스트 작업** (리뷰, 설계, 아이디어): 공급자 있으면 → 끝장토론; 없으면 → Claude only
|
|
157
|
+
**텍스트 작업** (리뷰, QA, 보안, 설계, 아이디어): 공급자 있으면 → 끝장토론; 없으면 → Claude only
|
|
186
158
|
|
|
187
159
|
**구현 작업** (team-lead 오케스트레이션):
|
|
188
160
|
- **Claude만으로** — Claude가 프로젝트/전역 에이전트를 활용해 직접 구현.
|
|
@@ -264,7 +236,7 @@ Turborepo 모노레포, 8개 패키지:
|
|
|
264
236
|
|
|
265
237
|
| 도구 | 설명 |
|
|
266
238
|
|------|------|
|
|
267
|
-
| `host_assets_status` | Codex custom agents 같은 생성된 호스트 네이티브 자산 상태 확인 |
|
|
239
|
+
| `host_assets_status` | Codex custom agents, Gemini assets 같은 생성된 호스트 네이티브 자산 상태 확인 |
|
|
268
240
|
| `host_assets_install` | 관리되는 호스트 네이티브 자산을 명시적으로 설치 또는 갱신 |
|
|
269
241
|
| `host_assets_uninstall` | Agestra가 추적하는 관리형 호스트 네이티브 자산 제거 |
|
|
270
242
|
|
|
@@ -357,9 +329,14 @@ agestra/
|
|
|
357
329
|
│ ├── review.toml # Gemini CLI의 /agestra:review
|
|
358
330
|
│ ├── design.toml # Gemini CLI의 /agestra:design
|
|
359
331
|
│ ├── idea.toml # Gemini CLI의 /agestra:idea
|
|
360
|
-
│
|
|
332
|
+
│ ├── implement.toml # Gemini CLI의 /agestra:implement
|
|
333
|
+
│ ├── qa.toml # Gemini CLI의 /agestra:qa
|
|
334
|
+
│ └── security.toml # Gemini CLI의 /agestra:security
|
|
361
335
|
├── commands/
|
|
336
|
+
│ ├── setup.md # /agestra setup — 공급자 설정
|
|
362
337
|
│ ├── review.md # /agestra review — 품질 검증
|
|
338
|
+
│ ├── qa.md # /agestra qa — PASS/FAIL 검증
|
|
339
|
+
│ ├── security.md # /agestra security — 보안 리뷰
|
|
363
340
|
│ ├── idea.md # /agestra idea — 개선점 발굴
|
|
364
341
|
│ ├── design.md # /agestra design — 아키텍처 탐색
|
|
365
342
|
│ └── implement.md # /agestra implement — 실제 구현 진행
|
|
@@ -367,8 +344,11 @@ agestra/
|
|
|
367
344
|
│ ├── agestra-reviewer.md # 엄격한 품질 검증자 (Opus)
|
|
368
345
|
│ ├── agestra-designer.md # 아키텍처 탐색자 (Opus)
|
|
369
346
|
│ ├── agestra-ideator.md # 개선점 발굴자 (Sonnet)
|
|
347
|
+
│ ├── agestra-implementer.md # 제한된 구현 실행자 (Sonnet)
|
|
348
|
+
│ ├── agestra-e2e-writer.md # 지속 E2E 테스트 작성자 (Sonnet)
|
|
370
349
|
│ ├── agestra-moderator.md # 다목적 진행자 (Sonnet)
|
|
371
350
|
│ ├── agestra-qa.md # QA 검증자 (Opus, 코드 쓰기 불가)
|
|
351
|
+
│ ├── agestra-security.md # 보안 리뷰어 (Opus)
|
|
372
352
|
│ └── agestra-team-lead.md # 풀 오케스트레이터 (Sonnet, 코드 쓰기 불가)
|
|
373
353
|
├── skills/
|
|
374
354
|
│ ├── provider-guide.md # 공급자 라우팅 및 모드 참조
|
|
@@ -380,6 +360,9 @@ agestra/
|
|
|
380
360
|
│ ├── design.md # 아키텍처 탐색 워크플로우
|
|
381
361
|
│ ├── idea.md # 개선점 발굴 워크플로우
|
|
382
362
|
│ ├── review.md # 코드 품질 리뷰 워크플로우
|
|
363
|
+
│ ├── qa.md # 설계 계약 QA 워크플로우
|
|
364
|
+
│ ├── security.md # 전용 보안 리뷰 워크플로우
|
|
365
|
+
│ ├── e2e.md # 지속 E2E 테스트 작성 워크플로우
|
|
383
366
|
│ └── leader.md # 멀티 AI 오케스트레이션 라우터
|
|
384
367
|
├── hooks/
|
|
385
368
|
│ └── user-prompt-submit.md # 도구 추천 hook
|
|
@@ -431,7 +414,7 @@ npm run uninstall:gemini
|
|
|
431
414
|
npm run uninstall:gemini:assets
|
|
432
415
|
```
|
|
433
416
|
|
|
434
|
-
`*:assets` 제거 명령은 호스트 등록과 변경되지 않은 생성형 호스트 자산을 함께 제거합니다. 사용자가 생성된 자산을 수정했다면 Agestra는 삭제하지 않고 남겨둔 파일을 보고합니다. 전역 npm 설치에서는 `agestra-uninstall codex --assets` 또는 `agestra-uninstall gemini --assets --scope user`를 사용하세요.
|
|
417
|
+
`*:assets` 제거 명령은 호스트 등록과 변경되지 않은 생성형 호스트 자산을 함께 제거합니다. Codex 자산은 custom-agent 파일입니다. Gemini project-scope 자산은 관리 파일이고, Gemini user-scope 자산은 `gemini extensions uninstall agestra`로 제거됩니다. 사용자가 생성된 자산을 수정했다면 Agestra는 삭제하지 않고 남겨둔 파일을 보고합니다. 전역 npm 설치에서는 `agestra-uninstall codex --assets` 또는 `agestra-uninstall gemini --assets --scope user`를 사용하세요.
|
|
435
418
|
|
|
436
419
|
프로젝트에 생성된 데이터까지 지우려면 `.agestra/` 디렉터리를 수동으로 삭제하세요.
|
|
437
420
|
|
package/README.md
CHANGED
|
@@ -11,70 +11,34 @@ Agestra connects the Claude host, Ollama (local), Gemini CLI, and Codex CLI as p
|
|
|
11
11
|
|
|
12
12
|
## Quick Start
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
Pick the host you work in first. Use the `--assets` path when you want the host-native commands/agents installed too; use MCP-only registration when you only need the server connection.
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
/plugin install agestra@agestra
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
Claude keeps the existing plugin UX. Agestra auto-detects available providers (Claude host, Ollama, Gemini CLI, Codex CLI) on first use via `environment_check`.
|
|
22
|
-
|
|
23
|
-
### Codex CLI
|
|
16
|
+
| Host | From this repository | From global npm | What `--assets` adds |
|
|
17
|
+
|------|----------------------|-----------------|----------------------|
|
|
18
|
+
| Claude Code | `/plugin marketplace add mua-vtuber/Agestra` then `/plugin install agestra@agestra` | same plugin flow | Plugin bundle, commands, agents, hooks, and MCP server together |
|
|
19
|
+
| Codex CLI | `npm run bundle` then `npm run install:codex:assets` | `npm install -g agestra` then `agestra-install codex --assets` | Generated custom agents under `.codex/agents/` |
|
|
20
|
+
| Gemini CLI | `npm run bundle` then `npm run install:gemini:assets` | `npm install -g agestra` then `agestra-install gemini --assets --scope user` | Project assets for project scope, or the native `agestra` Gemini extension for user scope |
|
|
24
21
|
|
|
25
|
-
|
|
22
|
+
MCP-only registration is also available:
|
|
26
23
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
npm run install:codex:
|
|
30
|
-
|
|
24
|
+
| Host | Repository package | Global package from a checkout |
|
|
25
|
+
|------|--------------------|--------------------------------|
|
|
26
|
+
| Codex CLI | `npm run install:codex` | `npm run install:codex:global` |
|
|
27
|
+
| Gemini CLI | `npm run install:gemini` | `npm run install:gemini:global` |
|
|
31
28
|
|
|
32
|
-
|
|
29
|
+
Claude keeps the native plugin UX. Codex combines [AGENTS.md](AGENTS.md), generated custom agents, and the registered `agestra` MCP server. Gemini combines [GEMINI.md](GEMINI.md), `.gemini/commands/agestra/`, generated skills, and either project-scope managed files or a user-scope native extension.
|
|
33
30
|
|
|
34
|
-
|
|
35
|
-
npm install -g agestra
|
|
36
|
-
agestra-install codex --assets
|
|
37
|
-
```
|
|
31
|
+
Note: `npm run install:gemini:assets` uses user scope by default. For project-scope managed Gemini files from a checkout, run `node scripts/install-host-mcp.mjs gemini --assets --scope project`.
|
|
38
32
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
```
|
|
42
|
-
npm run install:codex:global
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
Codex uses the repository-level [AGENTS.md](AGENTS.md) instructions plus the registered `agestra` MCP server. The `--assets` path is required for generated Codex custom agents; it installs them under `.codex/agents/` and tracks them in the Agestra host-asset manifest. For MCP-only registration without custom agents, use `npm run install:codex` or `agestra-install codex`.
|
|
46
|
-
|
|
47
|
-
### Gemini CLI
|
|
48
|
-
|
|
49
|
-
Repository checkout:
|
|
50
|
-
|
|
51
|
-
```
|
|
52
|
-
npm run bundle
|
|
53
|
-
npm run install:gemini:assets
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
Global npm package:
|
|
57
|
-
|
|
58
|
-
```
|
|
59
|
-
npm install -g agestra
|
|
60
|
-
agestra-install gemini --assets --scope user
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
If you want MCP-only registration of the global package while working from a repo checkout, use:
|
|
64
|
-
|
|
65
|
-
```
|
|
66
|
-
npm run install:gemini:global
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
Gemini uses the repository-level [GEMINI.md](GEMINI.md) context file plus project commands under [`.gemini/commands/agestra/`](.gemini/commands/agestra). The user-scope `--assets` path installs the Agestra Gemini native extension. For MCP-only registration, use `npm run install:gemini` or `agestra-install gemini`.
|
|
70
|
-
|
|
71
|
-
Available Gemini commands after setup:
|
|
33
|
+
Available Gemini commands after asset setup:
|
|
72
34
|
|
|
73
35
|
- `/agestra:setup`
|
|
74
36
|
- `/agestra:review`
|
|
75
37
|
- `/agestra:design`
|
|
76
38
|
- `/agestra:idea`
|
|
77
39
|
- `/agestra:implement`
|
|
40
|
+
- `/agestra:qa`
|
|
41
|
+
- `/agestra:security`
|
|
78
42
|
|
|
79
43
|
### Prerequisites
|
|
80
44
|
|
|
@@ -110,9 +74,9 @@ winget install BurntSushi.ripgrep.MSVC
|
|
|
110
74
|
|
|
111
75
|
| Host | Natural entrypoint |
|
|
112
76
|
|------|--------------------|
|
|
113
|
-
| Claude Code | `/agestra review`, `/agestra design`, `/agestra idea`, `/agestra implement` |
|
|
77
|
+
| Claude Code | `/agestra setup`, `/agestra review`, `/agestra qa`, `/agestra security`, `/agestra design`, `/agestra idea`, `/agestra implement` |
|
|
114
78
|
| Codex CLI | Plain-language requests guided by `AGENTS.md` |
|
|
115
|
-
| Gemini CLI | `/agestra:review`, `/agestra:design`, `/agestra:idea`, `/agestra:implement` |
|
|
79
|
+
| Gemini CLI | `/agestra:setup`, `/agestra:review`, `/agestra:qa`, `/agestra:security`, `/agestra:design`, `/agestra:idea`, `/agestra:implement` |
|
|
116
80
|
|
|
117
81
|
All three hosts drive the same MCP server and shared workflow specs from `commands/*.md`.
|
|
118
82
|
|
|
@@ -120,13 +84,15 @@ All three hosts drive the same MCP server and shared workflow specs from `comman
|
|
|
120
84
|
|
|
121
85
|
| Command | Description |
|
|
122
86
|
|---------|-------------|
|
|
87
|
+
| `/agestra setup` | Initial AI provider selection and setup |
|
|
123
88
|
| `/agestra review [target]` | Review code quality, security, and integration completeness |
|
|
89
|
+
| `/agestra qa [target]` | Verify implementation results and produce PASS/FAIL evidence |
|
|
90
|
+
| `/agestra security [target]` | Run a dedicated security review |
|
|
124
91
|
| `/agestra idea [topic]` | Discover improvements by comparing with similar projects |
|
|
125
92
|
| `/agestra design [subject]` | Explore architecture and design trade-offs before implementation |
|
|
126
|
-
| `/agestra setup` | Initial AI provider selection and setup |
|
|
127
93
|
| `/agestra implement [task]` | Execute implementation through Leader-host-only or suggested AI distribution mode |
|
|
128
94
|
|
|
129
|
-
When external providers are available,
|
|
95
|
+
When external providers are available, review, QA, security, design, and idea workflows route through the team lead for multi-AI cross-validation. When no providers are detected, the current leader host works with its local specialist agent automatically. Implementation requests first classify the task and can ask whether to propose an AI task distribution.
|
|
130
96
|
|
|
131
97
|
## Agents
|
|
132
98
|
|
|
@@ -134,11 +100,13 @@ When external providers are available, text commands (review, design, idea) go d
|
|
|
134
100
|
|-------|-------|------|
|
|
135
101
|
| `agestra-team-lead` | Sonnet | Full orchestrator — environment check, quality-based provider routing, work mode selection, CLI worker supervision, QA loop |
|
|
136
102
|
| `agestra-implementer` | Sonnet | Scoped implementation executor — code edits, test updates, local verification |
|
|
103
|
+
| `agestra-e2e-writer` | Sonnet | Persistent E2E test writer — creates approved browser-flow tests without changing product behavior |
|
|
137
104
|
| `agestra-reviewer` | Opus | Strict quality verifier — security, orphans, spec drift, test gaps |
|
|
138
105
|
| `agestra-designer` | Opus | Architecture explorer — Socratic questioning, trade-off analysis |
|
|
139
106
|
| `agestra-ideator` | Sonnet | Improvement discoverer — web research, competitive analysis |
|
|
140
107
|
| `agestra-moderator` | Sonnet | Multi-mode facilitator — debate with consensus detection, independent aggregation, document review, conflict resolution |
|
|
141
108
|
| `agestra-qa` | Opus | QA verifier — design compliance, PASS/FAIL judgment |
|
|
109
|
+
| `agestra-security` | Opus | Security reviewer — threat model, auth/data-flow risk, dependency and secret hygiene |
|
|
142
110
|
|
|
143
111
|
## Skills
|
|
144
112
|
|
|
@@ -153,6 +121,9 @@ When external providers are available, text commands (review, design, idea) go d
|
|
|
153
121
|
| `design` | Architecture exploration workflow with multi-AI mode selection |
|
|
154
122
|
| `idea` | Improvement discovery workflow with multi-AI mode selection |
|
|
155
123
|
| `review` | Code quality / security / hardcoding review workflow with multi-AI mode selection |
|
|
124
|
+
| `qa` | Design-contract verification and PASS/FAIL evidence workflow |
|
|
125
|
+
| `security` | Dedicated security review workflow |
|
|
126
|
+
| `e2e` | Persistent browser E2E test-authoring workflow |
|
|
156
127
|
| `leader` | Multi-AI/provider orchestration entry — catches explicit provider, debate, consensus, or cross-validation signals, classifies the domain, and hands off to `agestra-team-lead` |
|
|
157
128
|
|
|
158
129
|
---
|
|
@@ -175,7 +146,7 @@ Turborepo monorepo with 8 packages:
|
|
|
175
146
|
|
|
176
147
|
- **Provider abstraction** — All backends implement `AIProvider` (`chat`, `healthCheck`, `getCapabilities`). Adding a new provider is isolated to a provider package plus factory registration.
|
|
177
148
|
- **Zero-config** — Providers are auto-detected at startup. No manual configuration required.
|
|
178
|
-
- **Host-native** — Claude uses the plugin bundle, Codex uses `AGENTS.md
|
|
149
|
+
- **Host-native** — Claude uses the plugin bundle, Codex uses `AGENTS.md` plus custom agents, and Gemini uses `GEMINI.md`, commands, skills, or the native extension. All hosts share the same MCP server and workflow core.
|
|
179
150
|
- **Modular dispatch** — Each tool category is an independent module with `getTools()` + `handleTool()`. The server collects and dispatches dynamically.
|
|
180
151
|
- **Atomic writes** — All file operations use write-to-temp-then-rename to prevent corruption.
|
|
181
152
|
- **Dead-end tracking** — Failed approaches are recorded and injected into future prompts.
|
|
@@ -183,7 +154,7 @@ Turborepo monorepo with 8 packages:
|
|
|
183
154
|
|
|
184
155
|
### Work Modes
|
|
185
156
|
|
|
186
|
-
**Text work** (review, design, idea): providers available → consensus debate mode; no providers → Leader-host only
|
|
157
|
+
**Text work** (review, QA, security, design, idea): providers available → consensus debate mode; no providers → Leader-host only
|
|
187
158
|
|
|
188
159
|
**Implementation work** (team-lead orchestration):
|
|
189
160
|
- **Leader-host only** — `agestra-implementer` applies scoped code changes; reviewer/QA verify.
|
|
@@ -265,7 +236,7 @@ Turborepo monorepo with 8 packages:
|
|
|
265
236
|
|
|
266
237
|
| Tool | Description |
|
|
267
238
|
|------|-------------|
|
|
268
|
-
| `host_assets_status` | Check generated host-native assets such as Codex custom agents |
|
|
239
|
+
| `host_assets_status` | Check generated host-native assets such as Codex custom agents and Gemini assets |
|
|
269
240
|
| `host_assets_install` | Explicitly install or refresh managed host-native assets |
|
|
270
241
|
| `host_assets_uninstall` | Remove managed host-native assets tracked by Agestra |
|
|
271
242
|
|
|
@@ -358,9 +329,14 @@ agestra/
|
|
|
358
329
|
│ ├── review.toml # /agestra:review in Gemini CLI
|
|
359
330
|
│ ├── design.toml # /agestra:design in Gemini CLI
|
|
360
331
|
│ ├── idea.toml # /agestra:idea in Gemini CLI
|
|
361
|
-
│
|
|
332
|
+
│ ├── implement.toml # /agestra:implement in Gemini CLI
|
|
333
|
+
│ ├── qa.toml # /agestra:qa in Gemini CLI
|
|
334
|
+
│ └── security.toml # /agestra:security in Gemini CLI
|
|
362
335
|
├── commands/
|
|
336
|
+
│ ├── setup.md # /agestra setup — provider setup
|
|
363
337
|
│ ├── review.md # /agestra review — quality verification
|
|
338
|
+
│ ├── qa.md # /agestra qa — PASS/FAIL verification
|
|
339
|
+
│ ├── security.md # /agestra security — security review
|
|
364
340
|
│ ├── idea.md # /agestra idea — improvement discovery
|
|
365
341
|
│ ├── design.md # /agestra design — architecture exploration
|
|
366
342
|
│ └── implement.md # /agestra implement — execution workflow
|
|
@@ -369,8 +345,10 @@ agestra/
|
|
|
369
345
|
│ ├── agestra-designer.md # Architecture explorer (Opus)
|
|
370
346
|
│ ├── agestra-ideator.md # Improvement discoverer (Sonnet)
|
|
371
347
|
│ ├── agestra-implementer.md # Scoped implementation executor (Sonnet)
|
|
348
|
+
│ ├── agestra-e2e-writer.md # Persistent E2E test writer (Sonnet)
|
|
372
349
|
│ ├── agestra-moderator.md # Multi-mode facilitator (Sonnet)
|
|
373
350
|
│ ├── agestra-qa.md # QA verifier (Opus, no code writes)
|
|
351
|
+
│ ├── agestra-security.md # Security reviewer (Opus)
|
|
374
352
|
│ └── agestra-team-lead.md # Full orchestrator (Sonnet, no code writes)
|
|
375
353
|
├── skills/
|
|
376
354
|
│ ├── provider-guide.md # Provider routing and mode reference
|
|
@@ -382,6 +360,9 @@ agestra/
|
|
|
382
360
|
│ ├── design.md # Architecture exploration workflow
|
|
383
361
|
│ ├── idea.md # Improvement discovery workflow
|
|
384
362
|
│ ├── review.md # Code quality review workflow
|
|
363
|
+
│ ├── qa.md # Design-contract QA workflow
|
|
364
|
+
│ ├── security.md # Dedicated security review workflow
|
|
365
|
+
│ ├── e2e.md # Persistent E2E test-writing workflow
|
|
385
366
|
│ └── leader.md # Multi-AI orchestration entry router
|
|
386
367
|
├── hooks/
|
|
387
368
|
│ └── user-prompt-submit.md # Tool recommendation hook
|
|
@@ -433,7 +414,7 @@ npm run uninstall:gemini
|
|
|
433
414
|
npm run uninstall:gemini:assets
|
|
434
415
|
```
|
|
435
416
|
|
|
436
|
-
The `*:assets` uninstall commands remove both the host registration and unchanged generated host assets. If a generated asset was edited by the user, Agestra leaves it in place and reports it. For a global npm install, use `agestra-uninstall codex --assets` or `agestra-uninstall gemini --assets --scope user`.
|
|
417
|
+
The `*:assets` uninstall commands remove both the host registration and unchanged generated host assets. Codex assets are custom-agent files. Gemini project-scope assets are managed files; Gemini user-scope assets are removed through `gemini extensions uninstall agestra`. If a generated asset was edited by the user, Agestra leaves it in place and reports it. For a global npm install, use `agestra-uninstall codex --assets` or `agestra-uninstall gemini --assets --scope user`.
|
|
437
418
|
|
|
438
419
|
If you also want to delete generated project data, remove the `.agestra/` directory manually.
|
|
439
420
|
|
package/README.zh.md
CHANGED
|
@@ -50,7 +50,7 @@ npm install -g agestra
|
|
|
50
50
|
agestra-install gemini --assets --scope user
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
-
Gemini 会结合仓库根目录下的 [GEMINI.md](GEMINI.md)
|
|
53
|
+
Gemini 会结合仓库根目录下的 [GEMINI.md](GEMINI.md)、[`.gemini/commands/agestra/`](.gemini/commands/agestra) 和生成的 skills 一起工作。project scope 的 `--assets` 会写入受管文件,user scope 的 `--assets` 会安装 Agestra Gemini native extension。只注册 MCP 时,请使用 `npm run install:gemini` 或 `agestra-install gemini`。`npm run install:gemini:assets` 默认使用 user scope;如果要从 checkout 安装 project-scope 受管文件,请运行 `node scripts/install-host-mcp.mjs gemini --assets --scope project`。
|
|
54
54
|
|
|
55
55
|
安装后可用的 Gemini 命令:
|
|
56
56
|
|
|
@@ -59,6 +59,8 @@ Gemini 会结合仓库根目录下的 [GEMINI.md](GEMINI.md) 与 [`.gemini/comma
|
|
|
59
59
|
- `/agestra:design`
|
|
60
60
|
- `/agestra:idea`
|
|
61
61
|
- `/agestra:implement`
|
|
62
|
+
- `/agestra:qa`
|
|
63
|
+
- `/agestra:security`
|
|
62
64
|
|
|
63
65
|
### 前置条件
|
|
64
66
|
|
|
@@ -83,9 +85,9 @@ Gemini 会结合仓库根目录下的 [GEMINI.md](GEMINI.md) 与 [`.gemini/comma
|
|
|
83
85
|
|
|
84
86
|
| 宿主 | 自然入口 |
|
|
85
87
|
|------|----------|
|
|
86
|
-
| Claude Code | `/agestra review`, `/agestra design`, `/agestra idea`, `/agestra implement` |
|
|
88
|
+
| Claude Code | `/agestra setup`, `/agestra review`, `/agestra qa`, `/agestra security`, `/agestra design`, `/agestra idea`, `/agestra implement` |
|
|
87
89
|
| Codex CLI | 按 `AGENTS.md` 指引直接用自然语言发起请求 |
|
|
88
|
-
| Gemini CLI | `/agestra:review`, `/agestra:design`, `/agestra:idea`, `/agestra:implement` |
|
|
90
|
+
| Gemini CLI | `/agestra:setup`, `/agestra:review`, `/agestra:qa`, `/agestra:security`, `/agestra:design`, `/agestra:idea`, `/agestra:implement` |
|
|
89
91
|
|
|
90
92
|
三种宿主都会驱动同一个 MCP 服务,并共享 `commands/*.md` 中的工作流规范。
|
|
91
93
|
|
|
@@ -93,24 +95,29 @@ Gemini 会结合仓库根目录下的 [GEMINI.md](GEMINI.md) 与 [`.gemini/comma
|
|
|
93
95
|
|
|
94
96
|
| 命令 | 说明 |
|
|
95
97
|
|------|------|
|
|
98
|
+
| `/agestra setup` | 初始 AI 提供方选择与设置 |
|
|
96
99
|
| `/agestra review [target]` | 审查代码质量、安全性和集成完成度 |
|
|
100
|
+
| `/agestra qa [target]` | 验证实现结果并生成 PASS/FAIL 证据 |
|
|
101
|
+
| `/agestra security [target]` | 执行专门的安全审查 |
|
|
97
102
|
| `/agestra idea [topic]` | 通过与相似项目对比发掘改进点 |
|
|
98
103
|
| `/agestra design [subject]` | 在实现前探索架构与设计取舍 |
|
|
99
|
-
| `/agestra setup` | 初始 AI 提供方选择与设置 |
|
|
100
104
|
| `/agestra implement [task]` | 以 Claude only 或 Multi-AI 模式执行实现 |
|
|
101
105
|
|
|
102
|
-
|
|
106
|
+
当外部提供方可用时,review、QA、security、design、idea 工作流会经由 team-lead 进入多 AI 交叉验证。当未检测到提供方时,当前宿主的本地 specialist agent 会自动处理。
|
|
103
107
|
|
|
104
108
|
## 代理
|
|
105
109
|
|
|
106
110
|
| 代理 | 模型 | 角色 |
|
|
107
111
|
|------|------|------|
|
|
108
112
|
| `agestra-team-lead` | Sonnet | 全局编排者:环境检查、按质量路由提供方、选择工作模式、监督 CLI Worker、驱动 QA 循环 |
|
|
113
|
+
| `agestra-implementer` | Sonnet | 有范围的实现执行者:代码修改、测试更新、本地验证 |
|
|
114
|
+
| `agestra-e2e-writer` | Sonnet | 持久 E2E 测试作者:只编写已批准的浏览器流程测试 |
|
|
109
115
|
| `agestra-reviewer` | Opus | 严格质量审查者:关注安全、孤立实现、规格漂移、测试缺口 |
|
|
110
116
|
| `agestra-designer` | Opus | 架构探索者:苏格拉底式提问、权衡分析 |
|
|
111
117
|
| `agestra-ideator` | Sonnet | 改进点发现者:Web 调研、竞品分析 |
|
|
112
118
|
| `agestra-moderator` | Sonnet | 多模式主持者:带共识检测的辩论、独立汇总、文档审查、冲突解决 |
|
|
113
119
|
| `agestra-qa` | Opus | QA 验证者:检查设计符合性并给出 PASS/FAIL 判断 |
|
|
120
|
+
| `agestra-security` | Opus | 安全审查者:威胁模型、认证/数据流风险、依赖与密钥卫生 |
|
|
114
121
|
|
|
115
122
|
## 技能
|
|
116
123
|
|
|
@@ -125,6 +132,9 @@ Gemini 会结合仓库根目录下的 [GEMINI.md](GEMINI.md) 与 [`.gemini/comma
|
|
|
125
132
|
| `design` | 包含 Multi-AI 模式选择的架构探索工作流 |
|
|
126
133
|
| `idea` | 包含 Multi-AI 模式选择的改进发现工作流 |
|
|
127
134
|
| `review` | 包含 Multi-AI 模式选择的代码质量·安全·硬编码审查工作流 |
|
|
135
|
+
| `qa` | 设计契约验证与 PASS/FAIL 证据工作流 |
|
|
136
|
+
| `security` | 专门安全审查工作流 |
|
|
137
|
+
| `e2e` | 持久浏览器 E2E 测试编写工作流 |
|
|
128
138
|
| `leader` | 多AI/提供方编排入口 — 捕获明确的提供方、辩论、共识或交叉验证信号,进行领域分类后委托给 `agestra-team-lead` |
|
|
129
139
|
|
|
130
140
|
---
|
|
@@ -147,7 +157,7 @@ Gemini 会结合仓库根目录下的 [GEMINI.md](GEMINI.md) 与 [`.gemini/comma
|
|
|
147
157
|
|
|
148
158
|
- **Provider abstraction** — 所有后端都实现 `AIProvider`(`chat`、`healthCheck`、`getCapabilities`)。新增提供方只需新增一个 provider 包并注册工厂。
|
|
149
159
|
- **Zero-config** — 启动时自动检测提供方,无需手动配置。
|
|
150
|
-
- **Host-native** — Claude 使用插件包,Codex 使用 `AGENTS.md
|
|
160
|
+
- **Host-native** — Claude 使用插件包,Codex 使用 `AGENTS.md` 和 custom agents,Gemini 使用 `GEMINI.md`、commands、skills 或 native extension。所有宿主共享同一套 MCP 服务与工作流核心。
|
|
151
161
|
- **Modular dispatch** — 每类工具都是独立模块,对外提供 `getTools()` 和 `handleTool()`。服务端负责动态收集与分发。
|
|
152
162
|
- **Atomic writes** — 所有文件操作都采用“写临时文件再重命名”的方式,避免损坏。
|
|
153
163
|
- **Dead-end tracking** — 失败方案会被记录,并注入后续提示词。
|
|
@@ -155,11 +165,11 @@ Gemini 会结合仓库根目录下的 [GEMINI.md](GEMINI.md) 与 [`.gemini/comma
|
|
|
155
165
|
|
|
156
166
|
### 工作模式
|
|
157
167
|
|
|
158
|
-
**文本工作**(review、design、idea):有提供方 → 终极辩论模式;无提供方 → Claude only
|
|
168
|
+
**文本工作**(review、QA、security、design、idea):有提供方 → 终极辩论模式;无提供方 → Claude only
|
|
159
169
|
|
|
160
170
|
**实现工作**(team-lead orchestration):
|
|
161
|
-
- **
|
|
162
|
-
-
|
|
171
|
+
- **仅 Claude** — Claude 直接结合项目/全局代理完成实现。
|
|
172
|
+
- **与其他 AI 一起** — CLI Worker(Codex/Gemini)在隔离的 git worktree 中自主编码,Ollama 处理简单任务,Claude 负责监督与合并。
|
|
163
173
|
|
|
164
174
|
---
|
|
165
175
|
|
|
@@ -237,7 +247,7 @@ Gemini 会结合仓库根目录下的 [GEMINI.md](GEMINI.md) 与 [`.gemini/comma
|
|
|
237
247
|
|
|
238
248
|
| 工具 | 说明 |
|
|
239
249
|
|------|------|
|
|
240
|
-
| `host_assets_status` | 检查 Codex custom agents 等生成的宿主原生资产 |
|
|
250
|
+
| `host_assets_status` | 检查 Codex custom agents、Gemini assets 等生成的宿主原生资产 |
|
|
241
251
|
| `host_assets_install` | 显式安装或刷新受管宿主原生资产 |
|
|
242
252
|
| `host_assets_uninstall` | 移除 Agestra 追踪的受管宿主原生资产 |
|
|
243
253
|
|
|
@@ -326,21 +336,30 @@ agestra/
|
|
|
326
336
|
├── .gemini/
|
|
327
337
|
│ └── commands/
|
|
328
338
|
│ └── agestra/
|
|
339
|
+
│ ├── setup.toml # Gemini CLI 的 /agestra:setup
|
|
329
340
|
│ ├── review.toml # Gemini CLI 的 /agestra:review
|
|
330
341
|
│ ├── design.toml # Gemini CLI 的 /agestra:design
|
|
331
342
|
│ ├── idea.toml # Gemini CLI 的 /agestra:idea
|
|
332
|
-
│
|
|
343
|
+
│ ├── implement.toml # Gemini CLI 的 /agestra:implement
|
|
344
|
+
│ ├── qa.toml # Gemini CLI 的 /agestra:qa
|
|
345
|
+
│ └── security.toml # Gemini CLI 的 /agestra:security
|
|
333
346
|
├── commands/
|
|
347
|
+
│ ├── setup.md # /agestra setup — 提供方设置
|
|
334
348
|
│ ├── review.md # /agestra review — 质量验证
|
|
349
|
+
│ ├── qa.md # /agestra qa — PASS/FAIL 验证
|
|
350
|
+
│ ├── security.md # /agestra security — 安全审查
|
|
335
351
|
│ ├── idea.md # /agestra idea — 改进点发现
|
|
336
352
|
│ ├── design.md # /agestra design — 架构探索
|
|
337
353
|
│ └── implement.md # /agestra implement — 实现工作流
|
|
338
354
|
├── agents/
|
|
355
|
+
│ ├── agestra-implementer.md # 有范围的实现执行者(Sonnet)
|
|
356
|
+
│ ├── agestra-e2e-writer.md # 持久 E2E 测试作者(Sonnet)
|
|
339
357
|
│ ├── agestra-reviewer.md # 严格质量审查者(Opus)
|
|
340
358
|
│ ├── agestra-designer.md # 架构探索者(Opus)
|
|
341
359
|
│ ├── agestra-ideator.md # 改进点发现者(Sonnet)
|
|
342
360
|
│ ├── agestra-moderator.md # 多模式主持者(Sonnet)
|
|
343
361
|
│ ├── agestra-qa.md # QA 验证者(Opus,不写代码)
|
|
362
|
+
│ ├── agestra-security.md # 安全审查者(Opus)
|
|
344
363
|
│ └── agestra-team-lead.md # 全局编排者(Sonnet,不写代码)
|
|
345
364
|
├── skills/
|
|
346
365
|
│ ├── provider-guide.md # 提供方路由与模式说明
|
|
@@ -352,6 +371,9 @@ agestra/
|
|
|
352
371
|
│ ├── design.md # 架构探索工作流
|
|
353
372
|
│ ├── idea.md # 改进发现工作流
|
|
354
373
|
│ ├── review.md # 代码质量审查工作流
|
|
374
|
+
│ ├── qa.md # 设计契约 QA 工作流
|
|
375
|
+
│ ├── security.md # 专门安全审查工作流
|
|
376
|
+
│ ├── e2e.md # 持久 E2E 测试编写工作流
|
|
355
377
|
│ └── leader.md # 多AI 编排路由器
|
|
356
378
|
├── hooks/
|
|
357
379
|
│ └── user-prompt-submit.md # 工具推荐 hook
|
|
@@ -403,7 +425,7 @@ npm run uninstall:gemini
|
|
|
403
425
|
npm run uninstall:gemini:assets
|
|
404
426
|
```
|
|
405
427
|
|
|
406
|
-
`*:assets`
|
|
428
|
+
`*:assets` 卸载命令会同时移除宿主注册和未修改的生成宿主资产。Codex assets 是 custom-agent 文件。Gemini project-scope assets 是受管文件,Gemini user-scope assets 通过 `gemini extensions uninstall agestra` 移除。如果用户编辑过生成资产,Agestra 会保留该文件并报告。使用全局 npm 安装时,请运行 `agestra-uninstall codex --assets` 或 `agestra-uninstall gemini --assets --scope user`。
|
|
407
429
|
|
|
408
430
|
如果还想删除生成的项目数据,请手动删除 `.agestra/` 目录。
|
|
409
431
|
|
|
@@ -36,7 +36,7 @@ description: |
|
|
|
36
36
|
model: opus
|
|
37
37
|
color: blue
|
|
38
38
|
codexSandboxMode: workspace-write
|
|
39
|
-
|
|
39
|
+
tools: Read, Glob, Grep, Bash, WebFetch, WebSearch, TodoWrite, AskUserQuestion, Skill, ToolSearch, CronCreate, CronList, CronDelete, Agent, Write
|
|
40
40
|
---
|
|
41
41
|
|
|
42
42
|
<Role>
|
|
@@ -35,7 +35,7 @@ description: |
|
|
|
35
35
|
model: sonnet
|
|
36
36
|
color: green
|
|
37
37
|
codexSandboxMode: workspace-write
|
|
38
|
-
|
|
38
|
+
tools: Read, Glob, Grep, Bash, WebFetch, WebSearch, TodoWrite, AskUserQuestion, Skill, ToolSearch, CronCreate, CronList, CronDelete, Agent, Write
|
|
39
39
|
---
|
|
40
40
|
|
|
41
41
|
<Role>
|
|
@@ -61,7 +61,7 @@ description: |
|
|
|
61
61
|
model: sonnet
|
|
62
62
|
color: cyan
|
|
63
63
|
codexSandboxMode: read-only
|
|
64
|
-
|
|
64
|
+
tools: Read, Glob, Grep, Bash, WebFetch, WebSearch, TodoWrite, AskUserQuestion, Skill, ToolSearch, CronCreate, CronList, CronDelete, Agent, mcp__plugin_agestra_agestra__provider_list, mcp__plugin_agestra_agestra__agent_debate_structured, mcp__plugin_agestra_agestra__agent_debate_status, mcp__plugin_agestra_agestra__agent_debate_approve, mcp__plugin_agestra_agestra__agent_debate_continue, mcp__plugin_agestra_agestra__agent_debate_reject, mcp__plugin_agestra_agestra__agent_debate_review, mcp__plugin_agestra_agestra__ai_chat, mcp__plugin_agestra_agestra__workspace_read, mcp__plugin_agestra_agestra__workspace_create_document
|
|
65
65
|
---
|
|
66
66
|
|
|
67
67
|
<Role>
|
|
@@ -512,5 +512,4 @@ If `max_rounds` is hit with open proposals, the moderator surfaces the choice to
|
|
|
512
512
|
- `ai_chat` — query individual providers for feedback (Independent Aggregation mode).
|
|
513
513
|
- `workspace_create_document` — create analysis or aggregated documents (Independent Aggregation mode).
|
|
514
514
|
- `workspace_read` — read individual provider documents by ID (Independent Aggregation mode).
|
|
515
|
-
- `workspace_replace_document_content` — replace generated debate or synthesis markdown when the engine regenerates output from the ledger.
|
|
516
515
|
</Tool_Usage>
|
package/agents/agestra-qa.md
CHANGED
|
@@ -39,7 +39,7 @@ description: |
|
|
|
39
39
|
model: opus
|
|
40
40
|
color: yellow
|
|
41
41
|
codexSandboxMode: workspace-write
|
|
42
|
-
|
|
42
|
+
tools: Read, Glob, Grep, Bash, WebFetch, WebSearch, TodoWrite, AskUserQuestion, Skill, ToolSearch, CronCreate, CronList, CronDelete, Agent, Write
|
|
43
43
|
---
|
|
44
44
|
|
|
45
45
|
<Role>
|
|
@@ -37,7 +37,7 @@ description: |
|
|
|
37
37
|
model: opus
|
|
38
38
|
color: red
|
|
39
39
|
codexSandboxMode: workspace-write
|
|
40
|
-
|
|
40
|
+
tools: Read, Glob, Grep, Bash, WebFetch, WebSearch, TodoWrite, AskUserQuestion, Skill, ToolSearch, CronCreate, CronList, CronDelete, Agent, Write
|
|
41
41
|
---
|
|
42
42
|
|
|
43
43
|
<Role>
|
|
@@ -18,7 +18,7 @@ description: |
|
|
|
18
18
|
model: opus
|
|
19
19
|
color: red
|
|
20
20
|
codexSandboxMode: workspace-write
|
|
21
|
-
|
|
21
|
+
tools: Read, Glob, Grep, Bash, WebFetch, WebSearch, TodoWrite, AskUserQuestion, Skill, ToolSearch, CronCreate, CronList, CronDelete, Agent, Write
|
|
22
22
|
---
|
|
23
23
|
|
|
24
24
|
<Role>
|
|
@@ -70,7 +70,7 @@ description: |
|
|
|
70
70
|
model: sonnet
|
|
71
71
|
color: magenta
|
|
72
72
|
codexSandboxMode: read-only
|
|
73
|
-
|
|
73
|
+
tools: Read, Glob, Grep, Bash, WebFetch, WebSearch, TodoWrite, AskUserQuestion, Skill, ToolSearch, CronCreate, CronList, CronDelete, Agent, mcp__plugin_agestra_agestra__environment_check, mcp__plugin_agestra_agestra__provider_list, mcp__plugin_agestra_agestra__provider_health, mcp__plugin_agestra_agestra__trace_query, mcp__plugin_agestra_agestra__trace_summary, mcp__plugin_agestra_agestra__trace_visualize, mcp__plugin_agestra_agestra__ai_chat, mcp__plugin_agestra_agestra__ai_analyze_files, mcp__plugin_agestra_agestra__ai_compare, mcp__plugin_agestra_agestra__agent_debate_structured, mcp__plugin_agestra_agestra__agent_debate_status, mcp__plugin_agestra_agestra__agent_debate_approve, mcp__plugin_agestra_agestra__agent_debate_continue, mcp__plugin_agestra_agestra__agent_debate_reject, mcp__plugin_agestra_agestra__agent_cross_validate, mcp__plugin_agestra_agestra__cli_worker_spawn, mcp__plugin_agestra_agestra__cli_worker_status, mcp__plugin_agestra_agestra__cli_worker_collect, mcp__plugin_agestra_agestra__cli_worker_stop, mcp__plugin_agestra_agestra__agent_changes_review, mcp__plugin_agestra_agestra__agent_changes_accept, mcp__plugin_agestra_agestra__agent_changes_reject
|
|
74
74
|
---
|
|
75
75
|
|
|
76
76
|
<Role>
|
|
@@ -252,7 +252,7 @@ Execute approved tasks across available execution paths:
|
|
|
252
252
|
|
|
253
253
|
**Result Integration:**
|
|
254
254
|
- Leader-host implementation: changes are already applied on the main branch (no merge needed).
|
|
255
|
-
- CLI workers: call `agent_changes_review` to
|
|
255
|
+
- CLI workers: call `agent_changes_review` to inspect the full diff. Do **not** accept here — Phase 4 step 7 owns the supervised/autonomous accept gate.
|
|
256
256
|
- File overlap between tracks: detect conflicts between implementer-applied changes and CLI worker worktrees. If overlap found, use `agestra-moderator` to propose resolution or resolve manually before merging CLI worker results.
|
|
257
257
|
|
|
258
258
|
### Phase 4: Result Inspection
|
|
@@ -273,7 +273,9 @@ After each task completes:
|
|
|
273
273
|
- Import/export chains are complete
|
|
274
274
|
6. If issues found → craft a detailed correction prompt and re-assign to the same AI or send a scoped fix task to `agestra-implementer`.
|
|
275
275
|
7. If all checks pass:
|
|
276
|
-
- For CLI worker tasks:
|
|
276
|
+
- For CLI worker tasks: gate `agent_changes_accept` by execution mode.
|
|
277
|
+
- **Supervised (default):** Summarize the diff (files touched, scope, risk highlights) and use `AskUserQuestion` to confirm the merge before calling `agent_changes_accept`. Call `agent_changes_reject` only after an explicit user rejection with a reason. If the user does not respond or `AskUserQuestion` is unavailable, leave the worker worktree pending, report the task ID, and wait for a later accept/reject decision.
|
|
278
|
+
- **Autonomous:** Record the review evidence in your status update (files, design alignment notes), then call `agent_changes_accept`. Escalate to the user instead of auto-accepting when the diff exceeds the worker's stated scope, adds unrequested files, or touches a file flagged as high-risk in Phase 2.
|
|
277
279
|
- For rejected CLI worker tasks: call `agent_changes_reject` with reason
|
|
278
280
|
- Proceed to verification:
|
|
279
281
|
- **Multi-AI mode** → Phase 5M (Structured Debate) replaces the separate QA and post-implementation review phases.
|
package/dist/bundle.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire as ___cr } from 'module';import { fileURLToPath as ___fu } from 'url';import { dirname as ___dn } from 'path';const __filename = ___fu(import.meta.url);const __dirname = ___dn(__filename);const require = ___cr(import.meta.url);
|
|
3
|
-
var IR=Object.create;var Cd=Object.defineProperty;var RR=Object.getOwnPropertyDescriptor;var AR=Object.getOwnPropertyNames;var CR=Object.getPrototypeOf,DR=Object.prototype.hasOwnProperty;var Ar=(t,e)=>()=>(t&&(e=t(t=0)),e);var S=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports),rt=(t,e)=>{for(var r in e)Cd(t,r,{get:e[r],enumerable:!0})},OR=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of AR(e))!DR.call(t,s)&&s!==r&&Cd(t,s,{get:()=>e[s],enumerable:!(n=RR(e,s))||n.enumerable});return t};var Gy=(t,e,r)=>(r=t!=null?IR(CR(t)):{},OR(e||!t||!t.__esModule?Cd(r,"default",{value:t,enumerable:!0}):r,t));var Yy,si,Xy,Qy,ev,tv,rv,oi,nv,As,sv,ov,iv,av,cv,uv,In,Dd,Od,PK,kK,Md,lv,dv,ic,Rn,zd,pv,fv,Cs,Cr=Ar(()=>{"use strict";Yy="4.13.
|
|
3
|
+
var IR=Object.create;var Cd=Object.defineProperty;var RR=Object.getOwnPropertyDescriptor;var AR=Object.getOwnPropertyNames;var CR=Object.getPrototypeOf,DR=Object.prototype.hasOwnProperty;var Ar=(t,e)=>()=>(t&&(e=t(t=0)),e);var S=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports),rt=(t,e)=>{for(var r in e)Cd(t,r,{get:e[r],enumerable:!0})},OR=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of AR(e))!DR.call(t,s)&&s!==r&&Cd(t,s,{get:()=>e[s],enumerable:!(n=RR(e,s))||n.enumerable});return t};var Gy=(t,e,r)=>(r=t!=null?IR(CR(t)):{},OR(e||!t||!t.__esModule?Cd(r,"default",{value:t,enumerable:!0}):r,t));var Yy,si,Xy,Qy,ev,tv,rv,oi,nv,As,sv,ov,iv,av,cv,uv,In,Dd,Od,PK,kK,Md,lv,dv,ic,Rn,zd,pv,fv,Cs,Cr=Ar(()=>{"use strict";Yy="4.13.1",si="http://localhost:11434",Xy="llama3",Qy=".agestra/.jobs",ev=".agestra/traces",tv=".agestra/worktrees",rv=".agestra/sessions",oi=".agestra/workspace",nv="individual",As="debates",sv="synthesis",ov="issue",iv=".agestra/workers",av=Object.freeze(["PATH","HOME","USER","USERPROFILE","APPDATA","LOCALAPPDATA","TEMP","TMP","TMPDIR","SHELL","LANG","LC_ALL","NODE_PATH","SystemRoot","SystemDrive","COMSPEC","ComSpec","windir"]),cv=2,uv=6e4,In=20,Dd=5e4,Od=10,PK=Object.freeze([3,5,10]),kK=Object.freeze(["agree","disagree","abstain","revise"]),Md=2,lv=1440*60*1e3,dv=3600*1e3,ic=Object.freeze(["ko","zh","ja","en"]),Rn="ko",zd="en",pv="[REDACTED]",fv=["","--- REQUIRED RESPONSE FORMAT ---","Respond with JSON only, matching exactly this shape:",'{ "agrees": true | false, "feedback": "specific issues or why you agree", "suggestions": "concrete changes if you disagree (optional, may be omitted)" }',"No prose, markdown, or explanation outside the JSON object. The JSON must be the entire response or wrapped in a single ```json code fence.","-------------------------------"].join(`
|
|
4
4
|
`),Cs=Object.freeze({auto:Object.freeze({name:"auto",description:"Auto-detect build profile from project structure (package.json scripts, tsconfig, vitest config, etc.).",command:"npx",args:Object.freeze([])}),tsc:Object.freeze({name:"tsc",description:"TypeScript project-references build via `npx tsc -b --noEmit`.",command:"npx",args:Object.freeze(["tsc","-b","--noEmit"])}),vitest:Object.freeze({name:"vitest",description:"Run the Vitest unit-test suite in CI mode.",command:"npx",args:Object.freeze(["vitest","run","--reporter=dot"])}),"npm-build":Object.freeze({name:"npm-build",description:"Run the project's `npm run build` script.",command:"npm",args:Object.freeze(["run","build"])}),"npm-test":Object.freeze({name:"npm-test",description:"Run the project's `npm test` script.",command:"npm",args:Object.freeze(["test","--","--run"])})})});import{execFileSync as MR}from"child_process";function Ds(t){if(!Number.isFinite(t)||t<=0)return{delivered:!1};if(process.platform==="win32")try{return MR("taskkill",["/PID",String(t),"/T","/F"],{stdio:"ignore",windowsHide:!0}),{delivered:!0}}catch{try{return process.kill(t),{delivered:!0}}catch{return{delivered:!1}}}try{return process.kill(-t,"SIGTERM"),{delivered:!0}}catch{try{return process.kill(t,"SIGTERM"),{delivered:!0}}catch{return{delivered:!1}}}}function Qt(t,e=3e3){let r=t.pid;if(r)Ds(r);else try{t.kill("SIGTERM")}catch{}setTimeout(()=>{try{t.kill("SIGKILL")}catch{}},e).unref?.()}var Os=Ar(()=>{"use strict"});import{execFileSync as zR,spawn as jR}from"child_process";import{existsSync as NR}from"fs";function mv(t){let e=t.replace(/\s+/g," ").trim();return e.length>200?`${e.slice(0,200)}...`:e}function Yr(t,e){if(t)try{t({...e,at:new Date().toISOString()})}catch{}}function qR(t){return process.platform!=="win32"||t.includes("/")||t.includes("\\")?!1:LR.has(t.toLowerCase())}function FR(t){if(t.includes("\0"))throw new Error(`Windows shim arg contains null byte: ${JSON.stringify(t)}`);if(t.includes("%"))throw new Error(`Windows shim arg contains '%' which would trigger cmd.exe env expansion: ${JSON.stringify(t)}`);return/[\s"&^<>|()!]/.test(t)?`"${t.replace(/"/g,'""')}"`:t}function UR(t){let e=t.toLowerCase();if(Ms.has(e))return Ms.get(e)??null;try{let n=zR("where.exe",[t],{encoding:"utf-8",stdio:["ignore","pipe","ignore"],windowsHide:!0,timeout:5e3}).split(/\r?\n/).map(a=>a.trim()).filter(Boolean);if(n.length===0)return Ms.set(e,null),null;let s=n.find(a=>/\.(cmd|bat)$/i.test(a));if(s){let a={type:"cmd",path:s};return Ms.set(e,a),a}let i=`${n[0]}.ps1`;if(NR(i)){let a={type:"powershell",path:i};return Ms.set(e,a),a}}catch{}return Ms.set(e,null),null}function An(t,e){if(!qR(t))return{command:t,args:e};let r=UR(t);return r?r.type==="cmd"?{command:"cmd.exe",args:["/d","/s","/c",r.path,...e.map(n=>FR(n))]}:{command:"powershell.exe",args:["-NoProfile","-ExecutionPolicy","RemoteSigned","-File",r.path,...e]}:{command:t,args:e}}function vt(t){let{command:e,args:r,timeout:n=12e4,overallTimeoutMs:s,cwd:o,env:i,stdin:a,maxBuffer:c=10485760,onStderrChunk:u,onActivity:l,signal:d}=t;return new Promise((p,f)=>{if(d?.aborted){Yr(l,{type:"abort",command:e,args:r,reason:String(d.reason??"aborted before spawn")}),f(new jt(d.reason));return}let m=An(e,r);Yr(l,{type:"start",command:m.command,args:m.args,timeoutMs:n});let h=jR(m.command,m.args,{cwd:o,env:i?{...process.env,...i}:void 0,stdio:[a?"pipe":"ignore","pipe","pipe"],windowsHide:!0}),y="",g="",b=0,_=0,P=!1,x=null,N=!1,k=null,O=()=>{k&&d&&d.removeEventListener("abort",k)},L=!1,q=()=>{!L&&b+_>c&&(P=!0,L=!0,Qt(h))},$e=null,We=()=>{$e&&(clearTimeout($e),$e=null)},Rt=()=>{N||(Qt(h),N=!0,We(),O(),Yr(l,{type:"timeout",command:e,args:r,timeoutMs:n}),f(new Error(`CLI timeout after ${n}ms of inactivity: ${e} ${r.join(" ")}`)))},zt=setTimeout(Rt,n);$e=s!==void 0?setTimeout(()=>{N||(Qt(h),N=!0,clearTimeout(zt),We(),O(),Yr(l,{type:"timeout",command:e,args:r,timeoutMs:s}),f(new Error(`CLI overall timeout after ${s}ms: ${e} ${r.join(" ")}`)))},s):null,d&&(k=()=>{N||(N=!0,clearTimeout(zt),We(),Qt(h),O(),Yr(l,{type:"abort",command:e,args:r,reason:String(d.reason??"aborted")}),f(new jt(d.reason)))},d.addEventListener("abort",k));let Ts=()=>{L||(clearTimeout(zt),zt=setTimeout(Rt,n))};if(h.stdout.on("data",At=>{b+=At.length,Yr(l,{type:"stdout",command:e,args:r,preview:mv(At.toString())}),b<=c&&(y+=At.toString()),q(),Ts()}),h.stderr.on("data",At=>{_+=At.length;let Tn=At.toString();if(Yr(l,{type:"stderr",command:e,args:r,preview:mv(Tn)}),_<=c&&(g+=Tn),q(),!L&&u){let ni=u(Tn);ni&&(x=ni,L=!0,Qt(h))}Ts()}),a&&h.stdin){h.stdin.on("error",()=>{});try{h.stdin.write(a),h.stdin.end()}catch{}}h.on("close",(At,Tn)=>{if(clearTimeout(zt),We(),!N){if(Yr(l,{type:"close",command:e,args:r,exitCode:At,signalCode:Tn}),x){N=!0,O(),f(x);return}N=!0,O(),p({stdout:y,stderr:g,exitCode:At??1,truncated:P})}}),h.on("error",At=>{clearTimeout(zt),We(),!N&&(N=!0,O(),f(new Error(`CLI spawn error: ${At.message}`)))})})}var jt,LR,Ms,ii=Ar(()=>{"use strict";Os();jt=class extends Error{constructor(e){let r=e instanceof Error?`: ${e.message}`:typeof e=="string"&&e?`: ${e}`:"";super(`CLI aborted${r}`),this.name="CliAbortedError"}};LR=new Set(["codex","gemini","npm","npx"]),Ms=new Map});import{writeFileSync as dC,mkdirSync as di,openSync as Fd,writeSync as Ud,fsyncSync as Ov,closeSync as Zd,renameSync as pC,unlinkSync as Dv,appendFileSync as fC,copyFileSync as mC}from"fs";import{dirname as pi,join as hC}from"path";import{randomUUID as gC}from"crypto";function ge(t,e){let r=pi(t);di(r,{recursive:!0});let n=hC(r,`.tmp-${gC().slice(0,8)}`);try{dC(n,e,"utf-8");try{pC(n,t)}catch(s){if(s.code!=="EXDEV")throw s;mC(n,t),Dv(n)}}catch(s){try{Dv(n)}catch{}throw s}}function Ze(t,e){ge(t,JSON.stringify(e,null,2))}function _c(t,e){let r=pi(t);di(r,{recursive:!0});let n=Fd(t,"a");try{Ud(n,e),Ov(n)}finally{Zd(n)}}var vc,nn=Ar(()=>{"use strict";vc=class{buffer=new Map;flushTimer=null;flushIntervalMs;maxBufferSize;auditFsync;destroyed=!1;constructor(e){this.flushIntervalMs=e?.flushIntervalMs??2e3,this.maxBufferSize=e?.maxBufferSize??100,this.auditFsync=e?.auditFsync??!0,this.flushIntervalMs>0&&(this.flushTimer=setInterval(()=>this.flush(),this.flushIntervalMs),this.flushTimer&&typeof this.flushTimer.unref=="function"&&this.flushTimer.unref())}append(e,r,n){if(this.destroyed)throw new Error("DurableAppendWriter has been destroyed");if(n==="audit"){if(this.auditFsync)_c(e,r);else{let o=pi(e);di(o,{recursive:!0}),fC(e,r)}return}let s=this.buffer.get(e);s||(s=[],this.buffer.set(e,s)),s.push(r),s.length>=this.maxBufferSize&&this.flushFile(e),this.flushIntervalMs===0&&this.flushFile(e)}flush(){for(let e of this.buffer.keys())this.flushFile(e)}panicFlush(){for(let[e,r]of this.buffer)if(r.length!==0)try{let n=pi(e);di(n,{recursive:!0});let s=Fd(e,"a");try{Ud(s,r.join("")),Ov(s)}finally{Zd(s)}}catch{}this.buffer.clear()}destroy(){this.destroyed||(this.destroyed=!0,this.flushTimer!==null&&(clearInterval(this.flushTimer),this.flushTimer=null),this.flush())}flushFile(e){let r=this.buffer.get(e);if(!r||r.length===0)return;let n=pi(e);di(n,{recursive:!0});let s=Fd(e,"a");try{Ud(s,r.join(""))}finally{Zd(s)}this.buffer.delete(e)}}});import{openSync as yC,writeSync as vC,closeSync as _C,unlinkSync as Mv,statSync as bC,mkdirSync as wC,existsSync as SC}from"fs";import{dirname as $C}from"path";function EC(t){if(t<=0)return;let e=new SharedArrayBuffer(4),r=new Int32Array(e);Atomics.wait(r,0,0,t)}function Kn(t,e,r={}){let n=r.staleMs??xC,s=r.acquireTimeoutMs??PC,o=r.pollMs??kC;wC($C(t),{recursive:!0});let i=Date.now(),a=null;for(;a===null;)try{a=yC(t,"wx")}catch(c){let u=c.code;if(!(u==="EEXIST"||process.platform==="win32"&&u==="EPERM"&&SC(t)))throw c;let d=!1;try{let f=bC(t);d=Date.now()-f.mtimeMs>n}catch{continue}if(d){try{Mv(t)}catch{}continue}let p=Date.now()-i;if(p>=s)throw new Vd(t,p);EC(o)}try{try{vC(a,`${process.pid}@${Date.now()}
|
|
5
5
|
`)}catch{}return e()}finally{try{_C(a)}catch{}try{Mv(t)}catch{}}}var xC,PC,kC,Vd,bc=Ar(()=>{"use strict";xC=3e4,PC=5e3,kC=10,Vd=class extends Error{constructor(e,r){super(`withFileLock: timed out after ${r}ms waiting for ${e}`),this.name="FileLockTimeoutError"}}});import{existsSync as zv,realpathSync as TC}from"fs";import{basename as IC,dirname as RC,isAbsolute as Hd,join as AC,normalize as Nv,resolve as Wd,relative as CC}from"path";function DC(t){return t===""||!t.startsWith("..")&&!Hd(t)}function Bd(t){let e=[],r=Wd(t);for(;!zv(r);){let s=RC(r);if(s===r)break;e.unshift(IC(r)),r=s}let n=zv(r)?TC(r):r;return e.reduce((s,o)=>AC(s,o),n)}function Lv(t,e){let r=Bd(e),n=Bd(t),s=CC(r,n);return DC(s)}function Kd(t,e){let r=Wd(e,t);return Lv(r,e)}function Ft(t,e){let r=Wd(e,t);if(!Lv(r,e))throw new Error(`Path traversal blocked: ${t} escapes ${e}`);return r}function Je(t,e){if(t.length===0)throw new Error("Filename must not be empty");if(t.includes("\0"))throw new Error(`Filename contains null byte: ${JSON.stringify(t)}`);if(t.includes("/")||t.includes("\\"))throw new Error(`Filename must not contain path separators: ${JSON.stringify(t)}`);if(t.includes(".."))throw new Error(`Filename must not contain '..': ${JSON.stringify(t)}`);return Ft(t,e)}function sn(t,e){if(Hd(t)){let r=Nv(t);if(!Kd(r,e))throw new Error(`Read path outside base directory: ${t} is not within ${e}`);return r}return Ft(t,e)}function qv(t,e){return Hd(t)?Bd(Nv(t)):Ft(t,e)}function Nr(t){return OC.test(t)}function wc(t,e){if(!t||typeof t!="string")throw new Ct(String(t),"command must be a non-empty string");if(t.includes("\0"))throw new Ct(t,"command contains null byte");if(t.includes("/")||t.includes("\\"))throw new Ct(t,"command must not contain path separators");if(!jv.has(t))throw new Ct(t,`command is not in the allowlist (${[...jv].join(", ")})`);for(let r of e){if(typeof r!="string")throw new Ct(t,`args contain a non-string entry: ${JSON.stringify(r)}`);if(r.includes("\0"))throw new Ct(t,`arg contains null byte: ${JSON.stringify(r)}`);if(MC.has(r))throw new Ct(t,`arg ${JSON.stringify(r)} is a code-execution flag and is not permitted`)}}var OC,jv,MC,Ct,Vs=Ar(()=>{"use strict";OC=/^[a-zA-Z0-9_-]+-\d+-[a-f0-9]{6}$/;jv=new Set(["gemini","codex","claude","npx","node","npm","tsc"]),MC=new Set(["-e","--eval","-c","--command","-E","--execute","--exec"]),Ct=class extends Error{command;reason;constructor(e,r){super(`CLI command rejected: ${e} \u2014 ${r}`),this.command=e,this.reason=r,this.name="CliCommandRejectedError"}}});import{readFileSync as zC}from"fs";import{join as jC}from"path";function Ve(t,e){let r=jC(t,"status.json"),n=`${r}.lock`;Kn(n,()=>{let s=JSON.parse(zC(r,"utf-8"));Ze(r,{...s,...e})})}var fi=Ar(()=>{"use strict";nn();bc()});import{spawn as NC}from"child_process";import{join as Jd}from"path";function Fv(t){let e=t.replace(/\s+/g," ").trim();return e.length>200?`${e.slice(0,200)}...`:e}function Sc(t){return new Promise(e=>{let r=An(t.command,t.args),n={kind:"start",updatedAt:new Date().toISOString(),message:"CLI process started",command:r.command,timeoutMs:t.timeoutMs,stdoutBytes:0,stderrBytes:0},s=0,o,i=(y,g={})=>{Object.assign(n,y,{updatedAt:new Date().toISOString()});let b=Date.now(),_=n.kind!==o;if(!(!g.force&&!_&&b-s<LC))try{Ve(t.jobDir,{activity:{...n}}),s=b,o=n.kind}catch{}};i(n,{force:!0});let a=NC(r.command,r.args,{cwd:t.cwd,stdio:["ignore","pipe","pipe"],windowsHide:!0});if(t.recordPid&&typeof a.pid=="number"&&a.pid>0)try{Ve(t.jobDir,{pid:a.pid})}catch{}if(!a.stdout||!a.stderr){try{a.kill()}catch{}try{ge(Jd(t.jobDir,"error.txt"),"Worker stdout/stderr streams unavailable (pipe allocation failed)"),Ve(t.jobDir,{state:"error",completedAt:new Date().toISOString()})}catch{}e();return}let c="",u="",l=0,d=0,p=!1,f=!1;a.stdout.on("data",y=>{l+=y.length,i({kind:"stdout",message:"stdout received",stdoutBytes:l,stderrBytes:d,lastStdoutPreview:Fv(y.toString())}),l<=10485760?c+=y.toString():p||(p=!0,Qt(a))}),a.stderr.on("data",y=>{d+=y.length,i({kind:"stderr",message:"stderr received",stdoutBytes:l,stderrBytes:d,lastStderrPreview:Fv(y.toString())}),d<=10485760&&(u+=y.toString())});let m=(y,g)=>{if(!f){f=!0,clearTimeout(h);try{ge(Jd(t.jobDir,"output.txt"),c),ge(Jd(t.jobDir,"error.txt"),g!==void 0?g:u),Ve(t.jobDir,y)}catch{}e()}},h=setTimeout(()=>{Qt(a),i({kind:"timeout",message:`timed out after ${t.timeoutMs}ms`,timeoutMs:t.timeoutMs,stdoutBytes:l,stderrBytes:d},{force:!0}),m({state:"timed_out",completedAt:new Date().toISOString()})},t.timeoutMs);a.on("close",y=>{if(f)return;let g=c.trim().length>0,b=y===0||g?"completed":"error";i({kind:"close",message:"CLI process closed",exitCode:y??1,stdoutBytes:l,stderrBytes:d},{force:!0}),m({state:b,exitCode:y??1,completedAt:new Date().toISOString()})}),a.on("error",y=>{if(f)return;let g=y.code==="ENOENT"?"missing_cli":"error";i({kind:"close",message:`CLI spawn error: ${y.message}`,stdoutBytes:l,stderrBytes:d},{force:!0}),m({state:g,completedAt:new Date().toISOString()},y.message)})})}var LC,Gd=Ar(()=>{"use strict";nn();ii();Os();fi();LC=1e3});var Bv={};rt(Bv,{CLI_PROVIDERS:()=>Zv,resolveCliConfig:()=>Vv});import{readFileSync as Uv}from"fs";import{join as Jn}from"path";function Vv(t){let e=qC[t.provider]??t.provider;return Zv[e]??null}async function FC(){let t=process.argv[2];t||process.exit(1);let e;try{e=JSON.parse(Uv(Jn(t,"job.json"),"utf-8"))}catch{try{Ze(Jn(t,"status.json"),{id:"unknown",state:"error",provider:"unknown",completedAt:new Date().toISOString()}),ge(Jn(t,"error.txt"),"Failed to read job.json")}catch{}process.exit(1)}let r=Vv(e);r||(Ve(t,{state:"missing_cli",completedAt:new Date().toISOString()}),ge(Jn(t,"error.txt"),`No CLI mapping for provider: ${e.provider}`),process.exit(1));let{command:n,buildArgs:s}=r;Ve(t,{state:"running",startedAt:new Date().toISOString()});let o=Uv(Jn(t,"prompt.txt"),"utf-8"),i=s(o);try{wc(n,i)}catch(c){let u=c instanceof Ct?c.message:`Argv rejected: ${c.message}`;Ve(t,{state:"error",completedAt:new Date().toISOString()}),ge(Jn(t,"error.txt"),u);return}let a;if(e.cwd)try{a=Ft(e.cwd,process.cwd())}catch(c){Ve(t,{state:"error",completedAt:new Date().toISOString()}),ge(Jn(t,"error.txt"),`Rejected descriptor.cwd: ${c.message}`);return}await Sc({jobDir:t,command:n,args:i,cwd:a,timeoutMs:e.timeout,recordPid:!1})}var qC,Zv,UC,Hv=Ar(()=>{"use strict";nn();Vs();Gd();fi();qC={"gemini-cli":"gemini","codex-cli":"codex","claude-cli":"claude"},Zv={gemini:{command:"gemini",buildArgs:t=>["-p",t]},codex:{command:"codex",buildArgs:t=>["exec","--skip-git-repo-check","--full-auto","--ephemeral",t]},claude:{command:"claude",buildArgs:t=>["-p",t]}};UC=process.argv[1]?.endsWith("job-worker.js")||process.argv[1]?.endsWith("job-worker.ts");UC&&FC().catch(()=>process.exit(1))});var Qi=S(me=>{"use strict";Object.defineProperty(me,"__esModule",{value:!0});me.regexpCode=me.getEsmExportName=me.getProperty=me.safeStringify=me.stringify=me.strConcat=me.addCodeArg=me.str=me._=me.nil=me._Code=me.Name=me.IDENTIFIER=me._CodeOrName=void 0;var Yi=class{};me._CodeOrName=Yi;me.IDENTIFIER=/^[a-z$_][a-z$_0-9]*$/i;var ss=class extends Yi{constructor(e){if(super(),!me.IDENTIFIER.test(e))throw new Error("CodeGen: name must be a valid identifier");this.str=e}toString(){return this.str}emptyStr(){return!1}get names(){return{[this.str]:1}}};me.Name=ss;var Bt=class extends Yi{constructor(e){super(),this._items=typeof e=="string"?[e]:e}toString(){return this.str}emptyStr(){if(this._items.length>1)return!1;let e=this._items[0];return e===""||e==='""'}get str(){var e;return(e=this._str)!==null&&e!==void 0?e:this._str=this._items.reduce((r,n)=>`${r}${n}`,"")}get names(){var e;return(e=this._names)!==null&&e!==void 0?e:this._names=this._items.reduce((r,n)=>(n instanceof ss&&(r[n.str]=(r[n.str]||0)+1),r),{})}};me._Code=Bt;me.nil=new Bt("");function Q$(t,...e){let r=[t[0]],n=0;for(;n<e.length;)Df(r,e[n]),r.push(t[++n]);return new Bt(r)}me._=Q$;var Cf=new Bt("+");function ex(t,...e){let r=[Xi(t[0])],n=0;for(;n<e.length;)r.push(Cf),Df(r,e[n]),r.push(Cf,Xi(t[++n]));return Bj(r),new Bt(r)}me.str=ex;function Df(t,e){e instanceof Bt?t.push(...e._items):e instanceof ss?t.push(e):t.push(Kj(e))}me.addCodeArg=Df;function Bj(t){let e=1;for(;e<t.length-1;){if(t[e]===Cf){let r=Hj(t[e-1],t[e+1]);if(r!==void 0){t.splice(e-1,3,r);continue}t[e++]="+"}e++}}function Hj(t,e){if(e==='""')return t;if(t==='""')return e;if(typeof t=="string")return e instanceof ss||t[t.length-1]!=='"'?void 0:typeof e!="string"?`${t.slice(0,-1)}${e}"`:e[0]==='"'?t.slice(0,-1)+e.slice(1):void 0;if(typeof e=="string"&&e[0]==='"'&&!(t instanceof ss))return`"${t}${e.slice(1)}`}function Wj(t,e){return e.emptyStr()?t:t.emptyStr()?e:ex`${t}${e}`}me.strConcat=Wj;function Kj(t){return typeof t=="number"||typeof t=="boolean"||t===null?t:Xi(Array.isArray(t)?t.join(","):t)}function Jj(t){return new Bt(Xi(t))}me.stringify=Jj;function Xi(t){return JSON.stringify(t).replace(/\u2028/g,"\\u2028").replace(/\u2029/g,"\\u2029")}me.safeStringify=Xi;function Gj(t){return typeof t=="string"&&me.IDENTIFIER.test(t)?new Bt(`.${t}`):Q$`[${t}]`}me.getProperty=Gj;function Yj(t){if(typeof t=="string"&&me.IDENTIFIER.test(t))return new Bt(`${t}`);throw new Error(`CodeGen: invalid export name: ${t}, use explicit $id name mapping`)}me.getEsmExportName=Yj;function Xj(t){return new Bt(t.toString())}me.regexpCode=Xj});var zf=S($t=>{"use strict";Object.defineProperty($t,"__esModule",{value:!0});$t.ValueScope=$t.ValueScopeName=$t.Scope=$t.varKinds=$t.UsedValueState=void 0;var St=Qi(),Of=class extends Error{constructor(e){super(`CodeGen: "code" for ${e} not defined`),this.value=e.value}},Iu;(function(t){t[t.Started=0]="Started",t[t.Completed=1]="Completed"})(Iu||($t.UsedValueState=Iu={}));$t.varKinds={const:new St.Name("const"),let:new St.Name("let"),var:new St.Name("var")};var Ru=class{constructor({prefixes:e,parent:r}={}){this._names={},this._prefixes=e,this._parent=r}toName(e){return e instanceof St.Name?e:this.name(e)}name(e){return new St.Name(this._newName(e))}_newName(e){let r=this._names[e]||this._nameGroup(e);return`${e}${r.index++}`}_nameGroup(e){var r,n;if(!((n=(r=this._parent)===null||r===void 0?void 0:r._prefixes)===null||n===void 0)&&n.has(e)||this._prefixes&&!this._prefixes.has(e))throw new Error(`CodeGen: prefix "${e}" is not allowed in this scope`);return this._names[e]={prefix:e,index:0}}};$t.Scope=Ru;var Au=class extends St.Name{constructor(e,r){super(r),this.prefix=e}setValue(e,{property:r,itemIndex:n}){this.value=e,this.scopePath=(0,St._)`.${new St.Name(r)}[${n}]`}};$t.ValueScopeName=Au;var Qj=(0,St._)`\n`,Mf=class extends Ru{constructor(e){super(e),this._values={},this._scope=e.scope,this.opts={...e,_n:e.lines?Qj:St.nil}}get(){return this._scope}name(e){return new Au(e,this._newName(e))}value(e,r){var n;if(r.ref===void 0)throw new Error("CodeGen: ref must be passed in value");let s=this.toName(e),{prefix:o}=s,i=(n=r.key)!==null&&n!==void 0?n:r.ref,a=this._values[o];if(a){let l=a.get(i);if(l)return l}else a=this._values[o]=new Map;a.set(i,s);let c=this._scope[o]||(this._scope[o]=[]),u=c.length;return c[u]=r.ref,s.setValue(r,{property:o,itemIndex:u}),s}getValue(e,r){let n=this._values[e];if(n)return n.get(r)}scopeRefs(e,r=this._values){return this._reduceValues(r,n=>{if(n.scopePath===void 0)throw new Error(`CodeGen: name "${n}" has no value`);return(0,St._)`${e}${n.scopePath}`})}scopeCode(e=this._values,r,n){return this._reduceValues(e,s=>{if(s.value===void 0)throw new Error(`CodeGen: name "${s}" has no value`);return s.value.code},r,n)}_reduceValues(e,r,n={},s){let o=St.nil;for(let i in e){let a=e[i];if(!a)continue;let c=n[i]=n[i]||new Map;a.forEach(u=>{if(c.has(u))return;c.set(u,Iu.Started);let l=r(u);if(l){let d=this.opts.es5?$t.varKinds.var:$t.varKinds.const;o=(0,St._)`${o}${d} ${u} = ${l};${this.opts._n}`}else if(l=s?.(u))o=(0,St._)`${o}${l}${this.opts._n}`;else throw new Of(u);c.set(u,Iu.Completed)})}return o}};$t.ValueScope=Mf});var te=S(Q=>{"use strict";Object.defineProperty(Q,"__esModule",{value:!0});Q.or=Q.and=Q.not=Q.CodeGen=Q.operators=Q.varKinds=Q.ValueScopeName=Q.ValueScope=Q.Scope=Q.Name=Q.regexpCode=Q.stringify=Q.getProperty=Q.nil=Q.strConcat=Q.str=Q._=void 0;var ce=Qi(),sr=zf(),dn=Qi();Object.defineProperty(Q,"_",{enumerable:!0,get:function(){return dn._}});Object.defineProperty(Q,"str",{enumerable:!0,get:function(){return dn.str}});Object.defineProperty(Q,"strConcat",{enumerable:!0,get:function(){return dn.strConcat}});Object.defineProperty(Q,"nil",{enumerable:!0,get:function(){return dn.nil}});Object.defineProperty(Q,"getProperty",{enumerable:!0,get:function(){return dn.getProperty}});Object.defineProperty(Q,"stringify",{enumerable:!0,get:function(){return dn.stringify}});Object.defineProperty(Q,"regexpCode",{enumerable:!0,get:function(){return dn.regexpCode}});Object.defineProperty(Q,"Name",{enumerable:!0,get:function(){return dn.Name}});var Mu=zf();Object.defineProperty(Q,"Scope",{enumerable:!0,get:function(){return Mu.Scope}});Object.defineProperty(Q,"ValueScope",{enumerable:!0,get:function(){return Mu.ValueScope}});Object.defineProperty(Q,"ValueScopeName",{enumerable:!0,get:function(){return Mu.ValueScopeName}});Object.defineProperty(Q,"varKinds",{enumerable:!0,get:function(){return Mu.varKinds}});Q.operators={GT:new ce._Code(">"),GTE:new ce._Code(">="),LT:new ce._Code("<"),LTE:new ce._Code("<="),EQ:new ce._Code("==="),NEQ:new ce._Code("!=="),NOT:new ce._Code("!"),OR:new ce._Code("||"),AND:new ce._Code("&&"),ADD:new ce._Code("+")};var Fr=class{optimizeNodes(){return this}optimizeNames(e,r){return this}},jf=class extends Fr{constructor(e,r,n){super(),this.varKind=e,this.name=r,this.rhs=n}render({es5:e,_n:r}){let n=e?sr.varKinds.var:this.varKind,s=this.rhs===void 0?"":` = ${this.rhs}`;return`${n} ${this.name}${s};`+r}optimizeNames(e,r){if(e[this.name.str])return this.rhs&&(this.rhs=go(this.rhs,e,r)),this}get names(){return this.rhs instanceof ce._CodeOrName?this.rhs.names:{}}},Cu=class extends Fr{constructor(e,r,n){super(),this.lhs=e,this.rhs=r,this.sideEffects=n}render({_n:e}){return`${this.lhs} = ${this.rhs};`+e}optimizeNames(e,r){if(!(this.lhs instanceof ce.Name&&!e[this.lhs.str]&&!this.sideEffects))return this.rhs=go(this.rhs,e,r),this}get names(){let e=this.lhs instanceof ce.Name?{}:{...this.lhs.names};return Ou(e,this.rhs)}},Nf=class extends Cu{constructor(e,r,n,s){super(e,n,s),this.op=r}render({_n:e}){return`${this.lhs} ${this.op}= ${this.rhs};`+e}},Lf=class extends Fr{constructor(e){super(),this.label=e,this.names={}}render({_n:e}){return`${this.label}:`+e}},qf=class extends Fr{constructor(e){super(),this.label=e,this.names={}}render({_n:e}){return`break${this.label?` ${this.label}`:""};`+e}},Ff=class extends Fr{constructor(e){super(),this.error=e}render({_n:e}){return`throw ${this.error};`+e}get names(){return this.error.names}},Uf=class extends Fr{constructor(e){super(),this.code=e}render({_n:e}){return`${this.code};`+e}optimizeNodes(){return`${this.code}`?this:void 0}optimizeNames(e,r){return this.code=go(this.code,e,r),this}get names(){return this.code instanceof ce._CodeOrName?this.code.names:{}}},ea=class extends Fr{constructor(e=[]){super(),this.nodes=e}render(e){return this.nodes.reduce((r,n)=>r+n.render(e),"")}optimizeNodes(){let{nodes:e}=this,r=e.length;for(;r--;){let n=e[r].optimizeNodes();Array.isArray(n)?e.splice(r,1,...n):n?e[r]=n:e.splice(r,1)}return e.length>0?this:void 0}optimizeNames(e,r){let{nodes:n}=this,s=n.length;for(;s--;){let o=n[s];o.optimizeNames(e,r)||(eN(e,o.names),n.splice(s,1))}return n.length>0?this:void 0}get names(){return this.nodes.reduce((e,r)=>as(e,r.names),{})}},Ur=class extends ea{render(e){return"{"+e._n+super.render(e)+"}"+e._n}},Zf=class extends ea{},ho=class extends Ur{};ho.kind="else";var os=class t extends Ur{constructor(e,r){super(r),this.condition=e}render(e){let r=`if(${this.condition})`+super.render(e);return this.else&&(r+="else "+this.else.render(e)),r}optimizeNodes(){super.optimizeNodes();let e=this.condition;if(e===!0)return this.nodes;let r=this.else;if(r){let n=r.optimizeNodes();r=this.else=Array.isArray(n)?new ho(n):n}if(r)return e===!1?r instanceof t?r:r.nodes:this.nodes.length?this:new t(tx(e),r instanceof t?[r]:r.nodes);if(!(e===!1||!this.nodes.length))return this}optimizeNames(e,r){var n;if(this.else=(n=this.else)===null||n===void 0?void 0:n.optimizeNames(e,r),!!(super.optimizeNames(e,r)||this.else))return this.condition=go(this.condition,e,r),this}get names(){let e=super.names;return Ou(e,this.condition),this.else&&as(e,this.else.names),e}};os.kind="if";var is=class extends Ur{};is.kind="for";var Vf=class extends is{constructor(e){super(),this.iteration=e}render(e){return`for(${this.iteration})`+super.render(e)}optimizeNames(e,r){if(super.optimizeNames(e,r))return this.iteration=go(this.iteration,e,r),this}get names(){return as(super.names,this.iteration.names)}},Bf=class extends is{constructor(e,r,n,s){super(),this.varKind=e,this.name=r,this.from=n,this.to=s}render(e){let r=e.es5?sr.varKinds.var:this.varKind,{name:n,from:s,to:o}=this;return`for(${r} ${n}=${s}; ${n}<${o}; ${n}++)`+super.render(e)}get names(){let e=Ou(super.names,this.from);return Ou(e,this.to)}},Du=class extends is{constructor(e,r,n,s){super(),this.loop=e,this.varKind=r,this.name=n,this.iterable=s}render(e){return`for(${this.varKind} ${this.name} ${this.loop} ${this.iterable})`+super.render(e)}optimizeNames(e,r){if(super.optimizeNames(e,r))return this.iterable=go(this.iterable,e,r),this}get names(){return as(super.names,this.iterable.names)}},ta=class extends Ur{constructor(e,r,n){super(),this.name=e,this.args=r,this.async=n}render(e){return`${this.async?"async ":""}function ${this.name}(${this.args})`+super.render(e)}};ta.kind="func";var ra=class extends ea{render(e){return"return "+super.render(e)}};ra.kind="return";var Hf=class extends Ur{render(e){let r="try"+super.render(e);return this.catch&&(r+=this.catch.render(e)),this.finally&&(r+=this.finally.render(e)),r}optimizeNodes(){var e,r;return super.optimizeNodes(),(e=this.catch)===null||e===void 0||e.optimizeNodes(),(r=this.finally)===null||r===void 0||r.optimizeNodes(),this}optimizeNames(e,r){var n,s;return super.optimizeNames(e,r),(n=this.catch)===null||n===void 0||n.optimizeNames(e,r),(s=this.finally)===null||s===void 0||s.optimizeNames(e,r),this}get names(){let e=super.names;return this.catch&&as(e,this.catch.names),this.finally&&as(e,this.finally.names),e}},na=class extends Ur{constructor(e){super(),this.error=e}render(e){return`catch(${this.error})`+super.render(e)}};na.kind="catch";var sa=class extends Ur{render(e){return"finally"+super.render(e)}};sa.kind="finally";var Wf=class{constructor(e,r={}){this._values={},this._blockStarts=[],this._constants={},this.opts={...r,_n:r.lines?`
|
|
6
6
|
`:""},this._extScope=e,this._scope=new sr.Scope({parent:e}),this._nodes=[new Zf]}toString(){return this._root.render(this.opts)}name(e){return this._scope.name(e)}scopeName(e){return this._extScope.name(e)}scopeValue(e,r){let n=this._extScope.value(e,r);return(this._values[n.prefix]||(this._values[n.prefix]=new Set)).add(n),n}getScopeValue(e,r){return this._extScope.getValue(e,r)}scopeRefs(e){return this._extScope.scopeRefs(e,this._values)}scopeCode(){return this._extScope.scopeCode(this._values)}_def(e,r,n,s){let o=this._scope.toName(r);return n!==void 0&&s&&(this._constants[o.str]=n),this._leafNode(new jf(e,o,n)),o}const(e,r,n){return this._def(sr.varKinds.const,e,r,n)}let(e,r,n){return this._def(sr.varKinds.let,e,r,n)}var(e,r,n){return this._def(sr.varKinds.var,e,r,n)}assign(e,r,n){return this._leafNode(new Cu(e,r,n))}add(e,r){return this._leafNode(new Nf(e,Q.operators.ADD,r))}code(e){return typeof e=="function"?e():e!==ce.nil&&this._leafNode(new Uf(e)),this}object(...e){let r=["{"];for(let[n,s]of e)r.length>1&&r.push(","),r.push(n),(n!==s||this.opts.es5)&&(r.push(":"),(0,ce.addCodeArg)(r,s));return r.push("}"),new ce._Code(r)}if(e,r,n){if(this._blockNode(new os(e)),r&&n)this.code(r).else().code(n).endIf();else if(r)this.code(r).endIf();else if(n)throw new Error('CodeGen: "else" body without "then" body');return this}elseIf(e){return this._elseNode(new os(e))}else(){return this._elseNode(new ho)}endIf(){return this._endBlockNode(os,ho)}_for(e,r){return this._blockNode(e),r&&this.code(r).endFor(),this}for(e,r){return this._for(new Vf(e),r)}forRange(e,r,n,s,o=this.opts.es5?sr.varKinds.var:sr.varKinds.let){let i=this._scope.toName(e);return this._for(new Bf(o,i,r,n),()=>s(i))}forOf(e,r,n,s=sr.varKinds.const){let o=this._scope.toName(e);if(this.opts.es5){let i=r instanceof ce.Name?r:this.var("_arr",r);return this.forRange("_i",0,(0,ce._)`${i}.length`,a=>{this.var(o,(0,ce._)`${i}[${a}]`),n(o)})}return this._for(new Du("of",s,o,r),()=>n(o))}forIn(e,r,n,s=this.opts.es5?sr.varKinds.var:sr.varKinds.const){if(this.opts.ownProperties)return this.forOf(e,(0,ce._)`Object.keys(${r})`,n);let o=this._scope.toName(e);return this._for(new Du("in",s,o,r),()=>n(o))}endFor(){return this._endBlockNode(is)}label(e){return this._leafNode(new Lf(e))}break(e){return this._leafNode(new qf(e))}return(e){let r=new ra;if(this._blockNode(r),this.code(e),r.nodes.length!==1)throw new Error('CodeGen: "return" should have one node');return this._endBlockNode(ra)}try(e,r,n){if(!r&&!n)throw new Error('CodeGen: "try" without "catch" and "finally"');let s=new Hf;if(this._blockNode(s),this.code(e),r){let o=this.name("e");this._currNode=s.catch=new na(o),r(o)}return n&&(this._currNode=s.finally=new sa,this.code(n)),this._endBlockNode(na,sa)}throw(e){return this._leafNode(new Ff(e))}block(e,r){return this._blockStarts.push(this._nodes.length),e&&this.code(e).endBlock(r),this}endBlock(e){let r=this._blockStarts.pop();if(r===void 0)throw new Error("CodeGen: not in self-balancing block");let n=this._nodes.length-r;if(n<0||e!==void 0&&n!==e)throw new Error(`CodeGen: wrong number of nodes: ${n} vs ${e} expected`);return this._nodes.length=r,this}func(e,r=ce.nil,n,s){return this._blockNode(new ta(e,r,n)),s&&this.code(s).endFunc(),this}endFunc(){return this._endBlockNode(ta)}optimize(e=1){for(;e-- >0;)this._root.optimizeNodes(),this._root.optimizeNames(this._root.names,this._constants)}_leafNode(e){return this._currNode.nodes.push(e),this}_blockNode(e){this._currNode.nodes.push(e),this._nodes.push(e)}_endBlockNode(e,r){let n=this._currNode;if(n instanceof e||r&&n instanceof r)return this._nodes.pop(),this;throw new Error(`CodeGen: not in block "${r?`${e.kind}/${r.kind}`:e.kind}"`)}_elseNode(e){let r=this._currNode;if(!(r instanceof os))throw new Error('CodeGen: "else" without "if"');return this._currNode=r.else=e,this}get _root(){return this._nodes[0]}get _currNode(){let e=this._nodes;return e[e.length-1]}set _currNode(e){let r=this._nodes;r[r.length-1]=e}};Q.CodeGen=Wf;function as(t,e){for(let r in e)t[r]=(t[r]||0)+(e[r]||0);return t}function Ou(t,e){return e instanceof ce._CodeOrName?as(t,e.names):t}function go(t,e,r){if(t instanceof ce.Name)return n(t);if(!s(t))return t;return new ce._Code(t._items.reduce((o,i)=>(i instanceof ce.Name&&(i=n(i)),i instanceof ce._Code?o.push(...i._items):o.push(i),o),[]));function n(o){let i=r[o.str];return i===void 0||e[o.str]!==1?o:(delete e[o.str],i)}function s(o){return o instanceof ce._Code&&o._items.some(i=>i instanceof ce.Name&&e[i.str]===1&&r[i.str]!==void 0)}}function eN(t,e){for(let r in e)t[r]=(t[r]||0)-(e[r]||0)}function tx(t){return typeof t=="boolean"||typeof t=="number"||t===null?!t:(0,ce._)`!${Kf(t)}`}Q.not=tx;var tN=rx(Q.operators.AND);function rN(...t){return t.reduce(tN)}Q.and=rN;var nN=rx(Q.operators.OR);function sN(...t){return t.reduce(nN)}Q.or=sN;function rx(t){return(e,r)=>e===ce.nil?r:r===ce.nil?e:(0,ce._)`${Kf(e)} ${t} ${Kf(r)}`}function Kf(t){return t instanceof ce.Name?t:(0,ce._)`(${t})`}});var le=S(re=>{"use strict";Object.defineProperty(re,"__esModule",{value:!0});re.checkStrictMode=re.getErrorPath=re.Type=re.useFunc=re.setEvaluated=re.evaluatedPropsToName=re.mergeEvaluated=re.eachItem=re.unescapeJsonPointer=re.escapeJsonPointer=re.escapeFragment=re.unescapeFragment=re.schemaRefOrVal=re.schemaHasRulesButRef=re.schemaHasRules=re.checkUnknownRules=re.alwaysValidSchema=re.toHash=void 0;var we=te(),oN=Qi();function iN(t){let e={};for(let r of t)e[r]=!0;return e}re.toHash=iN;function aN(t,e){return typeof e=="boolean"?e:Object.keys(e).length===0?!0:(ox(t,e),!ix(e,t.self.RULES.all))}re.alwaysValidSchema=aN;function ox(t,e=t.schema){let{opts:r,self:n}=t;if(!r.strictSchema||typeof e=="boolean")return;let s=n.RULES.keywords;for(let o in e)s[o]||ux(t,`unknown keyword: "${o}"`)}re.checkUnknownRules=ox;function ix(t,e){if(typeof t=="boolean")return!t;for(let r in t)if(e[r])return!0;return!1}re.schemaHasRules=ix;function cN(t,e){if(typeof t=="boolean")return!t;for(let r in t)if(r!=="$ref"&&e.all[r])return!0;return!1}re.schemaHasRulesButRef=cN;function uN({topSchemaRef:t,schemaPath:e},r,n,s){if(!s){if(typeof r=="number"||typeof r=="boolean")return r;if(typeof r=="string")return(0,we._)`${r}`}return(0,we._)`${t}${e}${(0,we.getProperty)(n)}`}re.schemaRefOrVal=uN;function lN(t){return ax(decodeURIComponent(t))}re.unescapeFragment=lN;function dN(t){return encodeURIComponent(Gf(t))}re.escapeFragment=dN;function Gf(t){return typeof t=="number"?`${t}`:t.replace(/~/g,"~0").replace(/\//g,"~1")}re.escapeJsonPointer=Gf;function ax(t){return t.replace(/~1/g,"/").replace(/~0/g,"~")}re.unescapeJsonPointer=ax;function pN(t,e){if(Array.isArray(t))for(let r of t)e(r);else e(t)}re.eachItem=pN;function nx({mergeNames:t,mergeToName:e,mergeValues:r,resultToName:n}){return(s,o,i,a)=>{let c=i===void 0?o:i instanceof we.Name?(o instanceof we.Name?t(s,o,i):e(s,o,i),i):o instanceof we.Name?(e(s,i,o),o):r(o,i);return a===we.Name&&!(c instanceof we.Name)?n(s,c):c}}re.mergeEvaluated={props:nx({mergeNames:(t,e,r)=>t.if((0,we._)`${r} !== true && ${e} !== undefined`,()=>{t.if((0,we._)`${e} === true`,()=>t.assign(r,!0),()=>t.assign(r,(0,we._)`${r} || {}`).code((0,we._)`Object.assign(${r}, ${e})`))}),mergeToName:(t,e,r)=>t.if((0,we._)`${r} !== true`,()=>{e===!0?t.assign(r,!0):(t.assign(r,(0,we._)`${r} || {}`),Yf(t,r,e))}),mergeValues:(t,e)=>t===!0?!0:{...t,...e},resultToName:cx}),items:nx({mergeNames:(t,e,r)=>t.if((0,we._)`${r} !== true && ${e} !== undefined`,()=>t.assign(r,(0,we._)`${e} === true ? true : ${r} > ${e} ? ${r} : ${e}`)),mergeToName:(t,e,r)=>t.if((0,we._)`${r} !== true`,()=>t.assign(r,e===!0?!0:(0,we._)`${r} > ${e} ? ${r} : ${e}`)),mergeValues:(t,e)=>t===!0?!0:Math.max(t,e),resultToName:(t,e)=>t.var("items",e)})};function cx(t,e){if(e===!0)return t.var("props",!0);let r=t.var("props",(0,we._)`{}`);return e!==void 0&&Yf(t,r,e),r}re.evaluatedPropsToName=cx;function Yf(t,e,r){Object.keys(r).forEach(n=>t.assign((0,we._)`${e}${(0,we.getProperty)(n)}`,!0))}re.setEvaluated=Yf;var sx={};function fN(t,e){return t.scopeValue("func",{ref:e,code:sx[e.code]||(sx[e.code]=new oN._Code(e.code))})}re.useFunc=fN;var Jf;(function(t){t[t.Num=0]="Num",t[t.Str=1]="Str"})(Jf||(re.Type=Jf={}));function mN(t,e,r){if(t instanceof we.Name){let n=e===Jf.Num;return r?n?(0,we._)`"[" + ${t} + "]"`:(0,we._)`"['" + ${t} + "']"`:n?(0,we._)`"/" + ${t}`:(0,we._)`"/" + ${t}.replace(/~/g, "~0").replace(/\\//g, "~1")`}return r?(0,we.getProperty)(t).toString():"/"+Gf(t)}re.getErrorPath=mN;function ux(t,e,r=t.opts.strictSchema){if(r){if(e=`strict mode: ${e}`,r===!0)throw new Error(e);t.self.logger.warn(e)}}re.checkStrictMode=ux});var Zr=S(Xf=>{"use strict";Object.defineProperty(Xf,"__esModule",{value:!0});var ot=te(),hN={data:new ot.Name("data"),valCxt:new ot.Name("valCxt"),instancePath:new ot.Name("instancePath"),parentData:new ot.Name("parentData"),parentDataProperty:new ot.Name("parentDataProperty"),rootData:new ot.Name("rootData"),dynamicAnchors:new ot.Name("dynamicAnchors"),vErrors:new ot.Name("vErrors"),errors:new ot.Name("errors"),this:new ot.Name("this"),self:new ot.Name("self"),scope:new ot.Name("scope"),json:new ot.Name("json"),jsonPos:new ot.Name("jsonPos"),jsonLen:new ot.Name("jsonLen"),jsonPart:new ot.Name("jsonPart")};Xf.default=hN});var oa=S(it=>{"use strict";Object.defineProperty(it,"__esModule",{value:!0});it.extendErrors=it.resetErrorsCount=it.reportExtraError=it.reportError=it.keyword$DataError=it.keywordError=void 0;var de=te(),zu=le(),mt=Zr();it.keywordError={message:({keyword:t})=>(0,de.str)`must pass "${t}" keyword validation`};it.keyword$DataError={message:({keyword:t,schemaType:e})=>e?(0,de.str)`"${t}" keyword must be ${e} ($data)`:(0,de.str)`"${t}" keyword is invalid ($data)`};function gN(t,e=it.keywordError,r,n){let{it:s}=t,{gen:o,compositeRule:i,allErrors:a}=s,c=px(t,e,r);n??(i||a)?lx(o,c):dx(s,(0,de._)`[${c}]`)}it.reportError=gN;function yN(t,e=it.keywordError,r){let{it:n}=t,{gen:s,compositeRule:o,allErrors:i}=n,a=px(t,e,r);lx(s,a),o||i||dx(n,mt.default.vErrors)}it.reportExtraError=yN;function vN(t,e){t.assign(mt.default.errors,e),t.if((0,de._)`${mt.default.vErrors} !== null`,()=>t.if(e,()=>t.assign((0,de._)`${mt.default.vErrors}.length`,e),()=>t.assign(mt.default.vErrors,null)))}it.resetErrorsCount=vN;function _N({gen:t,keyword:e,schemaValue:r,data:n,errsCount:s,it:o}){if(s===void 0)throw new Error("ajv implementation error");let i=t.name("err");t.forRange("i",s,mt.default.errors,a=>{t.const(i,(0,de._)`${mt.default.vErrors}[${a}]`),t.if((0,de._)`${i}.instancePath === undefined`,()=>t.assign((0,de._)`${i}.instancePath`,(0,de.strConcat)(mt.default.instancePath,o.errorPath))),t.assign((0,de._)`${i}.schemaPath`,(0,de.str)`${o.errSchemaPath}/${e}`),o.opts.verbose&&(t.assign((0,de._)`${i}.schema`,r),t.assign((0,de._)`${i}.data`,n))})}it.extendErrors=_N;function lx(t,e){let r=t.const("err",e);t.if((0,de._)`${mt.default.vErrors} === null`,()=>t.assign(mt.default.vErrors,(0,de._)`[${r}]`),(0,de._)`${mt.default.vErrors}.push(${r})`),t.code((0,de._)`${mt.default.errors}++`)}function dx(t,e){let{gen:r,validateName:n,schemaEnv:s}=t;s.$async?r.throw((0,de._)`new ${t.ValidationError}(${e})`):(r.assign((0,de._)`${n}.errors`,e),r.return(!1))}var cs={keyword:new de.Name("keyword"),schemaPath:new de.Name("schemaPath"),params:new de.Name("params"),propertyName:new de.Name("propertyName"),message:new de.Name("message"),schema:new de.Name("schema"),parentSchema:new de.Name("parentSchema")};function px(t,e,r){let{createErrors:n}=t.it;return n===!1?(0,de._)`{}`:bN(t,e,r)}function bN(t,e,r={}){let{gen:n,it:s}=t,o=[wN(s,r),SN(t,r)];return $N(t,e,o),n.object(...o)}function wN({errorPath:t},{instancePath:e}){let r=e?(0,de.str)`${t}${(0,zu.getErrorPath)(e,zu.Type.Str)}`:t;return[mt.default.instancePath,(0,de.strConcat)(mt.default.instancePath,r)]}function SN({keyword:t,it:{errSchemaPath:e}},{schemaPath:r,parentSchema:n}){let s=n?e:(0,de.str)`${e}/${t}`;return r&&(s=(0,de.str)`${s}${(0,zu.getErrorPath)(r,zu.Type.Str)}`),[cs.schemaPath,s]}function $N(t,{params:e,message:r},n){let{keyword:s,data:o,schemaValue:i,it:a}=t,{opts:c,propertyName:u,topSchemaRef:l,schemaPath:d}=a;n.push([cs.keyword,s],[cs.params,typeof e=="function"?e(t):e||(0,de._)`{}`]),c.messages&&n.push([cs.message,typeof r=="function"?r(t):r]),c.verbose&&n.push([cs.schema,i],[cs.parentSchema,(0,de._)`${l}${d}`],[mt.default.data,o]),u&&n.push([cs.propertyName,u])}});var mx=S(yo=>{"use strict";Object.defineProperty(yo,"__esModule",{value:!0});yo.boolOrEmptySchema=yo.topBoolOrEmptySchema=void 0;var xN=oa(),PN=te(),kN=Zr(),EN={message:"boolean schema is false"};function TN(t){let{gen:e,schema:r,validateName:n}=t;r===!1?fx(t,!1):typeof r=="object"&&r.$async===!0?e.return(kN.default.data):(e.assign((0,PN._)`${n}.errors`,null),e.return(!0))}yo.topBoolOrEmptySchema=TN;function IN(t,e){let{gen:r,schema:n}=t;n===!1?(r.var(e,!1),fx(t)):r.var(e,!0)}yo.boolOrEmptySchema=IN;function fx(t,e){let{gen:r,data:n}=t,s={gen:r,keyword:"false schema",data:n,schema:!1,schemaCode:!1,schemaValue:!1,params:{},it:t};(0,xN.reportError)(s,EN,void 0,e)}});var Qf=S(vo=>{"use strict";Object.defineProperty(vo,"__esModule",{value:!0});vo.getRules=vo.isJSONType=void 0;var RN=["string","number","integer","boolean","null","object","array"],AN=new Set(RN);function CN(t){return typeof t=="string"&&AN.has(t)}vo.isJSONType=CN;function DN(){let t={number:{type:"number",rules:[]},string:{type:"string",rules:[]},array:{type:"array",rules:[]},object:{type:"object",rules:[]}};return{types:{...t,integer:!0,boolean:!0,null:!0},rules:[{rules:[]},t.number,t.string,t.array,t.object],post:{rules:[]},all:{},keywords:{}}}vo.getRules=DN});var em=S(pn=>{"use strict";Object.defineProperty(pn,"__esModule",{value:!0});pn.shouldUseRule=pn.shouldUseGroup=pn.schemaHasRulesForType=void 0;function ON({schema:t,self:e},r){let n=e.RULES.types[r];return n&&n!==!0&&hx(t,n)}pn.schemaHasRulesForType=ON;function hx(t,e){return e.rules.some(r=>gx(t,r))}pn.shouldUseGroup=hx;function gx(t,e){var r;return t[e.keyword]!==void 0||((r=e.definition.implements)===null||r===void 0?void 0:r.some(n=>t[n]!==void 0))}pn.shouldUseRule=gx});var ia=S(at=>{"use strict";Object.defineProperty(at,"__esModule",{value:!0});at.reportTypeError=at.checkDataTypes=at.checkDataType=at.coerceAndCheckDataType=at.getJSONTypes=at.getSchemaTypes=at.DataType=void 0;var MN=Qf(),zN=em(),jN=oa(),K=te(),yx=le(),_o;(function(t){t[t.Correct=0]="Correct",t[t.Wrong=1]="Wrong"})(_o||(at.DataType=_o={}));function NN(t){let e=vx(t.type);if(e.includes("null")){if(t.nullable===!1)throw new Error("type: null contradicts nullable: false")}else{if(!e.length&&t.nullable!==void 0)throw new Error('"nullable" cannot be used without "type"');t.nullable===!0&&e.push("null")}return e}at.getSchemaTypes=NN;function vx(t){let e=Array.isArray(t)?t:t?[t]:[];if(e.every(MN.isJSONType))return e;throw new Error("type must be JSONType or JSONType[]: "+e.join(","))}at.getJSONTypes=vx;function LN(t,e){let{gen:r,data:n,opts:s}=t,o=qN(e,s.coerceTypes),i=e.length>0&&!(o.length===0&&e.length===1&&(0,zN.schemaHasRulesForType)(t,e[0]));if(i){let a=rm(e,n,s.strictNumbers,_o.Wrong);r.if(a,()=>{o.length?FN(t,e,o):nm(t)})}return i}at.coerceAndCheckDataType=LN;var _x=new Set(["string","number","integer","boolean","null"]);function qN(t,e){return e?t.filter(r=>_x.has(r)||e==="array"&&r==="array"):[]}function FN(t,e,r){let{gen:n,data:s,opts:o}=t,i=n.let("dataType",(0,K._)`typeof ${s}`),a=n.let("coerced",(0,K._)`undefined`);o.coerceTypes==="array"&&n.if((0,K._)`${i} == 'object' && Array.isArray(${s}) && ${s}.length == 1`,()=>n.assign(s,(0,K._)`${s}[0]`).assign(i,(0,K._)`typeof ${s}`).if(rm(e,s,o.strictNumbers),()=>n.assign(a,s))),n.if((0,K._)`${a} !== undefined`);for(let u of r)(_x.has(u)||u==="array"&&o.coerceTypes==="array")&&c(u);n.else(),nm(t),n.endIf(),n.if((0,K._)`${a} !== undefined`,()=>{n.assign(s,a),UN(t,a)});function c(u){switch(u){case"string":n.elseIf((0,K._)`${i} == "number" || ${i} == "boolean"`).assign(a,(0,K._)`"" + ${s}`).elseIf((0,K._)`${s} === null`).assign(a,(0,K._)`""`);return;case"number":n.elseIf((0,K._)`${i} == "boolean" || ${s} === null
|
package/package.json
CHANGED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
// Single source of truth for agent permission categories.
|
|
2
|
+
//
|
|
3
|
+
// Five categories partition the nine Agestra agents by role.
|
|
4
|
+
// Each category fixes the exact `tools:` allowlist that the agent's
|
|
5
|
+
// frontmatter must declare, so Claude Code only loads the schemas the
|
|
6
|
+
// role legitimately needs and any drift is caught by a consistency test.
|
|
7
|
+
|
|
8
|
+
const MCP_PREFIX = "mcp__plugin_agestra_agestra__";
|
|
9
|
+
|
|
10
|
+
function withMcpPrefix(names) {
|
|
11
|
+
return names.map((name) => `${MCP_PREFIX}${name}`);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const STANDARD_NON_WRITE_TOOLS = Object.freeze([
|
|
15
|
+
"Read",
|
|
16
|
+
"Glob",
|
|
17
|
+
"Grep",
|
|
18
|
+
"Bash",
|
|
19
|
+
"WebFetch",
|
|
20
|
+
"WebSearch",
|
|
21
|
+
"TodoWrite",
|
|
22
|
+
"AskUserQuestion",
|
|
23
|
+
"Skill",
|
|
24
|
+
"ToolSearch",
|
|
25
|
+
"CronCreate",
|
|
26
|
+
"CronList",
|
|
27
|
+
"CronDelete",
|
|
28
|
+
"Agent",
|
|
29
|
+
]);
|
|
30
|
+
|
|
31
|
+
const ORCHESTRATOR_LEAD_MCP = Object.freeze(
|
|
32
|
+
withMcpPrefix([
|
|
33
|
+
"environment_check",
|
|
34
|
+
"provider_list",
|
|
35
|
+
"provider_health",
|
|
36
|
+
"trace_query",
|
|
37
|
+
"trace_summary",
|
|
38
|
+
"trace_visualize",
|
|
39
|
+
"ai_chat",
|
|
40
|
+
"ai_analyze_files",
|
|
41
|
+
"ai_compare",
|
|
42
|
+
"agent_debate_structured",
|
|
43
|
+
"agent_debate_status",
|
|
44
|
+
"agent_debate_approve",
|
|
45
|
+
"agent_debate_continue",
|
|
46
|
+
"agent_debate_reject",
|
|
47
|
+
"agent_cross_validate",
|
|
48
|
+
"cli_worker_spawn",
|
|
49
|
+
"cli_worker_status",
|
|
50
|
+
"cli_worker_collect",
|
|
51
|
+
"cli_worker_stop",
|
|
52
|
+
"agent_changes_review",
|
|
53
|
+
"agent_changes_accept",
|
|
54
|
+
"agent_changes_reject",
|
|
55
|
+
]),
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
const ORCHESTRATOR_MODERATOR_MCP = Object.freeze(
|
|
59
|
+
withMcpPrefix([
|
|
60
|
+
"provider_list",
|
|
61
|
+
"agent_debate_structured",
|
|
62
|
+
"agent_debate_status",
|
|
63
|
+
"agent_debate_approve",
|
|
64
|
+
"agent_debate_continue",
|
|
65
|
+
"agent_debate_reject",
|
|
66
|
+
"agent_debate_review",
|
|
67
|
+
"ai_chat",
|
|
68
|
+
"workspace_read",
|
|
69
|
+
"workspace_create_document",
|
|
70
|
+
]),
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
const ORCHESTRATOR_LEAD_TOOLS = Object.freeze([
|
|
74
|
+
...STANDARD_NON_WRITE_TOOLS,
|
|
75
|
+
...ORCHESTRATOR_LEAD_MCP,
|
|
76
|
+
]);
|
|
77
|
+
|
|
78
|
+
const ORCHESTRATOR_MODERATOR_TOOLS = Object.freeze([
|
|
79
|
+
...STANDARD_NON_WRITE_TOOLS,
|
|
80
|
+
...ORCHESTRATOR_MODERATOR_MCP,
|
|
81
|
+
]);
|
|
82
|
+
|
|
83
|
+
const WRITER_TOOLS = Object.freeze([...STANDARD_NON_WRITE_TOOLS, "Write"]);
|
|
84
|
+
|
|
85
|
+
export const CATEGORIES = Object.freeze({
|
|
86
|
+
"orchestrator-lead": Object.freeze({
|
|
87
|
+
members: Object.freeze(["agestra-team-lead"]),
|
|
88
|
+
policy: "mcp-allowlist",
|
|
89
|
+
tools: ORCHESTRATOR_LEAD_TOOLS,
|
|
90
|
+
description:
|
|
91
|
+
"Full-lifecycle orchestrator. Spawns workers, reviews and accepts worktree changes, runs structured debates. Does not write files directly.",
|
|
92
|
+
}),
|
|
93
|
+
"orchestrator-moderator": Object.freeze({
|
|
94
|
+
members: Object.freeze(["agestra-moderator"]),
|
|
95
|
+
policy: "mcp-allowlist",
|
|
96
|
+
tools: ORCHESTRATOR_MODERATOR_TOOLS,
|
|
97
|
+
description:
|
|
98
|
+
"Debate facilitator and result aggregator. Reads workspace and creates aggregation documents through MCP. Does not spawn workers, accept changes, or write files directly.",
|
|
99
|
+
}),
|
|
100
|
+
"artifact-writer": Object.freeze({
|
|
101
|
+
members: Object.freeze(["agestra-designer", "agestra-ideator"]),
|
|
102
|
+
policy: "tools-allowlist",
|
|
103
|
+
tools: WRITER_TOOLS,
|
|
104
|
+
description:
|
|
105
|
+
"Writes design or idea decision Markdown under docs/plans/ or docs/ideas/. Has Write but no MCP tools to prevent orchestration or change-acceptance leakage.",
|
|
106
|
+
}),
|
|
107
|
+
"report-writer": Object.freeze({
|
|
108
|
+
members: Object.freeze([
|
|
109
|
+
"agestra-qa",
|
|
110
|
+
"agestra-reviewer",
|
|
111
|
+
"agestra-security",
|
|
112
|
+
]),
|
|
113
|
+
policy: "tools-allowlist",
|
|
114
|
+
tools: WRITER_TOOLS,
|
|
115
|
+
description:
|
|
116
|
+
"Writes QA, review, or security reports under docs/reports/. Has Write but no MCP tools to keep verification roles from accepting changes or spawning workers.",
|
|
117
|
+
}),
|
|
118
|
+
implementation: Object.freeze({
|
|
119
|
+
members: Object.freeze([
|
|
120
|
+
"agestra-implementer",
|
|
121
|
+
"agestra-e2e-writer",
|
|
122
|
+
]),
|
|
123
|
+
policy: "open",
|
|
124
|
+
tools: null,
|
|
125
|
+
description:
|
|
126
|
+
"Applies scoped code or test changes. Tool surface is intentionally unconstrained at the frontmatter level so implementation can use whatever the task requires.",
|
|
127
|
+
}),
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
export const ALL_AGENTS = Object.freeze(
|
|
131
|
+
Object.values(CATEGORIES).flatMap((category) => [...category.members]),
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
export function categoryForAgent(agentName) {
|
|
135
|
+
for (const [name, category] of Object.entries(CATEGORIES)) {
|
|
136
|
+
if (category.members.includes(agentName)) {
|
|
137
|
+
return { name, ...category };
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export function expectedToolsForAgent(agentName) {
|
|
144
|
+
const category = categoryForAgent(agentName);
|
|
145
|
+
if (!category) {
|
|
146
|
+
throw new Error(`Unknown agent: ${agentName}`);
|
|
147
|
+
}
|
|
148
|
+
return category.tools;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export function isOrchestratorCategory(categoryName) {
|
|
152
|
+
return (
|
|
153
|
+
categoryName === "orchestrator-lead" ||
|
|
154
|
+
categoryName === "orchestrator-moderator"
|
|
155
|
+
);
|
|
156
|
+
}
|