@ozzylabs/feedradar 0.1.0
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/LICENSE +21 -0
- package/README.md +104 -0
- package/dist/agents/_boundary.d.ts +44 -0
- package/dist/agents/_boundary.d.ts.map +1 -0
- package/dist/agents/_boundary.js +59 -0
- package/dist/agents/_boundary.js.map +1 -0
- package/dist/agents/claude-code.d.ts +32 -0
- package/dist/agents/claude-code.d.ts.map +1 -0
- package/dist/agents/claude-code.js +256 -0
- package/dist/agents/claude-code.js.map +1 -0
- package/dist/agents/codex-cli.d.ts +31 -0
- package/dist/agents/codex-cli.d.ts.map +1 -0
- package/dist/agents/codex-cli.js +303 -0
- package/dist/agents/codex-cli.js.map +1 -0
- package/dist/agents/copilot.d.ts +29 -0
- package/dist/agents/copilot.d.ts.map +1 -0
- package/dist/agents/copilot.js +282 -0
- package/dist/agents/copilot.js.map +1 -0
- package/dist/agents/gemini-cli.d.ts +30 -0
- package/dist/agents/gemini-cli.d.ts.map +1 -0
- package/dist/agents/gemini-cli.js +316 -0
- package/dist/agents/gemini-cli.js.map +1 -0
- package/dist/agents/index.d.ts +12 -0
- package/dist/agents/index.d.ts.map +1 -0
- package/dist/agents/index.js +33 -0
- package/dist/agents/index.js.map +1 -0
- package/dist/agents/types.d.ts +103 -0
- package/dist/agents/types.d.ts.map +1 -0
- package/dist/agents/types.js +2 -0
- package/dist/agents/types.js.map +1 -0
- package/dist/claude-skills/dismiss/SKILL.md +41 -0
- package/dist/claude-skills/research/SKILL.md +45 -0
- package/dist/claude-skills/review/SKILL.md +45 -0
- package/dist/claude-skills/update/SKILL.md +49 -0
- package/dist/cli/dismiss.d.ts +28 -0
- package/dist/cli/dismiss.d.ts.map +1 -0
- package/dist/cli/dismiss.js +122 -0
- package/dist/cli/dismiss.js.map +1 -0
- package/dist/cli/index.d.ts +7 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +64 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init.d.ts +148 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +578 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/research.d.ts +30 -0
- package/dist/cli/research.d.ts.map +1 -0
- package/dist/cli/research.js +313 -0
- package/dist/cli/research.js.map +1 -0
- package/dist/cli/review.d.ts +34 -0
- package/dist/cli/review.d.ts.map +1 -0
- package/dist/cli/review.js +418 -0
- package/dist/cli/review.js.map +1 -0
- package/dist/cli/source.d.ts +57 -0
- package/dist/cli/source.d.ts.map +1 -0
- package/dist/cli/source.js +511 -0
- package/dist/cli/source.js.map +1 -0
- package/dist/cli/update.d.ts +43 -0
- package/dist/cli/update.d.ts.map +1 -0
- package/dist/cli/update.js +429 -0
- package/dist/cli/update.js.map +1 -0
- package/dist/cli/watch.d.ts +22 -0
- package/dist/cli/watch.d.ts.map +1 -0
- package/dist/cli/watch.js +101 -0
- package/dist/cli/watch.js.map +1 -0
- package/dist/core/config.d.ts +60 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +101 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/feeds/derive-id.d.ts +43 -0
- package/dist/core/feeds/derive-id.d.ts.map +1 -0
- package/dist/core/feeds/derive-id.js +66 -0
- package/dist/core/feeds/derive-id.js.map +1 -0
- package/dist/core/feeds/github-api.d.ts +69 -0
- package/dist/core/feeds/github-api.d.ts.map +1 -0
- package/dist/core/feeds/github-api.js +161 -0
- package/dist/core/feeds/github-api.js.map +1 -0
- package/dist/core/feeds/github-releases.d.ts +3 -0
- package/dist/core/feeds/github-releases.d.ts.map +1 -0
- package/dist/core/feeds/github-releases.js +85 -0
- package/dist/core/feeds/github-releases.js.map +1 -0
- package/dist/core/feeds/html.d.ts +10 -0
- package/dist/core/feeds/html.d.ts.map +1 -0
- package/dist/core/feeds/html.js +263 -0
- package/dist/core/feeds/html.js.map +1 -0
- package/dist/core/feeds/index.d.ts +5 -0
- package/dist/core/feeds/index.d.ts.map +1 -0
- package/dist/core/feeds/index.js +18 -0
- package/dist/core/feeds/index.js.map +1 -0
- package/dist/core/feeds/npm-registry.d.ts +36 -0
- package/dist/core/feeds/npm-registry.d.ts.map +1 -0
- package/dist/core/feeds/npm-registry.js +200 -0
- package/dist/core/feeds/npm-registry.js.map +1 -0
- package/dist/core/feeds/rss.d.ts +12 -0
- package/dist/core/feeds/rss.d.ts.map +1 -0
- package/dist/core/feeds/rss.js +222 -0
- package/dist/core/feeds/rss.js.map +1 -0
- package/dist/core/feeds/types.d.ts +45 -0
- package/dist/core/feeds/types.d.ts.map +1 -0
- package/dist/core/feeds/types.js +2 -0
- package/dist/core/feeds/types.js.map +1 -0
- package/dist/core/filter.d.ts +25 -0
- package/dist/core/filter.d.ts.map +1 -0
- package/dist/core/filter.js +123 -0
- package/dist/core/filter.js.map +1 -0
- package/dist/core/injection-detector.d.ts +57 -0
- package/dist/core/injection-detector.d.ts.map +1 -0
- package/dist/core/injection-detector.js +109 -0
- package/dist/core/injection-detector.js.map +1 -0
- package/dist/core/items.d.ts +20 -0
- package/dist/core/items.d.ts.map +1 -0
- package/dist/core/items.js +105 -0
- package/dist/core/items.js.map +1 -0
- package/dist/core/state.d.ts +12 -0
- package/dist/core/state.d.ts.map +1 -0
- package/dist/core/state.js +42 -0
- package/dist/core/state.js.map +1 -0
- package/dist/core/templates.d.ts +21 -0
- package/dist/core/templates.d.ts.map +1 -0
- package/dist/core/templates.js +52 -0
- package/dist/core/templates.js.map +1 -0
- package/dist/core/watcher.d.ts +72 -0
- package/dist/core/watcher.d.ts.map +1 -0
- package/dist/core/watcher.js +240 -0
- package/dist/core/watcher.js.map +1 -0
- package/dist/gemini-commands/dismiss.toml +2 -0
- package/dist/gemini-commands/research.toml +2 -0
- package/dist/gemini-commands/review.toml +2 -0
- package/dist/gemini-commands/update.toml +2 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/schemas/config.d.ts +39 -0
- package/dist/schemas/config.d.ts.map +1 -0
- package/dist/schemas/config.js +23 -0
- package/dist/schemas/config.js.map +1 -0
- package/dist/schemas/index.d.ts +6 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +6 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/schemas/item.d.ts +38 -0
- package/dist/schemas/item.d.ts.map +1 -0
- package/dist/schemas/item.js +34 -0
- package/dist/schemas/item.js.map +1 -0
- package/dist/schemas/research.d.ts +82 -0
- package/dist/schemas/research.d.ts.map +1 -0
- package/dist/schemas/research.js +45 -0
- package/dist/schemas/research.js.map +1 -0
- package/dist/schemas/source.d.ts +139 -0
- package/dist/schemas/source.d.ts.map +1 -0
- package/dist/schemas/source.js +127 -0
- package/dist/schemas/source.js.map +1 -0
- package/dist/schemas/state.d.ts +19 -0
- package/dist/schemas/state.d.ts.map +1 -0
- package/dist/schemas/state.js +12 -0
- package/dist/schemas/state.js.map +1 -0
- package/dist/skills/research/SKILL.md +156 -0
- package/dist/skills/review/SKILL.md +173 -0
- package/dist/skills/update/SKILL.md +200 -0
- package/dist/templates/agents/AGENTS.md +161 -0
- package/dist/templates/claude/CLAUDE.md +5 -0
- package/dist/templates/default.md +16 -0
- package/dist/templates/feedradar.md +165 -0
- package/dist/templates/routines/watch-daily.md +42 -0
- package/dist/templates/workflows/watch.yaml +70 -0
- package/package.json +73 -0
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
import { access, readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import matter from "gray-matter";
|
|
4
|
+
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
5
|
+
/**
|
|
6
|
+
* gray-matter defaults to js-yaml, which auto-converts ISO 8601 strings to
|
|
7
|
+
* Date objects per the YAML 1.1 timestamp tag. That breaks
|
|
8
|
+
* `ResearchFrontmatterSchema`, which expects `createdAt` / `updatedAt` to be
|
|
9
|
+
* strings (ADR-0003). Swap in the `yaml` v2 engine (already a dep of this
|
|
10
|
+
* package) which keeps quoted/unquoted ISO 8601 as a plain string.
|
|
11
|
+
*/
|
|
12
|
+
const matterOptions = {
|
|
13
|
+
engines: {
|
|
14
|
+
yaml: {
|
|
15
|
+
parse: (s) => parseYaml(s),
|
|
16
|
+
stringify: (data) => stringifyYaml(data),
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
import { getAgentAdapter } from "../agents/index.js";
|
|
21
|
+
import { getDefaultAgent, loadRadarConfig, RadarConfigError } from "../core/config.js";
|
|
22
|
+
import { loadItems, saveItems } from "../core/items.js";
|
|
23
|
+
import { loadTemplate } from "../core/templates.js";
|
|
24
|
+
import { AgentIdSchema, ResearchFrontmatterSchema } from "../schemas/index.js";
|
|
25
|
+
function parseArgs(args) {
|
|
26
|
+
const out = {};
|
|
27
|
+
for (let i = 0; i < args.length; i++) {
|
|
28
|
+
const a = args[i];
|
|
29
|
+
if (a === "-h" || a === "--help") {
|
|
30
|
+
out.help = true;
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
if (a === "--agent") {
|
|
34
|
+
out.agent = args[++i];
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
if (a === "--template") {
|
|
38
|
+
out.template = args[++i];
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (a?.startsWith("--")) {
|
|
42
|
+
throw new Error(`unknown option: ${a}`);
|
|
43
|
+
}
|
|
44
|
+
if (!out.itemId) {
|
|
45
|
+
out.itemId = a;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
throw new Error(`unexpected positional argument: ${a}`);
|
|
49
|
+
}
|
|
50
|
+
return out;
|
|
51
|
+
}
|
|
52
|
+
function printHelp(log) {
|
|
53
|
+
log("Usage: radar research <item-id> [--agent <agent-id>] [--template <template-id>]");
|
|
54
|
+
log("");
|
|
55
|
+
log("Arguments:");
|
|
56
|
+
log(" <item-id> Item id (matches items/<sourceId>/<item-id>.yaml)");
|
|
57
|
+
log("");
|
|
58
|
+
log("Options:");
|
|
59
|
+
log(" --agent <agent-id> claude-code | codex-cli | gemini-cli | copilot (default: claude-code)");
|
|
60
|
+
log(" --template <id> Template id under templates/ (default: default)");
|
|
61
|
+
log("");
|
|
62
|
+
log("Writes research/<YYYYMMDD>_<slug>_v1.md (ADR-0003).");
|
|
63
|
+
}
|
|
64
|
+
async function pathExists(p) {
|
|
65
|
+
try {
|
|
66
|
+
await access(p);
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Slug an Item into the `<sourceId>-<short-slug>` form used by the research
|
|
75
|
+
* filename (`research/<YYYYMMDD>_<slug>_v1.md`).
|
|
76
|
+
*
|
|
77
|
+
* Falls back to the item id when the title is empty/unicode-only. We trim to
|
|
78
|
+
* 60 chars so the resulting filename stays inside typical filesystem limits
|
|
79
|
+
* after adding date prefix and version suffix.
|
|
80
|
+
*/
|
|
81
|
+
function buildSlug(item) {
|
|
82
|
+
const baseSource = item.sourceId.toLowerCase().replace(/[^a-z0-9]+/g, "-");
|
|
83
|
+
const titleSlug = item.title
|
|
84
|
+
.toLowerCase()
|
|
85
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
86
|
+
.replace(/^-+|-+$/g, "")
|
|
87
|
+
.slice(0, 60);
|
|
88
|
+
const tail = titleSlug ||
|
|
89
|
+
item.id
|
|
90
|
+
.toLowerCase()
|
|
91
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
92
|
+
.slice(0, 60);
|
|
93
|
+
return `${baseSource}-${tail}`;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Pick `YYYYMMDD` from the item's `publishedAt`, falling back to today (UTC)
|
|
97
|
+
* when the source feed did not provide a publish date.
|
|
98
|
+
*/
|
|
99
|
+
function buildDatePrefix(item, now) {
|
|
100
|
+
const iso = item.publishedAt ?? now.toISOString();
|
|
101
|
+
return iso.slice(0, 10).replace(/-/g, "");
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Locate `items/<sourceId>/<item-id>.yaml` across all source directories,
|
|
105
|
+
* since the CLI only takes `<item-id>` (sourceId is not on the command line).
|
|
106
|
+
*
|
|
107
|
+
* `loadItems` already walks every source subdir, so we delegate to it and
|
|
108
|
+
* then match by id. Returning the full Item (rather than just the path) lets
|
|
109
|
+
* the caller compute slug / date without a second read.
|
|
110
|
+
*/
|
|
111
|
+
async function findItem(cwd, itemId) {
|
|
112
|
+
const itemsDir = join(cwd, "items");
|
|
113
|
+
if (!(await pathExists(itemsDir)))
|
|
114
|
+
return null;
|
|
115
|
+
const items = await loadItems(itemsDir);
|
|
116
|
+
const match = items.find((i) => i.id === itemId);
|
|
117
|
+
if (!match)
|
|
118
|
+
return null;
|
|
119
|
+
return { item: match };
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Implementation of `radar research <item-id>`.
|
|
123
|
+
*
|
|
124
|
+
* High-level flow (Phase 1):
|
|
125
|
+
* 1. Parse + validate args (agent defaults to `claude-code`, template to `default`).
|
|
126
|
+
* 2. Locate `items/<sourceId>/<item-id>.yaml` and parse it.
|
|
127
|
+
* 3. Load `templates/<template-id>.md` (empty body when default is absent).
|
|
128
|
+
* 4. Compute `research/<YYYYMMDD>_<slug>_v1.md`; refuse to overwrite an
|
|
129
|
+
* existing file (re-runs go through `update` per ADR-0003).
|
|
130
|
+
* 5. Invoke the registered agent adapter; the agent writes the report.
|
|
131
|
+
* 6. Validate the report's frontmatter against `ResearchFrontmatterSchema`.
|
|
132
|
+
* 7. Transition the item: `status` → `researched` and persist.
|
|
133
|
+
*
|
|
134
|
+
* Any step from 4 onward that fails surfaces a non-zero exit code with a
|
|
135
|
+
* targeted message so the user can debug without re-reading the source.
|
|
136
|
+
*/
|
|
137
|
+
export async function runResearch(args, options = {}) {
|
|
138
|
+
const cwd = options.cwd ?? process.cwd();
|
|
139
|
+
const log = options.io?.log ?? ((m) => console.log(m));
|
|
140
|
+
const warn = options.io?.warn ?? ((m) => console.warn(m));
|
|
141
|
+
const error = options.io?.error ?? ((m) => console.error(m));
|
|
142
|
+
let parsed;
|
|
143
|
+
try {
|
|
144
|
+
parsed = parseArgs(args);
|
|
145
|
+
}
|
|
146
|
+
catch (e) {
|
|
147
|
+
error(`research: ${e instanceof Error ? e.message : String(e)}`);
|
|
148
|
+
return 2;
|
|
149
|
+
}
|
|
150
|
+
if (parsed.help) {
|
|
151
|
+
printHelp(log);
|
|
152
|
+
return 0;
|
|
153
|
+
}
|
|
154
|
+
if (!parsed.itemId) {
|
|
155
|
+
error("research: missing <item-id>");
|
|
156
|
+
printHelp(error);
|
|
157
|
+
return 2;
|
|
158
|
+
}
|
|
159
|
+
// Resolve the agent honoring the priority chain:
|
|
160
|
+
// explicit --agent > radar.config.yaml defaultResearchAgent > "claude-code"
|
|
161
|
+
// The explicit value is validated against AgentIdSchema first so a bogus
|
|
162
|
+
// --agent never reaches the config / fallback path.
|
|
163
|
+
let explicitAgent;
|
|
164
|
+
if (parsed.agent !== undefined) {
|
|
165
|
+
const agentResult = AgentIdSchema.safeParse(parsed.agent);
|
|
166
|
+
if (!agentResult.success) {
|
|
167
|
+
error(`research: invalid --agent '${parsed.agent}' (expected: claude-code | codex-cli | gemini-cli | copilot)`);
|
|
168
|
+
return 2;
|
|
169
|
+
}
|
|
170
|
+
explicitAgent = agentResult.data;
|
|
171
|
+
}
|
|
172
|
+
let agent;
|
|
173
|
+
try {
|
|
174
|
+
const config = await loadRadarConfig(cwd);
|
|
175
|
+
agent = await getDefaultAgent("research", { explicit: explicitAgent, configOverride: config });
|
|
176
|
+
}
|
|
177
|
+
catch (e) {
|
|
178
|
+
if (e instanceof RadarConfigError) {
|
|
179
|
+
error(`research: ${e.message}`);
|
|
180
|
+
return 2;
|
|
181
|
+
}
|
|
182
|
+
throw e;
|
|
183
|
+
}
|
|
184
|
+
// Phase 2 sub-issues B / C / D / E ship all four adapters. AgentIdSchema
|
|
185
|
+
// already rejected invalid `--agent` values upstream, so any value that
|
|
186
|
+
// reaches here is supported.
|
|
187
|
+
const templateId = parsed.template ?? "default";
|
|
188
|
+
// Locate the item.
|
|
189
|
+
const found = await findItem(cwd, parsed.itemId);
|
|
190
|
+
if (!found) {
|
|
191
|
+
error(`research: item '${parsed.itemId}' not found under items/`);
|
|
192
|
+
return 1;
|
|
193
|
+
}
|
|
194
|
+
const { item } = found;
|
|
195
|
+
// Surface any prompt-injection pre-filter hits recorded by the watcher
|
|
196
|
+
// (ADR-0009 M1a / M5a — Adopt). Audit-only: the agent still runs against
|
|
197
|
+
// the original content, but the user gets an explicit warning so they can
|
|
198
|
+
// `radar dismiss` and re-evaluate before committing tokens.
|
|
199
|
+
if (item.injectionFlags.length > 0) {
|
|
200
|
+
warn(`research: item '${item.id}' has ${item.injectionFlags.length} injection flag(s): ${item.injectionFlags.join(", ")} (audit-only; use \`radar dismiss\` to skip)`);
|
|
201
|
+
}
|
|
202
|
+
// Load template.
|
|
203
|
+
const templatesDir = join(cwd, "templates");
|
|
204
|
+
let template;
|
|
205
|
+
try {
|
|
206
|
+
template = await loadTemplate(templateId, templatesDir);
|
|
207
|
+
}
|
|
208
|
+
catch (e) {
|
|
209
|
+
error(`research: ${e instanceof Error ? e.message : String(e)}`);
|
|
210
|
+
return 1;
|
|
211
|
+
}
|
|
212
|
+
// Compute output path. Refuse to overwrite an existing file — re-runs go
|
|
213
|
+
// through `radar update` per ADR-0003 (immutable history).
|
|
214
|
+
const now = new Date();
|
|
215
|
+
const datePrefix = buildDatePrefix(item, now);
|
|
216
|
+
const slug = buildSlug(item);
|
|
217
|
+
const filename = `${datePrefix}_${slug}_v1.md`;
|
|
218
|
+
const outputPath = join(cwd, "research", filename);
|
|
219
|
+
if (await pathExists(outputPath)) {
|
|
220
|
+
error(`research: ${outputPath} already exists (use \`radar update\` to re-research)`);
|
|
221
|
+
return 1;
|
|
222
|
+
}
|
|
223
|
+
log(`research: invoking ${agent} adapter for item '${item.id}' -> ${filename}`);
|
|
224
|
+
// Invoke adapter.
|
|
225
|
+
const adapter = getAgentAdapter(agent);
|
|
226
|
+
try {
|
|
227
|
+
await adapter.research({
|
|
228
|
+
agent,
|
|
229
|
+
templateId,
|
|
230
|
+
templateBody: template.body,
|
|
231
|
+
items: [item],
|
|
232
|
+
outputPath,
|
|
233
|
+
cwd,
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
catch (e) {
|
|
237
|
+
error(`research: adapter failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
238
|
+
return 1;
|
|
239
|
+
}
|
|
240
|
+
// Validate the produced file: frontmatter must parse and match schema.
|
|
241
|
+
if (!(await pathExists(outputPath))) {
|
|
242
|
+
error(`research: adapter completed but did not write ${outputPath} (agent ignored the output path?)`);
|
|
243
|
+
return 1;
|
|
244
|
+
}
|
|
245
|
+
let body;
|
|
246
|
+
try {
|
|
247
|
+
body = await readFile(outputPath, "utf8");
|
|
248
|
+
}
|
|
249
|
+
catch (e) {
|
|
250
|
+
error(`research: failed to read generated report: ${e instanceof Error ? e.message : String(e)}`);
|
|
251
|
+
return 1;
|
|
252
|
+
}
|
|
253
|
+
let frontmatter;
|
|
254
|
+
try {
|
|
255
|
+
frontmatter = matter(body, matterOptions).data;
|
|
256
|
+
}
|
|
257
|
+
catch (e) {
|
|
258
|
+
error(`research: failed to parse frontmatter: ${e instanceof Error ? e.message : String(e)}`);
|
|
259
|
+
return 1;
|
|
260
|
+
}
|
|
261
|
+
const fmResult = ResearchFrontmatterSchema.safeParse(frontmatter);
|
|
262
|
+
if (!fmResult.success) {
|
|
263
|
+
error(`research: frontmatter does not match ResearchFrontmatterSchema:`);
|
|
264
|
+
for (const issue of fmResult.error.issues) {
|
|
265
|
+
error(` - ${issue.path.join(".") || "<root>"}: ${issue.message}`);
|
|
266
|
+
}
|
|
267
|
+
return 1;
|
|
268
|
+
}
|
|
269
|
+
// Phase 1 contract: review fields must be null. The schema permits null;
|
|
270
|
+
// we additionally enforce that the agent did not jump ahead and stamp them.
|
|
271
|
+
// Phase 5 contract: `supersedes` is null on v1 by definition (no predecessor
|
|
272
|
+
// exists). Defensive reset applies if a misbehaving agent populates it; the
|
|
273
|
+
// `update` command (Sub-issue B / #41) is the only writer that may set it.
|
|
274
|
+
const reviewedDrift = fmResult.data.reviewedAt !== null || fmResult.data.reviewedBy !== null;
|
|
275
|
+
const supersedesDrift = fmResult.data.supersedes !== null;
|
|
276
|
+
if (reviewedDrift || supersedesDrift) {
|
|
277
|
+
if (reviewedDrift) {
|
|
278
|
+
warn("research: agent populated reviewedAt/reviewedBy; resetting to null (Phase 1 contract — review handles this in Phase 2)");
|
|
279
|
+
}
|
|
280
|
+
if (supersedesDrift) {
|
|
281
|
+
warn("research: agent populated supersedes; resetting to null (Phase 5 contract — v1 has no predecessor; `update` writes supersedes)");
|
|
282
|
+
}
|
|
283
|
+
const parsed = matter(body, matterOptions);
|
|
284
|
+
const rewritten = matter.stringify(parsed.content, {
|
|
285
|
+
...fmResult.data,
|
|
286
|
+
reviewedAt: null,
|
|
287
|
+
reviewedBy: null,
|
|
288
|
+
supersedes: null,
|
|
289
|
+
}, matterOptions);
|
|
290
|
+
await writeFile(outputPath, rewritten, "utf8");
|
|
291
|
+
}
|
|
292
|
+
// Transition item status.
|
|
293
|
+
const updated = { ...item, status: "researched" };
|
|
294
|
+
try {
|
|
295
|
+
// saveItems writes by sourceId+id, so it will overwrite the existing file
|
|
296
|
+
// in place. We rely on this rather than constructing the path manually.
|
|
297
|
+
await saveItems(join(cwd, "items"), [updated]);
|
|
298
|
+
}
|
|
299
|
+
catch (e) {
|
|
300
|
+
error(`research: failed to update item status: ${e instanceof Error ? e.message : String(e)}`);
|
|
301
|
+
error(` (research file was written: ${outputPath})`);
|
|
302
|
+
return 1;
|
|
303
|
+
}
|
|
304
|
+
log(`research: wrote ${outputPath}`);
|
|
305
|
+
log(`research: items/${item.sourceId}/${item.id}.yaml status -> researched`);
|
|
306
|
+
return 0;
|
|
307
|
+
}
|
|
308
|
+
export const researchCommand = {
|
|
309
|
+
name: "research",
|
|
310
|
+
summary: "Generate Markdown research reports from items via an AI agent",
|
|
311
|
+
run: (args) => runResearch(args),
|
|
312
|
+
};
|
|
313
|
+
//# sourceMappingURL=research.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"research.js","sourceRoot":"","sources":["../../src/cli/research.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Command } from "./index.js";
|
|
2
|
+
/** Sinks for the review command's user-facing output. Tests inject capturing sinks. */
|
|
3
|
+
export interface ReviewIO {
|
|
4
|
+
log?: (message: string) => void;
|
|
5
|
+
warn?: (message: string) => void;
|
|
6
|
+
error?: (message: string) => void;
|
|
7
|
+
}
|
|
8
|
+
export interface ReviewCommandOptions {
|
|
9
|
+
cwd?: string;
|
|
10
|
+
io?: ReviewIO;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Implementation of `radar review <research-id>`.
|
|
14
|
+
*
|
|
15
|
+
* High-level flow (Phase 2):
|
|
16
|
+
* 1. Parse + validate args (agent defaults to `claude-code`, template to `default`).
|
|
17
|
+
* 2. Resolve `research/<research-id>.md` and parse its frontmatter.
|
|
18
|
+
* 3. Refuse to re-review (frontmatter already has `reviewedAt`).
|
|
19
|
+
* 4. Locate the linked items and verify their status is `researched`.
|
|
20
|
+
* 5. Load `templates/<template-id>.md` (empty body when default is absent).
|
|
21
|
+
* 6. Snapshot the research file body and item payloads (rollback target).
|
|
22
|
+
* 7. Invoke the adapter; the agent rewrites the research file in place
|
|
23
|
+
* (appends review block + stamps `reviewedAt` / `reviewedBy`).
|
|
24
|
+
* 8. Re-read the research file, validate the updated frontmatter.
|
|
25
|
+
* 9. Transition each linked item: `status` → `reviewed` and persist.
|
|
26
|
+
* If this step fails, restore the snapshot from (6) and exit non-zero.
|
|
27
|
+
*
|
|
28
|
+
* The snapshot/restore strategy gives us atomicity at the workspace level
|
|
29
|
+
* (ADR-0003 / ADR-0008): either both the research file and the linked items
|
|
30
|
+
* reflect the new review, or neither does.
|
|
31
|
+
*/
|
|
32
|
+
export declare function runReview(args: string[], options?: ReviewCommandOptions): Promise<number>;
|
|
33
|
+
export declare const reviewCommand: Command;
|
|
34
|
+
//# sourceMappingURL=review.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review.d.ts","sourceRoot":"","sources":["../../src/cli/review.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAiB1C,uFAAuF;AACvF,MAAM,WAAW,QAAQ;IACvB,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,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;CACf;AAqID;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,SAAS,CAC7B,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,MAAM,CAAC,CA2RjB;AAED,eAAO,MAAM,aAAa,EAAE,OAI3B,CAAC"}
|