@ozzylabs/feedradar 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ja.md +114 -0
- package/README.md +63 -53
- package/dist/cli/doctor.d.ts +83 -0
- package/dist/cli/doctor.d.ts.map +1 -0
- package/dist/cli/doctor.js +260 -0
- package/dist/cli/doctor.js.map +1 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +2 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/source.d.ts.map +1 -1
- package/dist/cli/source.js +6 -3
- package/dist/cli/source.js.map +1 -1
- package/dist/cli/watch.d.ts +16 -0
- package/dist/cli/watch.d.ts.map +1 -1
- package/dist/cli/watch.js +3 -0
- package/dist/cli/watch.js.map +1 -1
- package/dist/core/feeds/_html-common.d.ts +30 -0
- package/dist/core/feeds/_html-common.d.ts.map +1 -0
- package/dist/core/feeds/_html-common.js +192 -0
- package/dist/core/feeds/_html-common.js.map +1 -0
- package/dist/core/feeds/html-js.d.ts +50 -0
- package/dist/core/feeds/html-js.d.ts.map +1 -0
- package/dist/core/feeds/html-js.js +135 -0
- package/dist/core/feeds/html-js.js.map +1 -0
- package/dist/core/feeds/html.d.ts +1 -7
- package/dist/core/feeds/html.d.ts.map +1 -1
- package/dist/core/feeds/html.js +5 -180
- package/dist/core/feeds/html.js.map +1 -1
- package/dist/core/feeds/index.d.ts.map +1 -1
- package/dist/core/feeds/index.js +2 -0
- package/dist/core/feeds/index.js.map +1 -1
- package/dist/core/playwright-check.d.ts +134 -0
- package/dist/core/playwright-check.d.ts.map +1 -0
- package/dist/core/playwright-check.js +98 -0
- package/dist/core/playwright-check.js.map +1 -0
- package/dist/core/watcher.d.ts +17 -0
- package/dist/core/watcher.d.ts.map +1 -1
- package/dist/core/watcher.js +59 -0
- package/dist/core/watcher.js.map +1 -1
- package/dist/index.js +0 -0
- package/dist/schemas/source.d.ts +42 -0
- package/dist/schemas/source.d.ts.map +1 -1
- package/dist/schemas/source.js +42 -7
- package/dist/schemas/source.js.map +1 -1
- package/dist/templates/agents/AGENTS.md +2 -2
- package/dist/templates/feedradar.md +2 -2
- package/package.json +11 -1
package/README.ja.md
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
[English](README.md) | 日本語
|
|
2
|
+
|
|
3
|
+
# FeedRadar
|
|
4
|
+
|
|
5
|
+
ブログ・公式アップデート・リリースフィードを監視し、キーワードヒットを 4 種の AI エージェント (Claude Code / Codex / Gemini / Copilot) に渡して **Markdown 調査レポートを書かせる CLI**。
|
|
6
|
+
|
|
7
|
+
## 解決する課題
|
|
8
|
+
|
|
9
|
+
複数の公式ブログ・ドキュメント・リリースノートを横断的に追い、変更点を要約する作業は AI エージェントとの相性が良いが、ソース管理・差分検出・テンプレート適用・複数エージェントへの委譲を毎回手作業で組むのは煩雑になる。`radar` はこのループを CLI として固定化し、ユーザーの調査ディレクトリに Markdown レポートを蓄積する。
|
|
10
|
+
|
|
11
|
+
## 主な特徴
|
|
12
|
+
|
|
13
|
+
- **多エージェント対応**: Claude Code / Codex CLI / Gemini CLI / GitHub Copilot CLI を adapter 経由で切り替え。
|
|
14
|
+
- **複数フィード種別**: RSS / HTML / **HTML (JS rendered)** / GitHub Releases / npm registry を同一の `Source` 抽象で扱う。
|
|
15
|
+
- **ユーザー側データ管理**: `sources/` `items/` `state/` `research/` `templates/` は **ユーザーの任意ディレクトリ** に置き、本パッケージは engine のみを提供する。
|
|
16
|
+
- **npm 単体配布**: OIDC Trusted Publishers で `@ozzylabs/feedradar` を npm 配布。
|
|
17
|
+
|
|
18
|
+
## インストール
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm i -g @ozzylabs/feedradar
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`kind: html-js` adapter(JS 実行後に DOM が組み立てられる SPA / CSR ページ向け)を使う場合は Playwright を別途 install する。Playwright は **optional peer dep** として宣言されているため、RSS / static HTML のみ使うユーザーには ~300MB の Chromium footprint を強いない([ADR-0010](./docs/adr/0010-html-js-adapter-and-distribution.md)):
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm i -g playwright
|
|
28
|
+
npx playwright install chromium
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
`html-js` source を追加する前に `radar doctor` で Playwright / Chromium が検出できるか確認できる。CI で使う場合の具体例は [docs/user-guide.md → `--kind html-js` → CI で使う](./docs/user-guide.md#ci-で使う) を参照。
|
|
32
|
+
|
|
33
|
+
開発中は本リポを clone し、`pnpm install && pnpm run build` で `dist/index.js` を生成して `node dist/index.js <command>` で起動する。
|
|
34
|
+
|
|
35
|
+
## 使い方
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# クイックスタート (anthropics/anthropic-sdk-python の GitHub Releases を監視)
|
|
39
|
+
radar init
|
|
40
|
+
radar source add anthropic-sdk \
|
|
41
|
+
--kind github-releases \
|
|
42
|
+
--url https://github.com/anthropics/anthropic-sdk-python \
|
|
43
|
+
--keywords "feat,fix,release"
|
|
44
|
+
radar watch run
|
|
45
|
+
radar research <item-id>
|
|
46
|
+
|
|
47
|
+
# その他のサブコマンド
|
|
48
|
+
radar source list # ソース一覧
|
|
49
|
+
radar dismiss <item-id> # 不要 item を dismissed に遷移(LLM 不要)
|
|
50
|
+
radar review <research-id> # レポートを別エージェントで相互レビュー
|
|
51
|
+
radar update <research-id> # 既存レポートを最新 item で更新(v+1)
|
|
52
|
+
radar doctor # workspace / agent CLI / Playwright の health check
|
|
53
|
+
radar --help # ヘルプ
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
全 8 サブコマンドが実装済み。詳細は [docs/user-guide.md](./docs/user-guide.md) を参照。
|
|
57
|
+
|
|
58
|
+
## 開発
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
pnpm install # 依存関係インストール
|
|
62
|
+
pnpm run build # tsc でビルド(dist/)
|
|
63
|
+
pnpm run typecheck # 型チェック
|
|
64
|
+
pnpm run test # vitest run
|
|
65
|
+
|
|
66
|
+
# ローカルで CLI を呼ぶ場合 (build 後)
|
|
67
|
+
pnpm radar --help # = node dist/index.js --help (package.json scripts の alias)
|
|
68
|
+
node dist/index.js --help # 等価
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
> ローカルの `pnpm radar <cmd>` は `package.json` の `scripts.radar`(`node dist/index.js`)を呼ぶ alias で、事前に `pnpm run build` で `dist/index.js` を生成しておく必要がある。配布版 (`npm i -g @ozzylabs/feedradar`) でユーザーが直接叩く `radar <cmd>` は `package.json` の `bin.radar` 経由で、こちらは publish 済み `dist/` を参照するため build 不要。両者は同名だがレイヤーが違う。なお `pnpm --prefix <path> radar <cmd>` は CWD を `<path>` に切り替えてから scripts を実行する仕様なので、別ディレクトリ(例えば smoke test 用の空ワークスペース)で scripts alias を呼びたい場合は `pnpm --prefix` ではなく `node <repo-root>/dist/index.js <cmd>` を直接呼ぶこと(前者はリポ root に対して `init` 等が走る事故になる)。
|
|
72
|
+
|
|
73
|
+
## アーキテクチャ概要
|
|
74
|
+
|
|
75
|
+
```text
|
|
76
|
+
src/
|
|
77
|
+
index.ts CLI entry point (#!/usr/bin/env node)
|
|
78
|
+
cli/ init / source / watch / research / dismiss / review / update
|
|
79
|
+
core/
|
|
80
|
+
watcher.ts source → adapter → items
|
|
81
|
+
filter.ts keyword / excludeKeyword
|
|
82
|
+
items.ts items の load / save
|
|
83
|
+
templates.ts research テンプレートの読み込み
|
|
84
|
+
state.ts state/<sourceId>.yaml の load / save
|
|
85
|
+
config.ts radar.config.yaml の load / 検証
|
|
86
|
+
injection-detector.ts prompt injection regex pre-filter (ADR-0009 M1a)
|
|
87
|
+
feeds/ rss / html / html-js / github-releases / npm-registry
|
|
88
|
+
agents/ 4 CLI adapters(claude-code / codex-cli / gemini-cli / copilot)
|
|
89
|
+
schemas/ Zod スキーマ(Source / Item / State / Research)
|
|
90
|
+
skills/ engine SKILL bundle (research / review / update; init で .agents/skills/ に配布)
|
|
91
|
+
claude-skills/ Claude Code 用 slash-command 雛形 (init で .claude/skills/ に配布)
|
|
92
|
+
gemini-commands/ Gemini CLI 用 TOML slash-command 雛形 (init で .gemini/commands/ に配布)
|
|
93
|
+
templates/ workspace 既定テンプレート (init で templates/ に配布)
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## ドキュメント
|
|
97
|
+
|
|
98
|
+
- [docs/architecture.md](./docs/architecture.md) — システム全体図 / モジュール責務 / データフロー / Phase 別スコープ
|
|
99
|
+
- [docs/user-guide.md](./docs/user-guide.md) — インストール / クイックスタート / コマンド仕様
|
|
100
|
+
- [docs/release.md](./docs/release.md) — リリース手順(初回手動 publish + Trusted Publisher 登録 + 以降の OIDC 自動化)
|
|
101
|
+
- [docs/adr/](./docs/adr/README.md) — FeedRadar 内部の設計判断記録(Agent / Source / Output / Schedule / User Data / Filter / Skill Bundling / Status State Machine / Untrusted External Content Handling)
|
|
102
|
+
|
|
103
|
+
## 規約
|
|
104
|
+
|
|
105
|
+
- **言語**: TypeScript ESM / Node.js 22+ / pnpm
|
|
106
|
+
- **コミット**: Conventional Commits(`commitlint` で強制)
|
|
107
|
+
- **ブランチ**: GitHub Flow(`main` + feature branch、squash merge のみ)
|
|
108
|
+
- **配布**: npm `@ozzylabs/feedradar`、OIDC Trusted Publishers(`NPM_TOKEN` は使わない)
|
|
109
|
+
- **共通設定**: [`ozzy-labs/commons`](https://github.com/ozzy-labs/commons) から `sync.sh` で配布。
|
|
110
|
+
- **共通スキル**: [`ozzy-labs/skills`](https://github.com/ozzy-labs/skills) を `@ozzylabs/skills` Renovate preset で取り込み。
|
|
111
|
+
|
|
112
|
+
## License
|
|
113
|
+
|
|
114
|
+
MIT — see [LICENSE](./LICENSE).
|
package/README.md
CHANGED
|
@@ -1,33 +1,41 @@
|
|
|
1
|
-
|
|
1
|
+
English | [日本語](README.ja.md)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
# FeedRadar
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
CLI that watches blogs, official update streams, and release feeds, then hands keyword hits to one of four AI agents (Claude Code / Codex / Gemini / Copilot) to **produce Markdown research reports**.
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## Problem it solves
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Tracking multiple official blogs, docs, and release notes — and summarizing what actually changed — is a good fit for AI agents, but wiring up source management, diffing, template application, and multi-agent delegation by hand every time gets tedious. `radar` fixes that loop in a CLI and accumulates Markdown reports in your research directory.
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## Highlights
|
|
12
12
|
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
- **npm
|
|
13
|
+
- **Multi-agent**: switch between Claude Code / Codex CLI / Gemini CLI / GitHub Copilot CLI via adapters.
|
|
14
|
+
- **Multiple feed kinds**: RSS / HTML / **HTML (JS rendered)** / GitHub Releases / npm registry are all driven through the same `Source` abstraction.
|
|
15
|
+
- **User-owned data**: `sources/` `items/` `state/` `research/` `templates/` live in **your workspace directory**. This package ships only the engine.
|
|
16
|
+
- **Single npm package**: distributed as `@ozzylabs/feedradar` via OIDC Trusted Publishers.
|
|
17
17
|
|
|
18
|
-
##
|
|
18
|
+
## Install
|
|
19
19
|
|
|
20
20
|
```bash
|
|
21
|
-
# 初版公開後に有効化される
|
|
22
21
|
npm i -g @ozzylabs/feedradar
|
|
23
22
|
```
|
|
24
23
|
|
|
25
|
-
|
|
24
|
+
To use the `kind: html-js` adapter (SPA / CSR pages rendered after JS runs), install Playwright separately — it is declared as an *optional* peer dep so users who only need RSS / static HTML do not pay the ~300MB Chromium footprint ([ADR-0010](./docs/adr/0010-html-js-adapter-and-distribution.md)):
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm i -g playwright
|
|
28
|
+
npx playwright install chromium
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Run `radar doctor` to verify Playwright / Chromium are detected before adding an `html-js` source. CI setup details and a sample workflow are in [docs/user-guide.md → `--kind html-js` → CI で使う](./docs/user-guide.md#ci-で使う).
|
|
32
|
+
|
|
33
|
+
While developing locally, clone this repo and run `pnpm install && pnpm run build` to produce `dist/index.js`, then invoke `node dist/index.js <command>`.
|
|
26
34
|
|
|
27
|
-
##
|
|
35
|
+
## Usage
|
|
28
36
|
|
|
29
37
|
```bash
|
|
30
|
-
#
|
|
38
|
+
# Quickstart (watch anthropics/anthropic-sdk-python GitHub Releases)
|
|
31
39
|
radar init
|
|
32
40
|
radar source add anthropic-sdk \
|
|
33
41
|
--kind github-releases \
|
|
@@ -36,32 +44,33 @@ radar source add anthropic-sdk \
|
|
|
36
44
|
radar watch run
|
|
37
45
|
radar research <item-id>
|
|
38
46
|
|
|
39
|
-
#
|
|
40
|
-
radar source list #
|
|
41
|
-
radar dismiss <item-id> #
|
|
42
|
-
radar review <research-id> #
|
|
43
|
-
radar update <research-id> #
|
|
44
|
-
radar
|
|
47
|
+
# Other subcommands
|
|
48
|
+
radar source list # list sources
|
|
49
|
+
radar dismiss <item-id> # move an item to dismissed (no LLM)
|
|
50
|
+
radar review <research-id> # cross-review a report with a different agent
|
|
51
|
+
radar update <research-id> # refresh an existing report against the latest item (v+1)
|
|
52
|
+
radar doctor # check workspace / agent CLI / Playwright health
|
|
53
|
+
radar --help # help
|
|
45
54
|
```
|
|
46
55
|
|
|
47
|
-
|
|
56
|
+
All 8 subcommands are implemented. See [docs/user-guide.md](./docs/user-guide.md) for the full spec.
|
|
48
57
|
|
|
49
|
-
##
|
|
58
|
+
## Development
|
|
50
59
|
|
|
51
60
|
```bash
|
|
52
|
-
pnpm install #
|
|
53
|
-
pnpm run build # tsc
|
|
54
|
-
pnpm run typecheck #
|
|
61
|
+
pnpm install # install dependencies
|
|
62
|
+
pnpm run build # tsc build (dist/)
|
|
63
|
+
pnpm run typecheck # type check
|
|
55
64
|
pnpm run test # vitest run
|
|
56
65
|
|
|
57
|
-
#
|
|
58
|
-
pnpm radar --help # = node dist/index.js --help (package.json scripts
|
|
59
|
-
node dist/index.js --help #
|
|
66
|
+
# Invoking the CLI locally (after build)
|
|
67
|
+
pnpm radar --help # = node dist/index.js --help (package.json scripts alias)
|
|
68
|
+
node dist/index.js --help # equivalent
|
|
60
69
|
```
|
|
61
70
|
|
|
62
|
-
>
|
|
71
|
+
> The local `pnpm radar <cmd>` form is the `package.json` `scripts.radar` alias (`node dist/index.js`) and requires you to have run `pnpm run build` first to produce `dist/index.js`. The distributed `radar <cmd>` that end users invoke after `npm i -g @ozzylabs/feedradar` goes through `package.json` `bin.radar`, which points at the published `dist/`, so no build step is needed there. The two share a name but belong to different layers. Note also that `pnpm --prefix <path> radar <cmd>` switches CWD to `<path>` *before* running scripts, so when you want the scripts alias to run in a different directory (for example a smoke-test scratch workspace) you must call `node <repo-root>/dist/index.js <cmd>` directly — using `pnpm --prefix` would cause `init` et al. to run against the repo root by accident.
|
|
63
72
|
|
|
64
|
-
##
|
|
73
|
+
## Architecture overview
|
|
65
74
|
|
|
66
75
|
```text
|
|
67
76
|
src/
|
|
@@ -70,34 +79,35 @@ src/
|
|
|
70
79
|
core/
|
|
71
80
|
watcher.ts source → adapter → items
|
|
72
81
|
filter.ts keyword / excludeKeyword
|
|
73
|
-
items.ts items
|
|
74
|
-
templates.ts research
|
|
75
|
-
state.ts state/<sourceId>.yaml
|
|
76
|
-
config.ts radar.config.yaml
|
|
82
|
+
items.ts items load / save
|
|
83
|
+
templates.ts research template loader
|
|
84
|
+
state.ts state/<sourceId>.yaml load / save
|
|
85
|
+
config.ts radar.config.yaml load / validate
|
|
77
86
|
injection-detector.ts prompt injection regex pre-filter (ADR-0009 M1a)
|
|
78
|
-
feeds/ rss / html / github-releases / npm-registry
|
|
79
|
-
agents/ 4 CLI adapters
|
|
80
|
-
schemas/ Zod
|
|
81
|
-
skills/ engine SKILL bundle (research / review / update; init
|
|
82
|
-
claude-skills/ Claude Code
|
|
83
|
-
gemini-commands/ Gemini CLI
|
|
84
|
-
templates/ workspace
|
|
87
|
+
feeds/ rss / html / html-js / github-releases / npm-registry
|
|
88
|
+
agents/ 4 CLI adapters (claude-code / codex-cli / gemini-cli / copilot)
|
|
89
|
+
schemas/ Zod schemas (Source / Item / State / Research)
|
|
90
|
+
skills/ engine SKILL bundle (research / review / update; init copies into .agents/skills/)
|
|
91
|
+
claude-skills/ Claude Code slash-command wrappers (init copies into .claude/skills/)
|
|
92
|
+
gemini-commands/ Gemini CLI TOML slash-command wrappers (init copies into .gemini/commands/)
|
|
93
|
+
templates/ default workspace templates (init copies into templates/)
|
|
85
94
|
```
|
|
86
95
|
|
|
87
|
-
##
|
|
96
|
+
## Documentation
|
|
88
97
|
|
|
89
|
-
- [docs/architecture.md](./docs/architecture.md) —
|
|
90
|
-
- [docs/user-guide.md](./docs/user-guide.md) —
|
|
91
|
-
- [docs/
|
|
98
|
+
- [docs/architecture.md](./docs/architecture.md) — system diagrams / module responsibilities / data flow / per-phase scope
|
|
99
|
+
- [docs/user-guide.md](./docs/user-guide.md) — install / quickstart / command reference
|
|
100
|
+
- [docs/release.md](./docs/release.md) — release procedure (manual initial publish + Trusted Publisher registration + subsequent OIDC automation)
|
|
101
|
+
- [docs/adr/](./docs/adr/README.md) — FeedRadar design-decision records (Agent / Source / Output / Schedule / User Data / Filter / Skill Bundling / Status State Machine / Untrusted External Content Handling)
|
|
92
102
|
|
|
93
|
-
##
|
|
103
|
+
## Conventions
|
|
94
104
|
|
|
95
|
-
-
|
|
96
|
-
-
|
|
97
|
-
-
|
|
98
|
-
-
|
|
99
|
-
-
|
|
100
|
-
-
|
|
105
|
+
- **Language**: TypeScript ESM / Node.js 22+ / pnpm
|
|
106
|
+
- **Commits**: Conventional Commits (enforced via `commitlint`)
|
|
107
|
+
- **Branching**: GitHub Flow (`main` + feature branches, squash-merge only)
|
|
108
|
+
- **Distribution**: npm `@ozzylabs/feedradar`, OIDC Trusted Publishers (no `NPM_TOKEN`)
|
|
109
|
+
- **Shared config**: distributed from [`ozzy-labs/commons`](https://github.com/ozzy-labs/commons) via `sync.sh`
|
|
110
|
+
- **Shared skills**: pulled in from [`ozzy-labs/skills`](https://github.com/ozzy-labs/skills) via the `@ozzylabs/skills` Renovate preset
|
|
101
111
|
|
|
102
112
|
## License
|
|
103
113
|
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { type ProbeOptions } from "../core/playwright-check.js";
|
|
2
|
+
import type { Command } from "./index.js";
|
|
3
|
+
/**
|
|
4
|
+
* Sinks for the `doctor` command's user-facing output.
|
|
5
|
+
*
|
|
6
|
+
* Mirrors the per-command `IO` convention (see `dismiss.ts`, `watch.ts`): tests
|
|
7
|
+
* inject capturing sinks so we can assert against the structured output without
|
|
8
|
+
* touching real stdio.
|
|
9
|
+
*/
|
|
10
|
+
export interface DoctorIO {
|
|
11
|
+
log?: (message: string) => void;
|
|
12
|
+
error?: (message: string) => void;
|
|
13
|
+
}
|
|
14
|
+
export interface DoctorCommandOptions {
|
|
15
|
+
cwd?: string;
|
|
16
|
+
io?: DoctorIO;
|
|
17
|
+
/**
|
|
18
|
+
* Test seam: override the Playwright probe (lets the doctor test stub the
|
|
19
|
+
* `import("playwright")` path without monkey-patching `node:module`).
|
|
20
|
+
*/
|
|
21
|
+
probeOptions?: ProbeOptions;
|
|
22
|
+
/**
|
|
23
|
+
* Test seam: override `process.env` lookup so the test can compose a
|
|
24
|
+
* deterministic environment without leaking through `process.env`.
|
|
25
|
+
*/
|
|
26
|
+
env?: NodeJS.ProcessEnv;
|
|
27
|
+
/**
|
|
28
|
+
* Test seam: override the `which`-style binary lookup (lets tests assert
|
|
29
|
+
* the warn / error transitions for missing agent CLIs without depending on
|
|
30
|
+
* what is actually installed on the host machine).
|
|
31
|
+
*/
|
|
32
|
+
whichImpl?: (binary: string, env: NodeJS.ProcessEnv) => Promise<string | undefined>;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Possible statuses for a single doctor check.
|
|
36
|
+
*
|
|
37
|
+
* - `ok` — feature is fully functional.
|
|
38
|
+
* - `warn` — non-blocking issue (e.g. agent CLI missing — only matters if
|
|
39
|
+
* the user wants to use that specific agent).
|
|
40
|
+
* - `error` — blocking issue for an enabled feature (e.g. Chromium missing
|
|
41
|
+
* when an html-js source is configured).
|
|
42
|
+
*/
|
|
43
|
+
export type DoctorStatus = "ok" | "warn" | "error";
|
|
44
|
+
export interface DoctorCheck {
|
|
45
|
+
/** Stable identifier for the check (used in tests + structured output). */
|
|
46
|
+
id: string;
|
|
47
|
+
/** Human-friendly status line for terminal output. */
|
|
48
|
+
message: string;
|
|
49
|
+
status: DoctorStatus;
|
|
50
|
+
}
|
|
51
|
+
export interface DoctorReport {
|
|
52
|
+
checks: DoctorCheck[];
|
|
53
|
+
/** Aggregated counts per status. */
|
|
54
|
+
summary: {
|
|
55
|
+
ok: number;
|
|
56
|
+
warn: number;
|
|
57
|
+
error: number;
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Run all doctor checks and return a structured report.
|
|
62
|
+
*
|
|
63
|
+
* Exported separately from `runDoctor` so tests and downstream tooling can
|
|
64
|
+
* consume the structured form without parsing the human-readable log.
|
|
65
|
+
*
|
|
66
|
+
* Check ordering matches the user's likely investigation order:
|
|
67
|
+
* 1. Workspace directories (broken layout → nothing else matters).
|
|
68
|
+
* 2. `radar.config.yaml` (loaders run on every command, so a malformed
|
|
69
|
+
* config blocks the whole CLI).
|
|
70
|
+
* 3. Agent CLIs (research / review / update prerequisites).
|
|
71
|
+
* 4. Playwright + Chromium (only when an html-js source is configured).
|
|
72
|
+
*/
|
|
73
|
+
export declare function runDoctorChecks(options?: DoctorCommandOptions): Promise<DoctorReport>;
|
|
74
|
+
/**
|
|
75
|
+
* Implementation of `radar doctor`.
|
|
76
|
+
*
|
|
77
|
+
* Returns 0 if no checks are at `error` status (warnings still pass — they
|
|
78
|
+
* indicate optional dependencies / partial workspace state). Returns 1 if
|
|
79
|
+
* any check is `error` so CI / scripts can gate on a clean doctor run.
|
|
80
|
+
*/
|
|
81
|
+
export declare function runDoctor(args: string[], options?: DoctorCommandOptions): Promise<number>;
|
|
82
|
+
export declare const doctorCommand: Command;
|
|
83
|
+
//# sourceMappingURL=doctor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/cli/doctor.ts"],"names":[],"mappings":"AAGA,OAAO,EAGL,KAAK,YAAY,EAElB,MAAM,6BAA6B,CAAC;AAErC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C;;;;;;GAMG;AACH,MAAM,WAAW,QAAQ;IACvB,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAED,MAAM,WAAW,oBAAoB;IACnC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,EAAE,CAAC,EAAE,QAAQ,CAAC;IACd;;;OAGG;IACH,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB;;;;OAIG;IACH,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;CACrF;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,MAAM,GAAG,OAAO,CAAC;AAEnD,MAAM,WAAW,WAAW;IAC1B,2EAA2E;IAC3E,EAAE,EAAE,MAAM,CAAC;IACX,sDAAsD;IACtD,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,YAAY,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,oCAAoC;IACpC,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CACtD;AA4DD;;;;;;;;;;;;GAYG;AACH,wBAAsB,eAAe,CAAC,OAAO,GAAE,oBAAyB,GAAG,OAAO,CAAC,YAAY,CAAC,CA4H/F;AAqCD;;;;;;GAMG;AACH,wBAAsB,SAAS,CAC7B,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,MAAM,CAAC,CA2BjB;AAED,eAAO,MAAM,aAAa,EAAE,OAI3B,CAAC"}
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import { access, constants } from "node:fs/promises";
|
|
2
|
+
import { delimiter, join } from "node:path";
|
|
3
|
+
import { loadRadarConfig, RadarConfigError } from "../core/config.js";
|
|
4
|
+
import { CHROMIUM_MISSING_HINT, PLAYWRIGHT_MODULE_MISSING_HINT, probePlaywright, } from "../core/playwright-check.js";
|
|
5
|
+
import { loadSources } from "../core/watcher.js";
|
|
6
|
+
/**
|
|
7
|
+
* Agent CLIs the `doctor` command probes for. Order matches the AgentId enum
|
|
8
|
+
* declaration so the output is deterministic across runs and easy to scan.
|
|
9
|
+
*
|
|
10
|
+
* The `binary` field is the executable name expected on $PATH. Whether the
|
|
11
|
+
* user actually needs each binary depends on which agent they pick at
|
|
12
|
+
* `research --agent <id>` time, so missing agents are reported as `warn`
|
|
13
|
+
* (not `error`) — only the user knows which subset they use.
|
|
14
|
+
*/
|
|
15
|
+
const AGENT_BINARIES = [
|
|
16
|
+
{ agent: "claude-code", binary: "claude" },
|
|
17
|
+
{ agent: "codex-cli", binary: "codex" },
|
|
18
|
+
{ agent: "gemini-cli", binary: "gemini" },
|
|
19
|
+
{ agent: "copilot", binary: "copilot" },
|
|
20
|
+
];
|
|
21
|
+
/**
|
|
22
|
+
* Workspace directories `init` creates. We check for each so a user who ran
|
|
23
|
+
* `radar source add ...` in a non-initialized directory gets a clear pointer
|
|
24
|
+
* back to `radar init` rather than a cryptic ENOENT later.
|
|
25
|
+
*/
|
|
26
|
+
const WORKSPACE_DIRS = ["sources", "items", "state", "research", "templates"];
|
|
27
|
+
async function pathExists(p) {
|
|
28
|
+
try {
|
|
29
|
+
await access(p);
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Default `which`-style lookup: walk `PATH` and return the first directory
|
|
38
|
+
* containing an executable file named `binary`.
|
|
39
|
+
*
|
|
40
|
+
* We avoid invoking `which`/`where` itself because (a) it differs between
|
|
41
|
+
* platforms (`where.exe` on Windows, `which` elsewhere), and (b) shelling out
|
|
42
|
+
* for what is a simple filesystem walk pulls in process-spawn failure modes
|
|
43
|
+
* (ENOENT for `which` on stripped-down container images, etc.) for no
|
|
44
|
+
* benefit.
|
|
45
|
+
*/
|
|
46
|
+
async function defaultWhich(binary, env) {
|
|
47
|
+
const pathEnv = env.PATH ?? env.Path ?? "";
|
|
48
|
+
if (!pathEnv)
|
|
49
|
+
return undefined;
|
|
50
|
+
const entries = pathEnv.split(delimiter).filter((p) => p.length > 0);
|
|
51
|
+
for (const dir of entries) {
|
|
52
|
+
const candidate = join(dir, binary);
|
|
53
|
+
try {
|
|
54
|
+
await access(candidate, constants.X_OK);
|
|
55
|
+
return candidate;
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
// Fall through to the next directory.
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Run all doctor checks and return a structured report.
|
|
65
|
+
*
|
|
66
|
+
* Exported separately from `runDoctor` so tests and downstream tooling can
|
|
67
|
+
* consume the structured form without parsing the human-readable log.
|
|
68
|
+
*
|
|
69
|
+
* Check ordering matches the user's likely investigation order:
|
|
70
|
+
* 1. Workspace directories (broken layout → nothing else matters).
|
|
71
|
+
* 2. `radar.config.yaml` (loaders run on every command, so a malformed
|
|
72
|
+
* config blocks the whole CLI).
|
|
73
|
+
* 3. Agent CLIs (research / review / update prerequisites).
|
|
74
|
+
* 4. Playwright + Chromium (only when an html-js source is configured).
|
|
75
|
+
*/
|
|
76
|
+
export async function runDoctorChecks(options = {}) {
|
|
77
|
+
const cwd = options.cwd ?? process.cwd();
|
|
78
|
+
const env = options.env ?? process.env;
|
|
79
|
+
const whichImpl = options.whichImpl ?? defaultWhich;
|
|
80
|
+
const checks = [];
|
|
81
|
+
// 1. Workspace directories. Each missing dir is a `warn` — the user may
|
|
82
|
+
// not need every directory yet (e.g. `research/` is empty until after
|
|
83
|
+
// `radar research` runs), but the absence is a real signal that
|
|
84
|
+
// `radar init` was skipped or partially undone.
|
|
85
|
+
for (const dir of WORKSPACE_DIRS) {
|
|
86
|
+
const abs = join(cwd, dir);
|
|
87
|
+
if (await pathExists(abs)) {
|
|
88
|
+
checks.push({
|
|
89
|
+
id: `workspace:${dir}`,
|
|
90
|
+
status: "ok",
|
|
91
|
+
message: `${dir}/ exists`,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
checks.push({
|
|
96
|
+
id: `workspace:${dir}`,
|
|
97
|
+
status: "warn",
|
|
98
|
+
message: `${dir}/ missing — run \`radar init\` to scaffold the workspace`,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// 2. `radar.config.yaml`. Absence is `ok` (the file is fully optional and
|
|
103
|
+
// every field has a built-in default). A schema violation is `error`
|
|
104
|
+
// because `radar` itself fails on every invocation when the config
|
|
105
|
+
// parses but mismatches the schema — see `core/config.ts#loadRadarConfig`.
|
|
106
|
+
try {
|
|
107
|
+
await loadRadarConfig(cwd);
|
|
108
|
+
checks.push({
|
|
109
|
+
id: "config",
|
|
110
|
+
status: "ok",
|
|
111
|
+
message: "radar.config.yaml valid (or absent — defaults apply)",
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
catch (e) {
|
|
115
|
+
const message = e instanceof RadarConfigError ? e.message : String(e);
|
|
116
|
+
checks.push({
|
|
117
|
+
id: "config",
|
|
118
|
+
status: "error",
|
|
119
|
+
message: `radar.config.yaml invalid: ${message}`,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
// 3. Agent CLIs. Missing agents are `warn` only — a user who only runs
|
|
123
|
+
// `radar research --agent claude-code` does not care that `gemini` is
|
|
124
|
+
// absent. The check still surfaces every binary so the user can spot
|
|
125
|
+
// the one they actually need.
|
|
126
|
+
for (const { agent, binary } of AGENT_BINARIES) {
|
|
127
|
+
const found = await whichImpl(binary, env);
|
|
128
|
+
if (found) {
|
|
129
|
+
checks.push({
|
|
130
|
+
id: `agent:${agent}`,
|
|
131
|
+
status: "ok",
|
|
132
|
+
message: `${agent}: ${binary} found at ${found}`,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
checks.push({
|
|
137
|
+
id: `agent:${agent}`,
|
|
138
|
+
status: "warn",
|
|
139
|
+
message: `${agent}: ${binary} not found in PATH (install it to use \`radar research --agent ${agent}\`)`,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
// 4. Playwright + Chromium. Only relevant when at least one source
|
|
144
|
+
// declares `kind: html-js`; otherwise the user does not need Playwright
|
|
145
|
+
// installed at all and a missing peer dep should not pollute the
|
|
146
|
+
// output. We load sources via `core/watcher#loadSources` so the kind
|
|
147
|
+
// detection matches what `watch run` actually iterates over.
|
|
148
|
+
const sourcesDir = join(cwd, "sources");
|
|
149
|
+
let htmlJsSources = [];
|
|
150
|
+
if (await pathExists(sourcesDir)) {
|
|
151
|
+
const sources = await loadSources(sourcesDir, () => {
|
|
152
|
+
// Schema / read errors are surfaced separately via the workspace +
|
|
153
|
+
// config checks above; here we only care about the kind distribution.
|
|
154
|
+
// Silently dropping malformed YAMLs is fine for kind detection.
|
|
155
|
+
});
|
|
156
|
+
htmlJsSources = sources.filter((s) => s.kind === "html-js").map((s) => s.id);
|
|
157
|
+
}
|
|
158
|
+
if (htmlJsSources.length === 0) {
|
|
159
|
+
checks.push({
|
|
160
|
+
id: "playwright",
|
|
161
|
+
status: "ok",
|
|
162
|
+
message: "playwright: not required (no html-js sources configured)",
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
const probe = await probePlaywright(options.probeOptions);
|
|
167
|
+
if (probe.status === "ok") {
|
|
168
|
+
checks.push({
|
|
169
|
+
id: "playwright",
|
|
170
|
+
status: "ok",
|
|
171
|
+
message: `playwright: ok — chromium at ${probe.executablePath}`,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
else if (probe.status === "module-missing") {
|
|
175
|
+
checks.push({
|
|
176
|
+
id: "playwright",
|
|
177
|
+
status: "error",
|
|
178
|
+
message: `playwright: module not installed (required by html-js sources: ${htmlJsSources.join(", ")})\n ${PLAYWRIGHT_MODULE_MISSING_HINT}`,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
checks.push({
|
|
183
|
+
id: "playwright",
|
|
184
|
+
status: "error",
|
|
185
|
+
message: `playwright: chromium missing at '${probe.executablePath}' (required by html-js sources: ${htmlJsSources.join(", ")})\n ${CHROMIUM_MISSING_HINT}`,
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
const summary = checks.reduce((acc, c) => {
|
|
190
|
+
acc[c.status]++;
|
|
191
|
+
return acc;
|
|
192
|
+
}, { ok: 0, warn: 0, error: 0 });
|
|
193
|
+
return { checks, summary };
|
|
194
|
+
}
|
|
195
|
+
function parseDoctorArgs(args) {
|
|
196
|
+
const out = {};
|
|
197
|
+
for (const arg of args) {
|
|
198
|
+
if (arg === "-h" || arg === "--help") {
|
|
199
|
+
out.help = true;
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
if (arg.startsWith("--")) {
|
|
203
|
+
throw new Error(`unknown option: ${arg}`);
|
|
204
|
+
}
|
|
205
|
+
throw new Error(`unexpected argument: ${arg}`);
|
|
206
|
+
}
|
|
207
|
+
return out;
|
|
208
|
+
}
|
|
209
|
+
function printDoctorHelp(log) {
|
|
210
|
+
log("Usage: radar doctor");
|
|
211
|
+
log("");
|
|
212
|
+
log("Diagnose the workspace and report dependency / configuration health.");
|
|
213
|
+
log("");
|
|
214
|
+
log("Checks performed:");
|
|
215
|
+
log(" - Workspace directories (sources/, items/, state/, research/, templates/)");
|
|
216
|
+
log(" - radar.config.yaml schema validity");
|
|
217
|
+
log(" - Agent CLI availability (claude / codex / gemini / copilot)");
|
|
218
|
+
log(" - Playwright + Chromium install (only if html-js sources configured)");
|
|
219
|
+
log("");
|
|
220
|
+
log("Exit codes:");
|
|
221
|
+
log(" 0 all ok (warnings may appear, but no errors)");
|
|
222
|
+
log(" 1 one or more error-level checks failed");
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Implementation of `radar doctor`.
|
|
226
|
+
*
|
|
227
|
+
* Returns 0 if no checks are at `error` status (warnings still pass — they
|
|
228
|
+
* indicate optional dependencies / partial workspace state). Returns 1 if
|
|
229
|
+
* any check is `error` so CI / scripts can gate on a clean doctor run.
|
|
230
|
+
*/
|
|
231
|
+
export async function runDoctor(args, options = {}) {
|
|
232
|
+
const log = options.io?.log ?? ((m) => console.log(m));
|
|
233
|
+
const error = options.io?.error ?? ((m) => console.error(m));
|
|
234
|
+
let parsed;
|
|
235
|
+
try {
|
|
236
|
+
parsed = parseDoctorArgs(args);
|
|
237
|
+
}
|
|
238
|
+
catch (e) {
|
|
239
|
+
error(`doctor: ${e instanceof Error ? e.message : String(e)}`);
|
|
240
|
+
return 2;
|
|
241
|
+
}
|
|
242
|
+
if (parsed.help) {
|
|
243
|
+
printDoctorHelp(log);
|
|
244
|
+
return 0;
|
|
245
|
+
}
|
|
246
|
+
const report = await runDoctorChecks(options);
|
|
247
|
+
for (const check of report.checks) {
|
|
248
|
+
const tag = check.status === "ok" ? "[ok] " : check.status === "warn" ? "[warn] " : "[error]";
|
|
249
|
+
log(`${tag} ${check.message}`);
|
|
250
|
+
}
|
|
251
|
+
log("");
|
|
252
|
+
log(`doctor: ${report.summary.ok} ok, ${report.summary.warn} warn, ${report.summary.error} error`);
|
|
253
|
+
return report.summary.error > 0 ? 1 : 0;
|
|
254
|
+
}
|
|
255
|
+
export const doctorCommand = {
|
|
256
|
+
name: "doctor",
|
|
257
|
+
summary: "Diagnose workspace, agent CLIs, and html-js Playwright install",
|
|
258
|
+
run: (args) => runDoctor(args),
|
|
259
|
+
};
|
|
260
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/cli/doctor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACtE,OAAO,EACL,qBAAqB,EACrB,8BAA8B,EAE9B,eAAe,GAChB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AA6DjD;;;;;;;;GAQG;AACH,MAAM,cAAc,GAAqD;IACvE,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,QAAQ,EAAE;IAC1C,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE;IACvC,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE;IACzC,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE;CACxC,CAAC;AAEF;;;;GAIG;AACH,MAAM,cAAc,GAAG,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,WAAW,CAAU,CAAC;AAEvF,KAAK,UAAU,UAAU,CAAC,CAAS;IACjC,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,CAAC,CAAC,CAAC;QAChB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,KAAK,UAAU,YAAY,CAAC,MAAc,EAAE,GAAsB;IAChE,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;IAC3C,IAAI,CAAC,OAAO;QAAE,OAAO,SAAS,CAAC;IAC/B,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACrE,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;QAC1B,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QACpC,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,SAAS,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;YACxC,OAAO,SAAS,CAAC;QACnB,CAAC;QAAC,MAAM,CAAC;YACP,sCAAsC;QACxC,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,UAAgC,EAAE;IACtE,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IACzC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IACvC,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,YAAY,CAAC;IACpD,MAAM,MAAM,GAAkB,EAAE,CAAC;IAEjC,wEAAwE;IACxE,yEAAyE;IACzE,mEAAmE;IACnE,mDAAmD;IACnD,KAAK,MAAM,GAAG,IAAI,cAAc,EAAE,CAAC;QACjC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QAC3B,IAAI,MAAM,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1B,MAAM,CAAC,IAAI,CAAC;gBACV,EAAE,EAAE,aAAa,GAAG,EAAE;gBACtB,MAAM,EAAE,IAAI;gBACZ,OAAO,EAAE,GAAG,GAAG,UAAU;aAC1B,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,IAAI,CAAC;gBACV,EAAE,EAAE,aAAa,GAAG,EAAE;gBACtB,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,GAAG,GAAG,0DAA0D;aAC1E,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,0EAA0E;IAC1E,wEAAwE;IACxE,sEAAsE;IACtE,8EAA8E;IAC9E,IAAI,CAAC;QACH,MAAM,eAAe,CAAC,GAAG,CAAC,CAAC;QAC3B,MAAM,CAAC,IAAI,CAAC;YACV,EAAE,EAAE,QAAQ;YACZ,MAAM,EAAE,IAAI;YACZ,OAAO,EAAE,sDAAsD;SAChE,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,OAAO,GAAG,CAAC,YAAY,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACtE,MAAM,CAAC,IAAI,CAAC;YACV,EAAE,EAAE,QAAQ;YACZ,MAAM,EAAE,OAAO;YACf,OAAO,EAAE,8BAA8B,OAAO,EAAE;SACjD,CAAC,CAAC;IACL,CAAC;IAED,uEAAuE;IACvE,yEAAyE;IACzE,wEAAwE;IACxE,iCAAiC;IACjC,KAAK,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,cAAc,EAAE,CAAC;QAC/C,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAC3C,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,CAAC,IAAI,CAAC;gBACV,EAAE,EAAE,SAAS,KAAK,EAAE;gBACpB,MAAM,EAAE,IAAI;gBACZ,OAAO,EAAE,GAAG,KAAK,KAAK,MAAM,aAAa,KAAK,EAAE;aACjD,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,IAAI,CAAC;gBACV,EAAE,EAAE,SAAS,KAAK,EAAE;gBACpB,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,GAAG,KAAK,KAAK,MAAM,kEAAkE,KAAK,KAAK;aACzG,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,mEAAmE;IACnE,2EAA2E;IAC3E,oEAAoE;IACpE,wEAAwE;IACxE,gEAAgE;IAChE,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IACxC,IAAI,aAAa,GAAa,EAAE,CAAC;IACjC,IAAI,MAAM,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QACjC,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,UAAU,EAAE,GAAG,EAAE;YACjD,mEAAmE;YACnE,sEAAsE;YACtE,gEAAgE;QAClE,CAAC,CAAC,CAAC;QACH,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAC/E,CAAC;IACD,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/B,MAAM,CAAC,IAAI,CAAC;YACV,EAAE,EAAE,YAAY;YAChB,MAAM,EAAE,IAAI;YACZ,OAAO,EAAE,0DAA0D;SACpE,CAAC,CAAC;IACL,CAAC;SAAM,CAAC;QACN,MAAM,KAAK,GAAG,MAAM,eAAe,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;QAC1D,IAAI,KAAK,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;YAC1B,MAAM,CAAC,IAAI,CAAC;gBACV,EAAE,EAAE,YAAY;gBAChB,MAAM,EAAE,IAAI;gBACZ,OAAO,EAAE,gCAAgC,KAAK,CAAC,cAAc,EAAE;aAChE,CAAC,CAAC;QACL,CAAC;aAAM,IAAI,KAAK,CAAC,MAAM,KAAK,gBAAgB,EAAE,CAAC;YAC7C,MAAM,CAAC,IAAI,CAAC;gBACV,EAAE,EAAE,YAAY;gBAChB,MAAM,EAAE,OAAO;gBACf,OAAO,EAAE,kEAAkE,aAAa,CAAC,IAAI,CAC3F,IAAI,CACL,QAAQ,8BAA8B,EAAE;aAC1C,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,IAAI,CAAC;gBACV,EAAE,EAAE,YAAY;gBAChB,MAAM,EAAE,OAAO;gBACf,OAAO,EAAE,oCAAoC,KAAK,CAAC,cAAc,mCAAmC,aAAa,CAAC,IAAI,CACpH,IAAI,CACL,QAAQ,qBAAqB,EAAE;aACjC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAC3B,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE;QACT,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;QAChB,OAAO,GAAG,CAAC;IACb,CAAC,EACD,EAAE,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAC7B,CAAC;IACF,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;AAC7B,CAAC;AAMD,SAAS,eAAe,CAAC,IAAc;IACrC,MAAM,GAAG,GAAe,EAAE,CAAC;IAC3B,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,QAAQ,EAAE,CAAC;YACrC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;YAChB,SAAS;QACX,CAAC;QACD,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,mBAAmB,GAAG,EAAE,CAAC,CAAC;QAC5C,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,wBAAwB,GAAG,EAAE,CAAC,CAAC;IACjD,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,eAAe,CAAC,GAAwB;IAC/C,GAAG,CAAC,qBAAqB,CAAC,CAAC;IAC3B,GAAG,CAAC,EAAE,CAAC,CAAC;IACR,GAAG,CAAC,sEAAsE,CAAC,CAAC;IAC5E,GAAG,CAAC,EAAE,CAAC,CAAC;IACR,GAAG,CAAC,mBAAmB,CAAC,CAAC;IACzB,GAAG,CAAC,6EAA6E,CAAC,CAAC;IACnF,GAAG,CAAC,uCAAuC,CAAC,CAAC;IAC7C,GAAG,CAAC,gEAAgE,CAAC,CAAC;IACtE,GAAG,CAAC,wEAAwE,CAAC,CAAC;IAC9E,GAAG,CAAC,EAAE,CAAC,CAAC;IACR,GAAG,CAAC,aAAa,CAAC,CAAC;IACnB,GAAG,CAAC,kDAAkD,CAAC,CAAC;IACxD,GAAG,CAAC,4CAA4C,CAAC,CAAC;AACpD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,IAAc,EACd,UAAgC,EAAE;IAElC,MAAM,GAAG,GAAG,OAAO,CAAC,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/D,MAAM,KAAK,GAAG,OAAO,CAAC,EAAE,EAAE,KAAK,IAAI,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAErE,IAAI,MAAkB,CAAC;IACvB,IAAI,CAAC;QACH,MAAM,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;IACjC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,KAAK,CAAC,WAAW,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC/D,OAAO,CAAC,CAAC;IACX,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;QAChB,eAAe,CAAC,GAAG,CAAC,CAAC;QACrB,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,OAAO,CAAC,CAAC;IAC9C,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAClC,MAAM,GAAG,GACP,KAAK,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC;QACvF,GAAG,CAAC,GAAG,GAAG,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IACjC,CAAC;IACD,GAAG,CAAC,EAAE,CAAC,CAAC;IACR,GAAG,CACD,WAAW,MAAM,CAAC,OAAO,CAAC,EAAE,QAAQ,MAAM,CAAC,OAAO,CAAC,IAAI,UAAU,MAAM,CAAC,OAAO,CAAC,KAAK,QAAQ,CAC9F,CAAC;IACF,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1C,CAAC;AAED,MAAM,CAAC,MAAM,aAAa,GAAY;IACpC,IAAI,EAAE,QAAQ;IACd,OAAO,EAAE,gEAAgE;IACzE,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC;CAC/B,CAAC"}
|