@ozzylabs/feedradar 0.1.3 → 0.1.5
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 +31 -6
- package/README.md +31 -6
- package/dist/agents/claude-code.d.ts +12 -1
- package/dist/agents/claude-code.d.ts.map +1 -1
- package/dist/agents/claude-code.js +9 -5
- package/dist/agents/claude-code.js.map +1 -1
- package/dist/agents/codex-cli.d.ts +7 -1
- package/dist/agents/codex-cli.d.ts.map +1 -1
- package/dist/agents/codex-cli.js +9 -5
- package/dist/agents/codex-cli.js.map +1 -1
- package/dist/agents/copilot.d.ts +7 -1
- package/dist/agents/copilot.d.ts.map +1 -1
- package/dist/agents/copilot.js +9 -5
- package/dist/agents/copilot.js.map +1 -1
- package/dist/agents/gemini-cli.d.ts +7 -1
- package/dist/agents/gemini-cli.d.ts.map +1 -1
- package/dist/agents/gemini-cli.js +9 -5
- package/dist/agents/gemini-cli.js.map +1 -1
- package/dist/agents/index.d.ts +1 -1
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/types.d.ts +33 -0
- package/dist/agents/types.d.ts.map +1 -1
- package/dist/cli/_progress.d.ts +138 -0
- package/dist/cli/_progress.d.ts.map +1 -0
- package/dist/cli/_progress.js +176 -0
- package/dist/cli/_progress.js.map +1 -0
- package/dist/cli/doctor.d.ts +20 -0
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +291 -2
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +2 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/research.d.ts +18 -20
- package/dist/cli/research.d.ts.map +1 -1
- package/dist/cli/research.js +318 -203
- package/dist/cli/research.js.map +1 -1
- package/dist/cli/respawn.d.ts +53 -0
- package/dist/cli/respawn.d.ts.map +1 -0
- package/dist/cli/respawn.js +120 -0
- package/dist/cli/respawn.js.map +1 -0
- package/dist/cli/review.d.ts +7 -0
- package/dist/cli/review.d.ts.map +1 -1
- package/dist/cli/review.js +46 -1
- package/dist/cli/review.js.map +1 -1
- package/dist/cli/source.d.ts +23 -2
- package/dist/cli/source.d.ts.map +1 -1
- package/dist/cli/source.js +425 -7
- package/dist/cli/source.js.map +1 -1
- package/dist/cli/update.d.ts +7 -0
- package/dist/cli/update.d.ts.map +1 -1
- package/dist/cli/update.js +41 -1
- package/dist/cli/update.js.map +1 -1
- package/dist/cli/watch.d.ts.map +1 -1
- package/dist/cli/watch.js +65 -3
- package/dist/cli/watch.js.map +1 -1
- package/dist/cli/workflow/generate-combined.d.ts +100 -0
- package/dist/cli/workflow/generate-combined.d.ts.map +1 -0
- package/dist/cli/workflow/generate-combined.js +387 -0
- package/dist/cli/workflow/generate-combined.js.map +1 -0
- package/dist/cli/workflow/generate-watch.d.ts +142 -0
- package/dist/cli/workflow/generate-watch.d.ts.map +1 -0
- package/dist/cli/workflow/generate-watch.js +338 -0
- package/dist/cli/workflow/generate-watch.js.map +1 -0
- package/dist/cli/workflow.d.ts +29 -0
- package/dist/cli/workflow.d.ts.map +1 -0
- package/dist/cli/workflow.js +66 -0
- package/dist/cli/workflow.js.map +1 -0
- package/dist/core/feeds/_fetch.d.ts +103 -0
- package/dist/core/feeds/_fetch.d.ts.map +1 -0
- package/dist/core/feeds/_fetch.js +364 -0
- package/dist/core/feeds/_fetch.js.map +1 -0
- package/dist/core/feeds/_jsonpath.d.ts +57 -0
- package/dist/core/feeds/_jsonpath.d.ts.map +1 -0
- package/dist/core/feeds/_jsonpath.js +207 -0
- package/dist/core/feeds/_jsonpath.js.map +1 -0
- package/dist/core/feeds/github-api.d.ts.map +1 -1
- package/dist/core/feeds/github-api.js +2 -1
- package/dist/core/feeds/github-api.js.map +1 -1
- package/dist/core/feeds/html-js.d.ts +29 -0
- package/dist/core/feeds/html-js.d.ts.map +1 -1
- package/dist/core/feeds/html-js.js +86 -2
- package/dist/core/feeds/html-js.js.map +1 -1
- package/dist/core/feeds/html.d.ts.map +1 -1
- package/dist/core/feeds/html.js +2 -1
- package/dist/core/feeds/html.js.map +1 -1
- package/dist/core/feeds/index.d.ts +1 -1
- package/dist/core/feeds/index.d.ts.map +1 -1
- package/dist/core/feeds/index.js +4 -0
- package/dist/core/feeds/index.js.map +1 -1
- package/dist/core/feeds/json-api.d.ts +3 -0
- package/dist/core/feeds/json-api.d.ts.map +1 -0
- package/dist/core/feeds/json-api.js +723 -0
- package/dist/core/feeds/json-api.js.map +1 -0
- package/dist/core/feeds/json-feed.d.ts +11 -0
- package/dist/core/feeds/json-feed.d.ts.map +1 -0
- package/dist/core/feeds/json-feed.js +242 -0
- package/dist/core/feeds/json-feed.js.map +1 -0
- package/dist/core/feeds/npm-registry.d.ts.map +1 -1
- package/dist/core/feeds/npm-registry.js +2 -1
- package/dist/core/feeds/npm-registry.js.map +1 -1
- package/dist/core/feeds/rss.d.ts.map +1 -1
- package/dist/core/feeds/rss.js +2 -1
- package/dist/core/feeds/rss.js.map +1 -1
- package/dist/core/feeds/types.d.ts +123 -0
- package/dist/core/feeds/types.d.ts.map +1 -1
- package/dist/core/progress.d.ts +101 -0
- package/dist/core/progress.d.ts.map +1 -0
- package/dist/core/progress.js +212 -0
- package/dist/core/progress.js.map +1 -0
- package/dist/core/proxy.d.ts +87 -0
- package/dist/core/proxy.d.ts.map +1 -0
- package/dist/core/proxy.js +146 -0
- package/dist/core/proxy.js.map +1 -0
- package/dist/core/recipes.d.ts +138 -0
- package/dist/core/recipes.d.ts.map +1 -0
- package/dist/core/recipes.js +238 -0
- package/dist/core/recipes.js.map +1 -0
- package/dist/core/watcher.d.ts +61 -1
- package/dist/core/watcher.d.ts.map +1 -1
- package/dist/core/watcher.js +99 -2
- package/dist/core/watcher.js.map +1 -1
- package/dist/index.js +17 -4
- package/dist/index.js.map +1 -1
- package/dist/recipes/aws-whats-new.yaml +61 -0
- package/dist/recipes/dev-to.yaml +40 -0
- package/dist/schemas/index.d.ts +1 -0
- package/dist/schemas/index.d.ts.map +1 -1
- package/dist/schemas/index.js +1 -0
- package/dist/schemas/index.js.map +1 -1
- package/dist/schemas/recipe.d.ts +115 -0
- package/dist/schemas/recipe.d.ts.map +1 -0
- package/dist/schemas/recipe.js +54 -0
- package/dist/schemas/recipe.js.map +1 -0
- package/dist/schemas/source.d.ts +130 -0
- package/dist/schemas/source.d.ts.map +1 -1
- package/dist/schemas/source.js +130 -0
- package/dist/schemas/source.js.map +1 -1
- package/dist/templates/agents/AGENTS.md +31 -3
- package/dist/templates/feedradar.md +23 -8
- package/dist/templates/workflows/combined.template.yaml.tmpl +110 -0
- package/dist/templates/workflows/watch.template.yaml.tmpl +103 -0
- package/dist/templates/workflows/watch.yaml +5 -1
- package/package.json +2 -3
package/dist/schemas/source.js
CHANGED
|
@@ -5,6 +5,8 @@ export const SourceKindSchema = z.enum([
|
|
|
5
5
|
"html-js",
|
|
6
6
|
"github-releases",
|
|
7
7
|
"npm-registry",
|
|
8
|
+
"json-feed",
|
|
9
|
+
"json-api",
|
|
8
10
|
]);
|
|
9
11
|
/**
|
|
10
12
|
* Match modes for keyword evaluation (ADR-0006).
|
|
@@ -93,6 +95,114 @@ export const SourceJsOptionsSchema = z.object({
|
|
|
93
95
|
timeout: z.number().int().positive().default(30000),
|
|
94
96
|
userAgent: z.string().optional(),
|
|
95
97
|
});
|
|
98
|
+
/**
|
|
99
|
+
* HTTP options for `kind: json-api` sources (ADR-0012 §D2).
|
|
100
|
+
*
|
|
101
|
+
* Phase 1 supports GET only. `headers` accepts arbitrary key/value pairs and
|
|
102
|
+
* supports `${VAR}` env-var interpolation (resolved by the adapter, never
|
|
103
|
+
* persisted to log / frontmatter — see ADR-0012 §D5c).
|
|
104
|
+
*
|
|
105
|
+
* The schema deliberately does not validate header values against env names —
|
|
106
|
+
* the adapter handles unresolved `${VAR}` placeholders by omitting the header
|
|
107
|
+
* (degraded fetch). This lets public APIs work without env wiring while
|
|
108
|
+
* authenticated APIs fail-fast with a 401/403 at runtime.
|
|
109
|
+
*/
|
|
110
|
+
export const SourceHttpOptionsSchema = z.object({
|
|
111
|
+
method: z.literal("GET").default("GET"),
|
|
112
|
+
headers: z.record(z.string(), z.string()).default({}),
|
|
113
|
+
});
|
|
114
|
+
/**
|
|
115
|
+
* Pagination configuration for `kind: json-api` sources (ADR-0012 §D2).
|
|
116
|
+
*
|
|
117
|
+
* Five wire formats are supported:
|
|
118
|
+
*
|
|
119
|
+
* page — `?page=K&pageSize=N` (e.g. AWS What's New, dev.to)
|
|
120
|
+
* offset — `?offset=K&limit=N`
|
|
121
|
+
* cursor — `?after=<cursorValue>` with `nextCursor` extracted via JSONPath
|
|
122
|
+
* link-header — `Link: <...>; rel="next"` HTTP header
|
|
123
|
+
* token — `?pageToken=<opaque>` opaque continuation token
|
|
124
|
+
* none — single request, no pagination
|
|
125
|
+
*
|
|
126
|
+
* `maxPages` is a hard cap to prevent runaway loops / DoS on misconfigured
|
|
127
|
+
* recipes. The default (20) matches a conservative bound for normal-mode
|
|
128
|
+
* fetching; `--backfill` can override via `--max-pages` to walk further.
|
|
129
|
+
*
|
|
130
|
+
* `nextCursorPath` / `totalPath` are JSONPath-lite expressions resolved against
|
|
131
|
+
* the parsed response body. `totalPath` is consulted in backfill mode to
|
|
132
|
+
* compute an upper bound on pages and short-circuit early when the total is
|
|
133
|
+
* known.
|
|
134
|
+
*/
|
|
135
|
+
export const SourcePaginationSchema = z.object({
|
|
136
|
+
type: z.enum(["page", "offset", "cursor", "link-header", "token", "none"]),
|
|
137
|
+
/**
|
|
138
|
+
* Query parameter name for the page / offset / token (e.g. `page`, `offset`,
|
|
139
|
+
* `after`, `pageToken`). Required for `page` / `offset` / `cursor` / `token`;
|
|
140
|
+
* ignored for `link-header` / `none`.
|
|
141
|
+
*/
|
|
142
|
+
param: z.string().min(1).optional(),
|
|
143
|
+
/** Initial value (e.g. 0 for offset, 1 for page-number, undefined for cursor/token). */
|
|
144
|
+
start: z.number().int().optional(),
|
|
145
|
+
/** Items per page (e.g. 100 for AWS, 30 for dev.to). */
|
|
146
|
+
pageSize: z.number().int().positive().optional(),
|
|
147
|
+
/** Query parameter name for the page-size value. Defaults to `pageSize` when present. */
|
|
148
|
+
pageSizeParam: z.string().min(1).optional(),
|
|
149
|
+
/** JSONPath-lite to the next-cursor / next-token value in the response body. */
|
|
150
|
+
nextCursorPath: z.string().min(1).optional(),
|
|
151
|
+
/** JSONPath-lite to the total-count value in the response body (backfill-mode early-stop hint). */
|
|
152
|
+
totalPath: z.string().min(1).optional(),
|
|
153
|
+
/** Hard cap on pages traversed. Default 20 (normal mode); `--max-pages` overrides in backfill. */
|
|
154
|
+
maxPages: z.number().int().positive().default(20),
|
|
155
|
+
});
|
|
156
|
+
/**
|
|
157
|
+
* Selector ruleset for `kind: json-api` sources (ADR-0012 §D2).
|
|
158
|
+
*
|
|
159
|
+
* Every selector is a JSONPath-lite expression (`src/core/feeds/_jsonpath.ts`).
|
|
160
|
+
*
|
|
161
|
+
* Every field is optional. When omitted the adapter falls back to a default
|
|
162
|
+
* selector chain per field (#174 / ADR-0012 §D2 defaults). For "simple"
|
|
163
|
+
* page-based APIs (dev.to, JSON Feed-shaped) the recipe can therefore omit
|
|
164
|
+
* `jsonSelectors` entirely (or use just `{}`) and rely on:
|
|
165
|
+
*
|
|
166
|
+
* items — `$.items[*] || $.data[*] || $.results[*] || $.posts[*] || $.entries[*] || $[*]`
|
|
167
|
+
* title — `$.title || $.name || $.headline`
|
|
168
|
+
* link — `$.url || $.link || $.permalink || $.html_url`
|
|
169
|
+
* publishedAt — `$.publishedAt || $.published_at || $.date || $.created_at || $.pubDate`
|
|
170
|
+
* summary — `$.summary || $.description || $.excerpt || $.body`
|
|
171
|
+
*
|
|
172
|
+
* - `publisherId` has no fallback chain (stable id derivation falls through
|
|
173
|
+
* to `link` URL by default; see `derive-id.ts`).
|
|
174
|
+
* - `body` / `tags` have no fallback chain (rarely needed for normalization).
|
|
175
|
+
* - `linkBase` resolves relative `link` values against an explicit base URL
|
|
176
|
+
* (defaults to `source.url`). See field-level docstring for details (#204).
|
|
177
|
+
*
|
|
178
|
+
* Note that selectors are evaluated against each item element (already
|
|
179
|
+
* dereferenced via `items`), so paths inside this schema commonly use `$` as
|
|
180
|
+
* the per-item root (e.g. `$.title`, `$.created_at`).
|
|
181
|
+
*/
|
|
182
|
+
export const SourceJsonApiSelectorsSchema = z.object({
|
|
183
|
+
items: z.string().min(1).optional(),
|
|
184
|
+
title: z.string().min(1).optional(),
|
|
185
|
+
link: z.string().min(1).optional(),
|
|
186
|
+
publisherId: z.string().min(1).optional(),
|
|
187
|
+
summary: z.string().min(1).optional(),
|
|
188
|
+
publishedAt: z.string().min(1).optional(),
|
|
189
|
+
body: z.string().min(1).optional(),
|
|
190
|
+
tags: z.string().min(1).optional(),
|
|
191
|
+
/**
|
|
192
|
+
* Base URL used to resolve relative `link` values returned by the API
|
|
193
|
+
* (#204). Many APIs (e.g. AWS What's New) return `headlineUrl` as a path
|
|
194
|
+
* like `/about-aws/whats-new/.../` instead of a full URL, which causes
|
|
195
|
+
* every item to be silently dropped at `ItemSchema` validation. When
|
|
196
|
+
* `linkBase` is set, the adapter resolves relative `link` values against
|
|
197
|
+
* it (`new URL(raw, linkBase)`); when omitted, `source.url` is used as
|
|
198
|
+
* the base, mirroring how the html adapter resolves `<a href="/...">`.
|
|
199
|
+
* Absolute links pass through untouched in either case.
|
|
200
|
+
*
|
|
201
|
+
* Must be a fully-qualified http(s) URL — invalid bases would silently
|
|
202
|
+
* mis-resolve, so we fail-fast at schema parse time.
|
|
203
|
+
*/
|
|
204
|
+
linkBase: z.string().url().optional(),
|
|
205
|
+
});
|
|
96
206
|
/**
|
|
97
207
|
* Validate `Source.url` per kind.
|
|
98
208
|
*
|
|
@@ -137,6 +247,13 @@ export const SourceSchema = z
|
|
|
137
247
|
// existing source YAMLs (and `kind: html` ones) parse unchanged; the
|
|
138
248
|
// adapter applies defaults when the field is omitted entirely.
|
|
139
249
|
js: SourceJsOptionsSchema.optional(),
|
|
250
|
+
// `http` / `pagination` / `jsonSelectors` are consulted only by the
|
|
251
|
+
// `json-api` adapter (ADR-0012). Marked optional so existing source YAMLs
|
|
252
|
+
// and other kinds parse unchanged. The `jsonSelectors` name disambiguates
|
|
253
|
+
// from the css-selector `selectors` field that html / html-js use.
|
|
254
|
+
http: SourceHttpOptionsSchema.optional(),
|
|
255
|
+
pagination: SourcePaginationSchema.optional(),
|
|
256
|
+
jsonSelectors: SourceJsonApiSelectorsSchema.optional(),
|
|
140
257
|
// `trustLevel` defaults to `"untrusted"` so existing source YAMLs (which
|
|
141
258
|
// omit the field entirely) keep their current treatment. Per ADR-0009 M4
|
|
142
259
|
// this is schema-only; policy branches that read `trustLevel` arrive in a
|
|
@@ -158,5 +275,18 @@ export const SourceSchema = z
|
|
|
158
275
|
message: `selectors is required when kind is '${value.kind}'`,
|
|
159
276
|
});
|
|
160
277
|
}
|
|
278
|
+
if (value.kind === "json-api") {
|
|
279
|
+
// `jsonSelectors` is now optional — when omitted the adapter relies on
|
|
280
|
+
// its default selector chain (ADR-0012 §D2 / #174). Most "simple"
|
|
281
|
+
// page-based APIs work with just `pagination` set; complex shapes
|
|
282
|
+
// (AWS What's New, nested fields) still need explicit selectors.
|
|
283
|
+
if (value.pagination === undefined) {
|
|
284
|
+
ctx.addIssue({
|
|
285
|
+
code: "custom",
|
|
286
|
+
path: ["pagination"],
|
|
287
|
+
message: "pagination is required when kind is 'json-api'",
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
}
|
|
161
291
|
});
|
|
162
292
|
//# sourceMappingURL=source.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"source.js","sourceRoot":"","sources":["../../src/schemas/source.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,IAAI,CAAC;IACrC,KAAK;IACL,MAAM;IACN,SAAS;IACT,iBAAiB;IACjB,cAAc;
|
|
1
|
+
{"version":3,"file":"source.js","sourceRoot":"","sources":["../../src/schemas/source.ts"],"names":[],"mappings":"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"}
|
|
@@ -48,22 +48,50 @@ radar init --with-actions # .github/workflows/watch.yaml を生成
|
|
|
48
48
|
radar init --force # 既存ファイルを上書き
|
|
49
49
|
|
|
50
50
|
# 監視対象の管理
|
|
51
|
-
radar source add <id> --kind <rss|html|html-js|github-releases|npm-registry> --url <url> [options]
|
|
51
|
+
radar source add <id> --kind <rss|html|html-js|github-releases|npm-registry|json-feed|json-api> --url <url> [options]
|
|
52
52
|
radar source list
|
|
53
|
+
radar source recipes # バンドル recipe を一覧表示 (ADR-0012)
|
|
54
|
+
radar source add <id> --recipe <name> [--keywords ... --tags ... --name ...] # recipe ベースで 1 行追加
|
|
53
55
|
radar source test <id> [--limit N] [--show-content] # state/items を書き換えず取得 + フィルタを試す
|
|
54
56
|
radar source remove <id>
|
|
55
57
|
|
|
58
|
+
# JSON API recipe を pagination 付きで追加(ADR-0012)
|
|
59
|
+
radar source add aws-whats-new --kind json-api \
|
|
60
|
+
--url "https://aws.amazon.com/api/dirs/items/search?item.directoryId=whats-new&size=100&page=0" \
|
|
61
|
+
--keywords "Bedrock,Claude" \
|
|
62
|
+
--pagination-strategy page --page-size 100 --max-pages 200
|
|
63
|
+
|
|
64
|
+
# 同じことを bundled recipe で 1 行で
|
|
65
|
+
radar source add aws-watch --recipe aws-whats-new --keywords "Bedrock,Claude"
|
|
66
|
+
|
|
67
|
+
# JSON Feed (1.0 / 1.1) は URL のみで動く zero-config
|
|
68
|
+
radar source add example-microblog --kind json-feed \
|
|
69
|
+
--url https://example.micro.blog/feed.json \
|
|
70
|
+
--keywords "release"
|
|
71
|
+
|
|
56
72
|
# 監視実行 (新着検出 → items/*.yaml に detected で書く)
|
|
57
73
|
radar watch run
|
|
58
74
|
|
|
75
|
+
# 過去全履歴の一括取り込み (kind: json-api / github-releases / npm-registry)
|
|
76
|
+
radar watch run --source aws-whats-new --backfill --max-pages 200
|
|
77
|
+
|
|
59
78
|
# 検出済み item に対する操作
|
|
60
|
-
radar research <item-id> --agent <agent>
|
|
79
|
+
radar research <item-id> --agent <agent> [--verbose] # 調査レポートを生成 (status: detected -> researched)。--verbose で agent stdout を直接見る (ADR-0015)
|
|
61
80
|
radar research --digest <item-id> <item-id> ... [--agent <agent>] # 複数 item を 1 digest にまとめる (ADR-0011)
|
|
81
|
+
radar research --batch [--max-items N] [--filter-tags <list>] [--agent <agent>] # detected を一括 research (ADR-0014 D3a、--max-items 既定 10)
|
|
62
82
|
radar review <research-id> --agent <agent> # 既存レポートをレビュー (status: researched -> reviewed)
|
|
63
83
|
radar update <research-id> --agent <agent> # v+1 を生成 (item status は変えない)
|
|
64
84
|
radar dismiss <item-id> # LLM 不要、item を dismissed に
|
|
85
|
+
|
|
86
|
+
# GitHub Actions workflow の後追い生成 (ADR-0014)
|
|
87
|
+
radar workflow generate watch [--cron "<expr>"] [--agent <agent>] [--output <path>]
|
|
88
|
+
radar workflow generate combined [--watch-cron "<expr>"] [--max-items N] [--filter-tags <list>] [--agent <agent>] [--output <path>]
|
|
65
89
|
```
|
|
66
90
|
|
|
91
|
+
> **自動 research のコスト管理 (重要)**: `radar workflow generate combined` は watch → 自動 research を連鎖する workflow を生成し、`--max-items N` (既定 10) のハードキャップを YAML literal + CLI default の **二重防御**で焼き込む (ADR-0014 D3a)。`--max-items 100` のように大きい値を渡す前に必ず agent provider の billing alert を設定すること。暴走に気付いたら GitHub UI から workflow を `Disable workflow` で即停止する。詳細は `docs/user-guide.md` の「[`radar workflow generate`](https://github.com/ozzy-labs/feedradar/blob/main/docs/user-guide.md#radar-workflow-generate)」を参照。
|
|
92
|
+
>
|
|
93
|
+
> **進捗表示 (ADR-0015)**: `research` / `review` / `update` / `watch run --backfill` / html-js fetch / `source test` は stderr に phase markers + spinner + 副次メトリクス (`stdout` / `output` / `page x/N`) を出力する。`--verbose` で agent stdout を pass-through(デバッグ・「フリーズに見える」時の第一手)、`--quiet` または `RADAR_NO_PROGRESS=1` で完全に黙らせる。詳細は `docs/user-guide.md` の「[進捗表示 / verbose / quiet](https://github.com/ozzy-labs/feedradar/blob/main/docs/user-guide.md#進捗表示--verbose--quiet)」を参照。
|
|
94
|
+
|
|
67
95
|
`<agent>` の値: `claude-code` / `codex-cli` / `gemini-cli` / `copilot`
|
|
68
96
|
|
|
69
97
|
## 利用可能な slash commands (4 agent 共通)
|
|
@@ -145,7 +173,7 @@ agent の選択は CLI が強制せず、ユーザー判断です。
|
|
|
145
173
|
|
|
146
174
|
## セキュリティ警告 (untrusted external content)
|
|
147
175
|
|
|
148
|
-
`radar` が fetch する外部 feed (RSS / HTML / HTML (JS rendered, `kind: html-js`) / GitHub Releases / npm registry) のコンテンツは **untrusted** として扱われます ([ADR-0009](https://github.com/ozzy-labs/feedradar/blob/main/docs/adr/0009-untrusted-external-content-handling.md))。攻撃者が feed 内容に prompt injection を仕込む可能性があるため:
|
|
176
|
+
`radar` が fetch する外部 feed (RSS / HTML / HTML (JS rendered, `kind: html-js`) / GitHub Releases / npm registry / JSON Feed / JSON API) のコンテンツは **untrusted** として扱われます ([ADR-0009](https://github.com/ozzy-labs/feedradar/blob/main/docs/adr/0009-untrusted-external-content-handling.md))。攻撃者が feed 内容に prompt injection を仕込む可能性があるため:
|
|
149
177
|
|
|
150
178
|
- agent に渡すコンテンツは boundary marker で囲まれ、procedure 本体と分離される
|
|
151
179
|
- `sources/<id>.yaml` の `trustLevel` で `"trusted" | "untrusted"` を per-source で指定可能 (既定 `"untrusted"`)
|
|
@@ -24,7 +24,7 @@ radar watch run
|
|
|
24
24
|
# (c) あとは AI エージェントに頼む (次セクション)
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
`source add` と `watch run` は scheduler 連携を想定して CLI のままです。`--with-actions` / `--with-routines` を付けて init すれば、GitHub Actions / Claude Routines
|
|
27
|
+
`source add` と `watch run` は scheduler 連携を想定して CLI のままです。`--with-actions` / `--with-routines` を付けて init すれば、GitHub Actions / Claude Routines で定期実行する雛形が出ます。後から workflow を追加 / cadence 切替 / watch + 自動 research の連鎖が必要になったら `radar workflow generate watch | combined` で後追い生成できます ([ADR-0014](https://github.com/ozzy-labs/feedradar/blob/main/docs/adr/0014-workflow-generate-and-auto-research-safety.md))。
|
|
28
28
|
|
|
29
29
|
## 主要操作: エージェントに頼む
|
|
30
30
|
|
|
@@ -111,19 +111,34 @@ slash で直接呼ぶなら:
|
|
|
111
111
|
エージェントを起動しない自動化文脈では CLI を直接呼びます。`radar <subcommand> --help` で全コマンドのヘルプが出ます。
|
|
112
112
|
|
|
113
113
|
```bash
|
|
114
|
-
radar source add <id> --kind <rss|html|html-js|github-releases|npm-registry> --url <url> [options]
|
|
114
|
+
radar source add <id> --kind <rss|html|html-js|github-releases|npm-registry|json-feed|json-api> --url <url> [options]
|
|
115
|
+
radar source add <id> --recipe <name> [--keywords ... --tags ... --name ...] # バンドル recipe で 1 行追加 (ADR-0012)
|
|
115
116
|
radar source list
|
|
117
|
+
radar source recipes # バンドル recipe を一覧表示
|
|
116
118
|
radar source test <id> [--limit N] [--show-content]
|
|
117
119
|
radar source remove <id>
|
|
118
|
-
radar watch run [--source <id>] [--bootstrap]
|
|
119
|
-
radar research <item-id> --agent <agent>
|
|
120
|
+
radar watch run [--source <id>] [--bootstrap | --backfill [--max-pages N]] [-v|--verbose | -q|--quiet]
|
|
121
|
+
radar research <item-id> --agent <agent> [--verbose | --quiet] # 進捗表示・stdout pass-through は --verbose で有効化 (ADR-0015)
|
|
120
122
|
radar research --digest <item-id> <item-id> ... [--agent <agent>] # 複数 item を 1 digest にまとめる (ADR-0011)
|
|
121
|
-
radar review <research-id> --agent <agent>
|
|
122
|
-
radar update <research-id> --agent <agent>
|
|
123
|
+
radar review <research-id> --agent <agent> [--verbose | --quiet]
|
|
124
|
+
radar update <research-id> --agent <agent> [--verbose | --quiet]
|
|
123
125
|
radar dismiss <item-id>
|
|
126
|
+
radar research --batch [--max-items N] [--filter-tags <list>] [--agent <agent>] [--verbose | --quiet] # detected を一括 research (ADR-0014)
|
|
127
|
+
radar workflow generate watch [--cron "<expr>"] [--agent <agent>] [--output <path>] # GitHub Actions watch 雛形を後追い生成 (ADR-0014)
|
|
128
|
+
radar workflow generate combined [--watch-cron "<expr>"] [--max-items N] [--filter-tags <list>] [--agent <agent>] [--output <path>] # watch + 自動 research を --max-items ハードキャップ付きで生成 (ADR-0014)
|
|
124
129
|
```
|
|
125
130
|
|
|
126
|
-
|
|
131
|
+
JSON API は recipe ベースで、`kind: json-api` を選んで `pagination` を YAML に書く([ADR-0012](https://github.com/ozzy-labs/feedradar/blob/main/docs/adr/0012-json-api-adapter-and-recipe-strategy.md))。JSON Feed 1.0 / 1.1 標準に準拠したサイトは URL だけで動く zero-config kind (`kind: json-feed`)。過去の全件取り込みは `radar watch run --backfill` を使う (kind: json-api / github-releases / npm-registry 対応)。
|
|
132
|
+
|
|
133
|
+
長時間実行コマンド (`research` / `review` / `update` / `watch run --backfill` / html-js fetch / `source test`) は stderr に phase markers + spinner + 副次メトリクス (`stdout` / `output` / `page x/N`) を表示します([ADR-0015](https://github.com/ozzy-labs/feedradar/blob/main/docs/adr/0015-progress-reporting-ux.md))。挙動切替は env > flag > TTY auto-detect の優先順:
|
|
134
|
+
|
|
135
|
+
- `--verbose`(または `-v`): agent CLI / Playwright の stdout/stderr を pass-through。デバッグや「フリーズに見える」ときの第一手
|
|
136
|
+
- `--quiet`(または `-q`): reporter を完全に黙らせ、CLI の従来 1 行ログだけ残す
|
|
137
|
+
- `RADAR_NO_PROGRESS=1`(env): 上記より強い escape hatch。CI script で flag を消さずに reporter だけ off にしたいケース向け
|
|
138
|
+
|
|
139
|
+
詳細・トラブルシュート(`Agent running [mm:ss]` で動いていないように見える時の対処等)は [docs/user-guide.md → 進捗表示 / verbose / quiet](https://github.com/ozzy-labs/feedradar/blob/main/docs/user-guide.md#進捗表示--verbose--quiet) を参照。
|
|
140
|
+
|
|
141
|
+
定期実行の雛形 (GitHub Actions / Claude Routines) は `radar init --with-actions` / `--with-routines` で初回 bootstrap として生成できます。後追いで cadence 切替 / 複数 workflow 共存 / `combined` (watch + 自動 research) を追加したい場合は `radar workflow generate <type>` ([ADR-0014](https://github.com/ozzy-labs/feedradar/blob/main/docs/adr/0014-workflow-generate-and-auto-research-safety.md)) を使います。`combined` は `--max-items` ハードキャップを YAML literal + CLI default の二重防御で焼き込むため、暴走 feed (publisher 側 bug / `--backfill` 事故) による LLM cost 爆発を設計レベルで遮断します。
|
|
127
142
|
|
|
128
143
|
## このディレクトリのレイアウト
|
|
129
144
|
|
|
@@ -154,7 +169,7 @@ radar dismiss <item-id>
|
|
|
154
169
|
|
|
155
170
|
## セキュリティ警告
|
|
156
171
|
|
|
157
|
-
FeedRadar が fetch する外部 feed (RSS / HTML / HTML (JS rendered, `kind: html-js`) / GitHub Releases / npm registry) は **untrusted** として扱われます ([ADR-0009](https://github.com/ozzy-labs/feedradar/blob/main/docs/adr/0009-untrusted-external-content-handling.md))。攻撃者が feed 内容に prompt injection を仕込む可能性があるため:
|
|
172
|
+
FeedRadar が fetch する外部 feed (RSS / HTML / HTML (JS rendered, `kind: html-js`) / GitHub Releases / npm registry / JSON Feed / JSON API) は **untrusted** として扱われます ([ADR-0009](https://github.com/ozzy-labs/feedradar/blob/main/docs/adr/0009-untrusted-external-content-handling.md))。攻撃者が feed 内容に prompt injection を仕込む可能性があるため:
|
|
158
173
|
|
|
159
174
|
- 信頼できる公式 source のみ登録するのが第一の防御線
|
|
160
175
|
- `sources/<id>.yaml` の `trustLevel: trusted` で個別 opt-in 可 (既定 `untrusted`)
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# `radar workflow generate combined` template (ADR-0014 D2 / D3 / D4 / D5).
|
|
2
|
+
#
|
|
3
|
+
# Chains `radar watch run` -> "skip if no new items" guard -> `radar research
|
|
4
|
+
# --batch` -> `git commit/push --rebase` retry inside a single job so the
|
|
5
|
+
# detection-to-research delay collapses to one cron tick instead of two
|
|
6
|
+
# stacked workflows.
|
|
7
|
+
#
|
|
8
|
+
# Placeholders rendered by `src/cli/workflow/generate-combined.ts`:
|
|
9
|
+
# {{cron}} — schedule cron expression (default "0 0 * * *")
|
|
10
|
+
# {{maxItems}} — `--max-items` hard cap (ADR-0014 D3a; default 10)
|
|
11
|
+
# {{filterTags}} — `--filter-tags` arg as a single CLI literal (empty when
|
|
12
|
+
# filtering is off so the line collapses to bare `--batch`)
|
|
13
|
+
# {{agent}} — agent id literal (claude-code|codex-cli|gemini-cli|copilot)
|
|
14
|
+
# {{secretsBlock}} — agent-specific `env:` body (no shared default; the
|
|
15
|
+
# CLI generator selects one of four prebuilt fragments,
|
|
16
|
+
# never injecting OAuth tokens per ADR-0014 D5)
|
|
17
|
+
#
|
|
18
|
+
# Hard-cap rationale: this YAML embeds `--max-items {{maxItems}}` as a literal
|
|
19
|
+
# so a workflow audit shows the cap without needing to re-read CLI source.
|
|
20
|
+
# The CLI re-enforces the cap (`RESEARCH_BATCH_DEFAULT_MAX_ITEMS` in
|
|
21
|
+
# `src/cli/research.ts`) so even hand-edited YAML cannot blow it inside one
|
|
22
|
+
# invocation (ADR-0014 D3a 二重防御).
|
|
23
|
+
|
|
24
|
+
name: feedradar-combined
|
|
25
|
+
|
|
26
|
+
on:
|
|
27
|
+
schedule:
|
|
28
|
+
- cron: "{{cron}}"
|
|
29
|
+
workflow_dispatch: {}
|
|
30
|
+
|
|
31
|
+
permissions:
|
|
32
|
+
contents: write
|
|
33
|
+
|
|
34
|
+
concurrency:
|
|
35
|
+
# Type-scoped concurrency group: watch-only and combined workflows must not
|
|
36
|
+
# serialize each other (different cadence, different scope), so each type
|
|
37
|
+
# has its own `feedradar-<type>-${{ github.ref }}` group.
|
|
38
|
+
group: feedradar-combined-${{ github.ref }}
|
|
39
|
+
cancel-in-progress: false
|
|
40
|
+
|
|
41
|
+
jobs:
|
|
42
|
+
combined:
|
|
43
|
+
runs-on: ubuntu-latest
|
|
44
|
+
timeout-minutes: 30
|
|
45
|
+
steps:
|
|
46
|
+
- name: Checkout workspace
|
|
47
|
+
uses: actions/checkout@v4
|
|
48
|
+
with:
|
|
49
|
+
fetch-depth: 0
|
|
50
|
+
persist-credentials: true
|
|
51
|
+
|
|
52
|
+
- name: Set up Node.js
|
|
53
|
+
uses: actions/setup-node@v4
|
|
54
|
+
with:
|
|
55
|
+
node-version: "22.21"
|
|
56
|
+
|
|
57
|
+
- name: Install FeedRadar
|
|
58
|
+
run: npm install -g @ozzylabs/feedradar
|
|
59
|
+
|
|
60
|
+
- name: Run watch
|
|
61
|
+
env:
|
|
62
|
+
{{secretsBlock}}
|
|
63
|
+
run: radar watch run
|
|
64
|
+
|
|
65
|
+
- name: Skip research when no new items
|
|
66
|
+
id: detect_changes
|
|
67
|
+
# ADR-0014: skip the research step entirely when `watch run` produced
|
|
68
|
+
# no new items. Otherwise a runaway-detection cap would still burn a
|
|
69
|
+
# full `radar research --batch` invocation (template load, item walk)
|
|
70
|
+
# on a fresh-empty queue.
|
|
71
|
+
run: |
|
|
72
|
+
if [ -z "$(git status --porcelain items/)" ]; then
|
|
73
|
+
echo "no new items in items/; skipping research step"
|
|
74
|
+
echo "has_changes=false" >> "$GITHUB_OUTPUT"
|
|
75
|
+
else
|
|
76
|
+
echo "has_changes=true" >> "$GITHUB_OUTPUT"
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
- name: Run research on detected items (capped at {{maxItems}}, agent={{agent}})
|
|
80
|
+
if: steps.detect_changes.outputs.has_changes == 'true'
|
|
81
|
+
env:
|
|
82
|
+
{{secretsBlock}}
|
|
83
|
+
# `--batch` walks items/ for status=detected, applies the filter-tags
|
|
84
|
+
# allow-list, and stops once `--max-items` reports are written. The CLI
|
|
85
|
+
# re-enforces the cap so a hand-edited YAML cannot exceed it.
|
|
86
|
+
run: radar research --batch --status detected --max-items {{maxItems}}{{filterTags}} --agent {{agent}}
|
|
87
|
+
|
|
88
|
+
- name: Commit and push with retry
|
|
89
|
+
if: steps.detect_changes.outputs.has_changes == 'true'
|
|
90
|
+
# ADR-0014 D4: three-attempt push with `git pull --rebase --autostash`
|
|
91
|
+
# between failures. Tuned for two concurrent feedradar workflows (e.g.
|
|
92
|
+
# watch-hourly + combined-weekly) racing on items/ / state/ / research/.
|
|
93
|
+
run: |
|
|
94
|
+
git config user.name "feedradar-bot"
|
|
95
|
+
git config user.email "feedradar-bot@users.noreply.github.com"
|
|
96
|
+
git add items/ state/ research/
|
|
97
|
+
if git diff --cached --quiet; then
|
|
98
|
+
echo "nothing staged; exiting cleanly"
|
|
99
|
+
exit 0
|
|
100
|
+
fi
|
|
101
|
+
git commit -m "chore(feedradar): combined watch + research $(date -u +%Y-%m-%d)"
|
|
102
|
+
for attempt in 1 2 3; do
|
|
103
|
+
if git push origin "${GITHUB_REF_NAME}"; then
|
|
104
|
+
exit 0
|
|
105
|
+
fi
|
|
106
|
+
echo "push failed (attempt ${attempt}/3), rebasing..."
|
|
107
|
+
git pull --rebase --autostash origin "${GITHUB_REF_NAME}"
|
|
108
|
+
done
|
|
109
|
+
echo "push failed after 3 attempts" >&2
|
|
110
|
+
exit 1
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# GitHub Actions scaffold generated by `radar workflow generate watch`.
|
|
2
|
+
# Edit the cron schedule, sources, and commit message to match your workflow.
|
|
3
|
+
# Auth policy: API key only (ADR-0004 / ADR-0014). The Claude Code OAuth token
|
|
4
|
+
# is forbidden for unattended workflows per Anthropic's usage policy.
|
|
5
|
+
#
|
|
6
|
+
# This template is the placeholder-driven, post-init regeneration variant of
|
|
7
|
+
# `src/templates/workflows/watch.yaml`. The latter is emitted by
|
|
8
|
+
# `radar init --with-actions` for first-time workspace bootstrap and is
|
|
9
|
+
# preserved verbatim for backward compatibility (ADR-0014 D1). Differences:
|
|
10
|
+
#
|
|
11
|
+
# - Cron schedule, output path, and agent secret name are substituted by
|
|
12
|
+
# `generate-watch.ts` from CLI flags before the file is written.
|
|
13
|
+
# - `concurrency.group` is scoped to `feedradar-watch-` so multiple workflow
|
|
14
|
+
# types (watch / combined) can run side by side without cancelling each
|
|
15
|
+
# other; ADR-0014 D4 push-conflict mitigation pairs with the rebase retry
|
|
16
|
+
# below.
|
|
17
|
+
# - `Commit and push with retry` step has up to 3 `git pull --rebase`
|
|
18
|
+
# retries to recover from concurrent cron pushes (ADR-0014 D4).
|
|
19
|
+
|
|
20
|
+
name: feedradar-watch
|
|
21
|
+
|
|
22
|
+
on:
|
|
23
|
+
schedule:
|
|
24
|
+
- cron: "{{cron}}"
|
|
25
|
+
workflow_dispatch: {}
|
|
26
|
+
|
|
27
|
+
permissions:
|
|
28
|
+
# Required to commit detected items / state back to the workspace branch.
|
|
29
|
+
contents: write
|
|
30
|
+
|
|
31
|
+
concurrency:
|
|
32
|
+
# Per-type group so `watch` and `combined` workflows don't cancel each other.
|
|
33
|
+
# Same-type concurrent firings still serialize via this group.
|
|
34
|
+
group: feedradar-watch-${{ github.ref }}
|
|
35
|
+
cancel-in-progress: false
|
|
36
|
+
|
|
37
|
+
jobs:
|
|
38
|
+
watch:
|
|
39
|
+
runs-on: ubuntu-latest
|
|
40
|
+
timeout-minutes: 15
|
|
41
|
+
steps:
|
|
42
|
+
- name: Checkout workspace
|
|
43
|
+
uses: actions/checkout@v4
|
|
44
|
+
with:
|
|
45
|
+
# Need history so we can rebase on top of concurrent pushes.
|
|
46
|
+
fetch-depth: 0
|
|
47
|
+
persist-credentials: true
|
|
48
|
+
|
|
49
|
+
- name: Set up Node.js
|
|
50
|
+
uses: actions/setup-node@v4
|
|
51
|
+
with:
|
|
52
|
+
# Node 22.21+ (or 24.5+) is required so radar can auto-detect
|
|
53
|
+
# HTTPS_PROXY / HTTP_PROXY and respawn with --use-env-proxy.
|
|
54
|
+
node-version: "22.21"
|
|
55
|
+
|
|
56
|
+
- name: Install FeedRadar
|
|
57
|
+
# Pin to a release once you've decided on a version; this scaffold
|
|
58
|
+
# installs the latest published build.
|
|
59
|
+
run: npm install -g @ozzylabs/feedradar
|
|
60
|
+
|
|
61
|
+
- name: Run watch
|
|
62
|
+
env:
|
|
63
|
+
# Authenticate against the agent API per ADR-0004 / ADR-0014 D5.
|
|
64
|
+
# The secret name below follows the per-agent convention; see the
|
|
65
|
+
# post-generation stdout for the exact secret you must add.
|
|
66
|
+
{{agentEnvKey}}: ${{ secrets.{{agentEnvKey}} }}
|
|
67
|
+
# Raises GitHub REST API rate limit from 60 → 5000 req/h for the
|
|
68
|
+
# github-releases adapter (ADR-0002 / Phase 3).
|
|
69
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
70
|
+
run: radar watch run
|
|
71
|
+
|
|
72
|
+
- name: Commit and push with retry
|
|
73
|
+
# Persist updates to items/ and state/ so the next scheduled run can
|
|
74
|
+
# diff against the previous lastSeenIds. Routines / Actions both
|
|
75
|
+
# fresh-clone, so state must live in git.
|
|
76
|
+
#
|
|
77
|
+
# Push conflict mitigation (ADR-0014 D4): if another workflow (e.g.
|
|
78
|
+
# combined.yaml) pushed concurrently, `git push` fails with
|
|
79
|
+
# non-fast-forward. We retry up to 3 times, rebasing on each attempt;
|
|
80
|
+
# autostash keeps any unindexed bot-side changes safe across the
|
|
81
|
+
# rebase. 4+ attempts indicate a structural problem (branch
|
|
82
|
+
# protection, token failure, true merge conflict) so we fail fast
|
|
83
|
+
# instead of retrying further.
|
|
84
|
+
run: |
|
|
85
|
+
set -euo pipefail
|
|
86
|
+
git config user.name "github-actions[bot]"
|
|
87
|
+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
88
|
+
if git diff --quiet items/ state/; then
|
|
89
|
+
echo "no changes detected; skipping commit"
|
|
90
|
+
exit 0
|
|
91
|
+
fi
|
|
92
|
+
git add items/ state/
|
|
93
|
+
git commit -m "chore(watch): detected items $(date -u +%Y-%m-%d)"
|
|
94
|
+
for attempt in 1 2 3; do
|
|
95
|
+
if git push origin "${GITHUB_REF_NAME}"; then
|
|
96
|
+
echo "push succeeded on attempt ${attempt}"
|
|
97
|
+
exit 0
|
|
98
|
+
fi
|
|
99
|
+
echo "push failed (attempt ${attempt}/3), rebasing..."
|
|
100
|
+
git pull --rebase --autostash origin "${GITHUB_REF_NAME}"
|
|
101
|
+
done
|
|
102
|
+
echo "push failed after 3 attempts" >&2
|
|
103
|
+
exit 1
|
|
@@ -36,7 +36,11 @@ jobs:
|
|
|
36
36
|
- name: Set up Node.js
|
|
37
37
|
uses: actions/setup-node@v4
|
|
38
38
|
with:
|
|
39
|
-
|
|
39
|
+
# Node 22.21+ (or 24.5+) is required so radar can auto-detect
|
|
40
|
+
# HTTPS_PROXY / HTTP_PROXY and respawn with --use-env-proxy.
|
|
41
|
+
# Older 22.x lacks the flag and `radar` runs without proxy
|
|
42
|
+
# support even when HTTPS_PROXY is set.
|
|
43
|
+
node-version: "22.21"
|
|
40
44
|
|
|
41
45
|
- name: Install FeedRadar
|
|
42
46
|
# Pin to a release once you've decided on a version; this scaffold
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ozzylabs/feedradar",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Multi-agent CLI that watches blogs and release feeds, then turns keyword hits into Markdown research reports",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
},
|
|
9
9
|
"files": [
|
|
10
10
|
"dist",
|
|
11
|
-
"dist/skills",
|
|
12
11
|
"LICENSE",
|
|
13
12
|
"README.md"
|
|
14
13
|
],
|
|
@@ -78,6 +77,6 @@
|
|
|
78
77
|
],
|
|
79
78
|
"author": "ozzy-labs",
|
|
80
79
|
"engines": {
|
|
81
|
-
"node": ">=22"
|
|
80
|
+
"node": ">=22.21.0 || >=24.5.0"
|
|
82
81
|
}
|
|
83
82
|
}
|