@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.
Files changed (47) hide show
  1. package/README.ja.md +114 -0
  2. package/README.md +63 -53
  3. package/dist/cli/doctor.d.ts +83 -0
  4. package/dist/cli/doctor.d.ts.map +1 -0
  5. package/dist/cli/doctor.js +260 -0
  6. package/dist/cli/doctor.js.map +1 -0
  7. package/dist/cli/index.d.ts.map +1 -1
  8. package/dist/cli/index.js +2 -2
  9. package/dist/cli/index.js.map +1 -1
  10. package/dist/cli/source.d.ts.map +1 -1
  11. package/dist/cli/source.js +6 -3
  12. package/dist/cli/source.js.map +1 -1
  13. package/dist/cli/watch.d.ts +16 -0
  14. package/dist/cli/watch.d.ts.map +1 -1
  15. package/dist/cli/watch.js +3 -0
  16. package/dist/cli/watch.js.map +1 -1
  17. package/dist/core/feeds/_html-common.d.ts +30 -0
  18. package/dist/core/feeds/_html-common.d.ts.map +1 -0
  19. package/dist/core/feeds/_html-common.js +192 -0
  20. package/dist/core/feeds/_html-common.js.map +1 -0
  21. package/dist/core/feeds/html-js.d.ts +50 -0
  22. package/dist/core/feeds/html-js.d.ts.map +1 -0
  23. package/dist/core/feeds/html-js.js +135 -0
  24. package/dist/core/feeds/html-js.js.map +1 -0
  25. package/dist/core/feeds/html.d.ts +1 -7
  26. package/dist/core/feeds/html.d.ts.map +1 -1
  27. package/dist/core/feeds/html.js +5 -180
  28. package/dist/core/feeds/html.js.map +1 -1
  29. package/dist/core/feeds/index.d.ts.map +1 -1
  30. package/dist/core/feeds/index.js +2 -0
  31. package/dist/core/feeds/index.js.map +1 -1
  32. package/dist/core/playwright-check.d.ts +134 -0
  33. package/dist/core/playwright-check.d.ts.map +1 -0
  34. package/dist/core/playwright-check.js +98 -0
  35. package/dist/core/playwright-check.js.map +1 -0
  36. package/dist/core/watcher.d.ts +17 -0
  37. package/dist/core/watcher.d.ts.map +1 -1
  38. package/dist/core/watcher.js +59 -0
  39. package/dist/core/watcher.js.map +1 -1
  40. package/dist/index.js +0 -0
  41. package/dist/schemas/source.d.ts +42 -0
  42. package/dist/schemas/source.d.ts.map +1 -1
  43. package/dist/schemas/source.js +42 -7
  44. package/dist/schemas/source.js.map +1 -1
  45. package/dist/templates/agents/AGENTS.md +2 -2
  46. package/dist/templates/feedradar.md +2 -2
  47. 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
- # FeedRadar
1
+ English | [日本語](README.ja.md)
2
2
 
3
- > **Status: alpha** — Phase 1-5 まで実装済み(7 サブコマンド + 4 agent × 4 source kind + cron 雛形 + [ADR-0009](./docs/adr/0009-untrusted-external-content-handling.md) Adopt 策)。Phase 6 進行中: 初回 `v0.1.0` は手動 publish 予定、2 回目以降は sibling-style `release.yaml` で OIDC 自動 publish(手順: [docs/release.md](./docs/release.md))。
3
+ # FeedRadar
4
4
 
5
- ブログ・公式アップデート・リリースフィードを監視し、キーワードヒットを 4 種の AI エージェント (Claude Code / Codex / Gemini / Copilot) に渡して **Markdown 調査レポートを書かせる CLI**。
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
- 複数の公式ブログ・ドキュメント・リリースノートを横断的に追い、変更点を要約する作業は AI エージェントとの相性が良いが、ソース管理・差分検出・テンプレート適用・複数エージェントへの委譲を毎回手作業で組むのは煩雑になる。`radar` はこのループを CLI として固定化し、ユーザーの調査ディレクトリに Markdown レポートを蓄積する。
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
- - **多エージェント対応**: Claude Code / Codex CLI / Gemini CLI / GitHub Copilot CLI adapter 経由で切り替え。
14
- - **複数フィード種別**: RSS / HTML スクレイプ / GitHub Releases / npm registry を同一の `Source` 抽象で扱う。
15
- - **ユーザー側データ管理**: `sources/` `items/` `state/` `research/` `templates/` **ユーザーの任意ディレクトリ** に置き、本パッケージは engine のみを提供する。
16
- - **npm 単体配布**: OIDC Trusted Publishers で `@ozzylabs/feedradar` を公開予定(Phase 6)。
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
- 開発中は本リポを clone し、`pnpm install && pnpm run build` `dist/index.js` を生成して `node dist/index.js <command>` で起動する。
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
- # クイックスタート (anthropics/anthropic-sdk-python GitHub Releases を監視)
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> # 不要 item dismissed に遷移(LLM 不要)
42
- radar review <research-id> # レポートを別エージェントで相互レビュー
43
- radar update <research-id> # 既存レポートを最新 item で更新(v+1
44
- radar --help # ヘルプ
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
- 7 サブコマンドが実装済み。詳細は [docs/user-guide.md](./docs/user-guide.md) を参照。
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 でビルド(dist/)
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
- # ローカルで CLI を呼ぶ場合 (build)
58
- pnpm radar --help # = node dist/index.js --help (package.json scripts alias)
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
- > ローカルの `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` 等が走る事故になる)。
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 load / save
74
- templates.ts research テンプレートの読み込み
75
- state.ts state/<sourceId>.yaml load / save
76
- config.ts radar.config.yaml load / 検証
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 adaptersclaude-code / codex-cli / gemini-cli / copilot
80
- schemas/ Zod スキーマ(Source / Item / State / Research
81
- skills/ engine SKILL bundle (research / review / update; init .agents/skills/ に配布)
82
- claude-skills/ Claude Code slash-command 雛形 (init .claude/skills/ に配布)
83
- gemini-commands/ Gemini CLI TOML slash-command 雛形 (init .gemini/commands/ に配布)
84
- templates/ workspace 既定テンプレート (init templates/ に配布)
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) — システム全体図 / モジュール責務 / データフロー / Phase 別スコープ
90
- - [docs/user-guide.md](./docs/user-guide.md) — インストール / クイックスタート / コマンド仕様
91
- - [docs/adr/](./docs/adr/README.md) — FeedRadar 内部の設計判断記録(Agent / Source / Output / Schedule / User Data / Filter / Skill Bundling / Status State Machine / Untrusted External Content Handling)
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
- - **言語**: TypeScript ESM / Node.js 22+ / pnpm
96
- - **コミット**: Conventional Commits(`commitlint` で強制)
97
- - **ブランチ**: GitHub Flow(`main` + feature branch、squash merge のみ)
98
- - **配布**: npm `@ozzylabs/feedradar`、OIDC Trusted Publishers(`NPM_TOKEN` は使わない)
99
- - **共通設定**: [`ozzy-labs/commons`](https://github.com/ozzy-labs/commons) から `sync.sh` で配布。
100
- - **共通スキル**: [`ozzy-labs/skills`](https://github.com/ozzy-labs/skills) `@ozzylabs/skills` Renovate preset で取り込み。
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":"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"}