@ozzylabs/feedradar 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ja.md +51 -13
- package/README.md +51 -13
- package/dist/agents/_boundary.d.ts +21 -0
- package/dist/agents/_boundary.d.ts.map +1 -1
- package/dist/agents/_boundary.js +34 -0
- package/dist/agents/_boundary.js.map +1 -1
- package/dist/agents/claude-code.d.ts.map +1 -1
- package/dist/agents/claude-code.js +14 -6
- package/dist/agents/claude-code.js.map +1 -1
- package/dist/agents/codex-cli.d.ts.map +1 -1
- package/dist/agents/codex-cli.js +13 -7
- package/dist/agents/codex-cli.js.map +1 -1
- package/dist/agents/copilot.d.ts.map +1 -1
- package/dist/agents/copilot.js +13 -6
- package/dist/agents/copilot.js.map +1 -1
- package/dist/agents/gemini-cli.d.ts.map +1 -1
- package/dist/agents/gemini-cli.js +13 -6
- package/dist/agents/gemini-cli.js.map +1 -1
- package/dist/agents/types.d.ts +26 -0
- package/dist/agents/types.d.ts.map +1 -1
- package/dist/claude-skills/dismiss/SKILL.md +4 -4
- package/dist/claude-skills/research/SKILL.md +2 -3
- package/dist/claude-skills/review/SKILL.md +2 -2
- package/dist/claude-skills/update/SKILL.md +7 -7
- package/dist/cli/_locale.d.ts +96 -0
- package/dist/cli/_locale.d.ts.map +1 -0
- package/dist/cli/_locale.js +130 -0
- package/dist/cli/_locale.js.map +1 -0
- package/dist/cli/_progress.d.ts +30 -1
- package/dist/cli/_progress.d.ts.map +1 -1
- package/dist/cli/_progress.js +9 -1
- package/dist/cli/_progress.js.map +1 -1
- package/dist/cli/dismiss.d.ts.map +1 -1
- package/dist/cli/dismiss.js +61 -54
- package/dist/cli/dismiss.js.map +1 -1
- package/dist/cli/doctor.d.ts +8 -0
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +91 -60
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/index.d.ts +36 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +79 -18
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/init.d.ts +15 -0
- package/dist/cli/init.d.ts.map +1 -1
- package/dist/cli/init.js +149 -51
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/items.d.ts.map +1 -1
- package/dist/cli/items.js +51 -30
- package/dist/cli/items.js.map +1 -1
- package/dist/cli/research.d.ts.map +1 -1
- package/dist/cli/research.js +138 -109
- package/dist/cli/research.js.map +1 -1
- package/dist/cli/review.d.ts.map +1 -1
- package/dist/cli/review.js +114 -92
- package/dist/cli/review.js.map +1 -1
- package/dist/cli/routine/fire.d.ts +3 -2
- package/dist/cli/routine/fire.d.ts.map +1 -1
- package/dist/cli/routine/fire.js +30 -25
- package/dist/cli/routine/fire.js.map +1 -1
- package/dist/cli/routine/generate-pipeline.d.ts +70 -1
- package/dist/cli/routine/generate-pipeline.d.ts.map +1 -1
- package/dist/cli/routine/generate-pipeline.js +273 -44
- package/dist/cli/routine/generate-pipeline.js.map +1 -1
- package/dist/cli/routine/generate-watch.d.ts +10 -1
- package/dist/cli/routine/generate-watch.d.ts.map +1 -1
- package/dist/cli/routine/generate-watch.js +49 -37
- package/dist/cli/routine/generate-watch.js.map +1 -1
- package/dist/cli/routine.d.ts.map +1 -1
- package/dist/cli/routine.js +28 -24
- package/dist/cli/routine.js.map +1 -1
- package/dist/cli/source.d.ts.map +1 -1
- package/dist/cli/source.js +206 -182
- package/dist/cli/source.js.map +1 -1
- package/dist/cli/triage.d.ts.map +1 -1
- package/dist/cli/triage.js +146 -130
- package/dist/cli/triage.js.map +1 -1
- package/dist/cli/undismiss.d.ts.map +1 -1
- package/dist/cli/undismiss.js +32 -25
- package/dist/cli/undismiss.js.map +1 -1
- package/dist/cli/update.d.ts.map +1 -1
- package/dist/cli/update.js +77 -61
- package/dist/cli/update.js.map +1 -1
- package/dist/cli/watch.d.ts.map +1 -1
- package/dist/cli/watch.js +71 -31
- package/dist/cli/watch.js.map +1 -1
- package/dist/cli/workflow/generate-combined-with-triage.d.ts +9 -2
- package/dist/cli/workflow/generate-combined-with-triage.d.ts.map +1 -1
- package/dist/cli/workflow/generate-combined-with-triage.js +120 -71
- package/dist/cli/workflow/generate-combined-with-triage.js.map +1 -1
- package/dist/cli/workflow/generate-combined.d.ts +8 -1
- package/dist/cli/workflow/generate-combined.d.ts.map +1 -1
- package/dist/cli/workflow/generate-combined.js +39 -33
- package/dist/cli/workflow/generate-combined.js.map +1 -1
- package/dist/cli/workflow/generate-watch.d.ts +10 -1
- package/dist/cli/workflow/generate-watch.d.ts.map +1 -1
- package/dist/cli/workflow/generate-watch.js +37 -30
- package/dist/cli/workflow/generate-watch.js.map +1 -1
- package/dist/cli/workflow.d.ts.map +1 -1
- package/dist/cli/workflow.js +28 -23
- package/dist/cli/workflow.js.map +1 -1
- package/dist/core/config.d.ts +2 -1
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +14 -4
- package/dist/core/config.js.map +1 -1
- package/dist/core/feeds/html-js.d.ts.map +1 -1
- package/dist/core/feeds/html-js.js +16 -9
- package/dist/core/feeds/html-js.js.map +1 -1
- package/dist/core/feeds/types.d.ts +9 -0
- package/dist/core/feeds/types.d.ts.map +1 -1
- package/dist/core/locale.d.ts +69 -0
- package/dist/core/locale.d.ts.map +1 -0
- package/dist/core/locale.js +74 -0
- package/dist/core/locale.js.map +1 -0
- package/dist/core/watcher.d.ts +11 -0
- package/dist/core/watcher.d.ts.map +1 -1
- package/dist/core/watcher.js +21 -5
- package/dist/core/watcher.js.map +1 -1
- package/dist/i18n/index.d.ts +57 -0
- package/dist/i18n/index.d.ts.map +1 -0
- package/dist/i18n/index.js +49 -0
- package/dist/i18n/index.js.map +1 -0
- package/dist/i18n/messages/en.d.ts +993 -0
- package/dist/i18n/messages/en.d.ts.map +1 -0
- package/dist/i18n/messages/en.js +1096 -0
- package/dist/i18n/messages/en.js.map +1 -0
- package/dist/i18n/messages/ja.d.ts +13 -0
- package/dist/i18n/messages/ja.d.ts.map +1 -0
- package/dist/i18n/messages/ja.js +970 -0
- package/dist/i18n/messages/ja.js.map +1 -0
- package/dist/schemas/config.d.ts +7 -0
- package/dist/schemas/config.d.ts.map +1 -1
- package/dist/schemas/config.js +5 -0
- package/dist/schemas/config.js.map +1 -1
- package/dist/schemas/recipe.d.ts +1 -1
- package/dist/schemas/source.d.ts +3 -3
- package/dist/skills/research/SKILL.md +13 -12
- package/dist/skills/review/SKILL.md +13 -12
- package/dist/skills/update/SKILL.md +19 -19
- package/dist/templates/en/agents/AGENTS.md +284 -0
- package/dist/templates/en/claude/CLAUDE.md +5 -0
- package/dist/templates/en/default.md +16 -0
- package/dist/templates/en/digest.md +66 -0
- package/dist/templates/en/feedradar.md +235 -0
- package/dist/templates/{routines → en/routines}/pipeline.yaml.tmpl +30 -41
- package/dist/templates/{routines → en/routines}/watch-daily.yaml +12 -15
- package/dist/templates/{routines → en/routines}/watch.yaml.tmpl +11 -14
- package/dist/templates/{workflows → en/workflows}/combined-with-triage.template.yaml.tmpl +3 -3
- package/dist/templates/{workflows → en/workflows}/combined.template.yaml.tmpl +6 -6
- package/dist/templates/{workflows → en/workflows}/watch.template.yaml.tmpl +8 -8
- package/dist/templates/{workflows → en/workflows}/watch.yaml +3 -3
- package/dist/templates/{agents → ja/agents}/AGENTS.md +16 -16
- package/dist/templates/{digest.md → ja/digest.md} +5 -6
- package/dist/templates/{feedradar.md → ja/feedradar.md} +12 -12
- package/dist/templates/ja/routines/pipeline.yaml.tmpl +211 -0
- package/dist/templates/ja/routines/watch-daily.yaml +151 -0
- package/dist/templates/ja/routines/watch.yaml.tmpl +145 -0
- package/dist/templates/ja/workflows/combined-with-triage.template.yaml.tmpl +123 -0
- package/dist/templates/ja/workflows/combined.template.yaml.tmpl +109 -0
- package/dist/templates/ja/workflows/watch.template.yaml.tmpl +100 -0
- package/dist/templates/ja/workflows/watch.yaml +73 -0
- package/package.json +1 -1
- /package/dist/templates/{claude → ja/claude}/CLAUDE.md +0 -0
- /package/dist/templates/{default.md → ja/default.md} +0 -0
package/dist/cli/source.js
CHANGED
|
@@ -5,7 +5,9 @@ import { createProgressReporter } from "../core/progress.js";
|
|
|
5
5
|
import { listRecipes, loadRecipe, mergeRecipeWithOverrides, } from "../core/recipes.js";
|
|
6
6
|
import { loadSourceState } from "../core/state.js";
|
|
7
7
|
import { watchRun } from "../core/watcher.js";
|
|
8
|
+
import { createTranslator } from "../i18n/index.js";
|
|
8
9
|
import { SourceKindSchema, SourceSchema, SourceSelectorsSchema } from "../schemas/source.js";
|
|
10
|
+
import { LangFlagError, parseLangFlag, resolveWorkspaceLocale } from "./_locale.js";
|
|
9
11
|
async function pathExists(p) {
|
|
10
12
|
try {
|
|
11
13
|
await access(p);
|
|
@@ -282,112 +284,23 @@ function parseRemoveArgs(args) {
|
|
|
282
284
|
}
|
|
283
285
|
return out;
|
|
284
286
|
}
|
|
285
|
-
function printAddHelp(log) {
|
|
286
|
-
log("
|
|
287
|
-
log(" radar source add <id> --recipe <name> [overrides]");
|
|
288
|
-
log("");
|
|
289
|
-
log("Options:");
|
|
290
|
-
log(" --kind <kind> rss | html | html-js | github-releases | npm-registry | json-feed | json-api");
|
|
291
|
-
log(" --url <url> fetch target URL");
|
|
292
|
-
log(" --recipe <name> apply a bundled recipe (see `radar source recipes`).");
|
|
293
|
-
log(" Mutually exclusive with --kind / --url / --selector-* /");
|
|
294
|
-
log(" --pagination-*; --name / --tags / --keywords /");
|
|
295
|
-
log(" --exclude-keywords still override the recipe defaults.");
|
|
296
|
-
log(" --name <name> display name (defaults to <id>)");
|
|
297
|
-
log(" --tags <a,b> comma-separated tags");
|
|
298
|
-
log(" --keywords <a,b> comma-separated include keywords");
|
|
299
|
-
log(" (required for useful output — empty = match nothing)");
|
|
300
|
-
log(" --exclude-keywords <a,b> comma-separated exclude keywords");
|
|
301
|
-
log(" --selector-<field> <css> CSS selector for kind=html / html-js (required: item, title, link)");
|
|
302
|
-
log(" optional: summary, publishedAt, body, tags");
|
|
303
|
-
log(" For kind=html-js, selectors evaluate against the post-JS DOM.");
|
|
304
|
-
log(" The `js:` block (waitFor / timeout / userAgent) cannot be set");
|
|
305
|
-
log(" via flags; edit sources/<id>.yaml after add. See ADR-0010.");
|
|
306
|
-
log("");
|
|
307
|
-
log(" For kind=json-api (ADR-0012 / #174):");
|
|
308
|
-
log(" --pagination-strategy <s> page | offset | cursor | link-header | token | none (default: page)");
|
|
309
|
-
log(" --pagination-param <name> query param name for the page/offset/cursor value");
|
|
310
|
-
log(" --pagination-start N initial page/offset value (default: 0)");
|
|
311
|
-
log(" --page-size N items per page");
|
|
312
|
-
log(" --page-size-param <name> query param name for the page-size value");
|
|
313
|
-
log(" --max-pages N hard cap on pages traversed (default: 20)");
|
|
314
|
-
log(" --next-cursor-path <jp> JSONPath-lite to the next-cursor value (cursor/token strategy)");
|
|
315
|
-
log(" --total-path <jp> JSONPath-lite to the total-count value (backfill early-stop hint)");
|
|
316
|
-
log("");
|
|
317
|
-
log(" Selector fields (`jsonSelectors.*`) for kind=json-api cannot be set via flags;");
|
|
318
|
-
log(" the schema has a default fallback chain (items / title / link / publishedAt / summary),");
|
|
319
|
-
log(" so simple APIs work without selectors. Edit sources/<id>.yaml directly when explicit");
|
|
320
|
-
log(" selectors are needed (nested fields, non-standard envelopes).");
|
|
321
|
-
log("");
|
|
322
|
-
log(" Facet sweep (e.g. year-by-year sweep) cannot be configured via flags; see ADR-0017");
|
|
323
|
-
log(" and bundle the year sweep through `--recipe aws-whats-new`. Recipe-only structural field.");
|
|
287
|
+
function printAddHelp(t, log) {
|
|
288
|
+
log(t("cli.source.addHelp"));
|
|
324
289
|
}
|
|
325
|
-
function printListHelp(log) {
|
|
326
|
-
log("
|
|
327
|
-
log("");
|
|
328
|
-
log("Lists sources/*.yaml in tabular form: id / kind / url / tags.");
|
|
329
|
-
log("");
|
|
330
|
-
log("Options:");
|
|
331
|
-
log(" --enabled-only Reserved for forward compatibility (currently a no-op).");
|
|
332
|
-
log(" -v, --verbose Print a detailed block per source including keywords,");
|
|
333
|
-
log(" trustLevel, and lastFetchedAt (from state/<id>.yaml).");
|
|
290
|
+
function printListHelp(t, log) {
|
|
291
|
+
log(t("cli.source.listHelp"));
|
|
334
292
|
}
|
|
335
|
-
function printRemoveHelp(log) {
|
|
336
|
-
log("
|
|
337
|
-
log("");
|
|
338
|
-
log("Deletes sources/<id>.yaml. state/<id>.yaml and items/ are preserved.");
|
|
293
|
+
function printRemoveHelp(t, log) {
|
|
294
|
+
log(t("cli.source.removeHelp"));
|
|
339
295
|
}
|
|
340
|
-
function printTestHelp(log) {
|
|
341
|
-
log("
|
|
342
|
-
log("");
|
|
343
|
-
log("Dry-run a single source: fetch, filter, and print matched items.");
|
|
344
|
-
log("state/ and items/ are not touched (no persistence). Useful for tuning");
|
|
345
|
-
log("keywords when adding a new source.");
|
|
346
|
-
log("");
|
|
347
|
-
log("For kind=json-api (ADR-0012 / #174), `source test` fetches PAGE 0 ONLY.");
|
|
348
|
-
log("Pagination is NOT walked even when the recipe declares multiple pages —");
|
|
349
|
-
log("`--limit N` caps how many matched items are PRINTED, it does not change");
|
|
350
|
-
log("the page budget. Use `radar watch run --backfill` for full-history ingest.");
|
|
351
|
-
log("Page 0's `Link` header / `nextCursor` extraction is surfaced via");
|
|
352
|
-
log("`--show-content` for pagination tuning without state mutation.");
|
|
353
|
-
log("");
|
|
354
|
-
log("For facet-sweep recipes (ADR-0017 / #256), `source test` probes a SINGLE");
|
|
355
|
-
log("facet value: range facets use the upper bound (latest year), enum facets");
|
|
356
|
-
log("use the first listed value. A warning names which value was tested so");
|
|
357
|
-
log("keyword tuning is not silently scoped to one slice. Run `radar watch run");
|
|
358
|
-
log("--backfill` to sweep every facet value.");
|
|
359
|
-
log("");
|
|
360
|
-
log("Options:");
|
|
361
|
-
log(" --limit N Maximum number of matched items to print (default 10)");
|
|
362
|
-
log(" --show-content Also print the first 200 chars of each item's body, plus");
|
|
363
|
-
log(" (kind=json-api) the selector adoption table and pagination");
|
|
364
|
-
log(" preview (would-be next URL / Link header / nextCursor).");
|
|
365
|
-
log(" -v, --verbose Enable progress-reporter raw() pass-through (adapter stdout).");
|
|
366
|
-
log(" Most useful with kind=html-js (Playwright phase markers).");
|
|
367
|
-
log(" -q, --quiet Suppress the progress reporter entirely. RADAR_NO_PROGRESS=1");
|
|
368
|
-
log(" has the same effect.");
|
|
296
|
+
function printTestHelp(t, log) {
|
|
297
|
+
log(t("cli.source.testHelp"));
|
|
369
298
|
}
|
|
370
|
-
function printRecipesHelp(log) {
|
|
371
|
-
log("
|
|
372
|
-
log("");
|
|
373
|
-
log("List bundled recipes (recipes/*.yaml in the radar package — ADR-0012 §D3).");
|
|
374
|
-
log("Each recipe can be applied via:");
|
|
375
|
-
log(" radar source add <id> --recipe <name> [--keywords <kw>] [--tags <t>] [--name <display>]");
|
|
376
|
-
log("");
|
|
377
|
-
log("Bundled recipes ship with the radar npm package; user-authored recipes are");
|
|
378
|
-
log("not yet supported. To add a new bundled recipe, contribute a YAML to the");
|
|
379
|
-
log("radar repo's recipes/ directory.");
|
|
299
|
+
function printRecipesHelp(t, log) {
|
|
300
|
+
log(t("cli.source.recipesHelp"));
|
|
380
301
|
}
|
|
381
|
-
function printSourceHelp(log) {
|
|
382
|
-
log("
|
|
383
|
-
log("");
|
|
384
|
-
log("Subcommands:");
|
|
385
|
-
log(" add <id> --kind <kind> --url <url> [...]");
|
|
386
|
-
log(" add <id> --recipe <name> [--keywords <kw>] [--tags <t>] [--name <display>]");
|
|
387
|
-
log(" list [--enabled-only]");
|
|
388
|
-
log(" recipes");
|
|
389
|
-
log(" remove <id>");
|
|
390
|
-
log(" test <id> [--limit N] [--show-content]");
|
|
302
|
+
function printSourceHelp(t, log) {
|
|
303
|
+
log(t("cli.source.help"));
|
|
391
304
|
}
|
|
392
305
|
/**
|
|
393
306
|
* Implementation of `source add`.
|
|
@@ -402,25 +315,38 @@ export async function addSource(args, options = {}) {
|
|
|
402
315
|
const log = options.io?.log ?? ((m) => console.log(m));
|
|
403
316
|
const warn = options.io?.warn ?? ((m) => console.warn(m));
|
|
404
317
|
const error = options.io?.error ?? ((m) => console.error(m));
|
|
318
|
+
let langState;
|
|
319
|
+
try {
|
|
320
|
+
langState = parseLangFlag(args);
|
|
321
|
+
}
|
|
322
|
+
catch (e) {
|
|
323
|
+
if (e instanceof LangFlagError) {
|
|
324
|
+
error(`source add: ${e.message}`);
|
|
325
|
+
return 2;
|
|
326
|
+
}
|
|
327
|
+
throw e;
|
|
328
|
+
}
|
|
329
|
+
const locale = await resolveWorkspaceLocale({ flag: langState.flag, cwd, warn: error });
|
|
330
|
+
const t = createTranslator(locale);
|
|
405
331
|
let parsed;
|
|
406
332
|
try {
|
|
407
|
-
parsed = parseAddArgs(
|
|
333
|
+
parsed = parseAddArgs(langState.rest);
|
|
408
334
|
}
|
|
409
335
|
catch (e) {
|
|
410
336
|
error(`source add: ${e instanceof Error ? e.message : String(e)}`);
|
|
411
337
|
return 2;
|
|
412
338
|
}
|
|
413
339
|
if (parsed.help) {
|
|
414
|
-
printAddHelp(log);
|
|
340
|
+
printAddHelp(t, log);
|
|
415
341
|
return 0;
|
|
416
342
|
}
|
|
417
343
|
if (!parsed.id) {
|
|
418
|
-
error("source
|
|
419
|
-
printAddHelp(error);
|
|
344
|
+
error(t("cli.source.missingId", { sub: "add" }));
|
|
345
|
+
printAddHelp(t, error);
|
|
420
346
|
return 2;
|
|
421
347
|
}
|
|
422
348
|
if (!isSafeSourceId(parsed.id)) {
|
|
423
|
-
error(
|
|
349
|
+
error(t("cli.source.invalidId", { sub: "add", id: parsed.id }));
|
|
424
350
|
return 2;
|
|
425
351
|
}
|
|
426
352
|
// `--recipe <name>` short-circuits the flag-based composition: the
|
|
@@ -431,19 +357,19 @@ export async function addSource(args, options = {}) {
|
|
|
431
357
|
// `--pagination-*`) is rejected so the user gets an immediate, targeted
|
|
432
358
|
// error instead of silently-ignored flags. ADR-0012 §D3.
|
|
433
359
|
if (parsed.recipe !== undefined) {
|
|
434
|
-
return addSourceFromRecipe(parsed, cwd, options, log, warn, error);
|
|
360
|
+
return addSourceFromRecipe(parsed, cwd, options, log, warn, error, t);
|
|
435
361
|
}
|
|
436
362
|
if (!parsed.kind) {
|
|
437
|
-
error("source
|
|
363
|
+
error(t("cli.source.kindRequired"));
|
|
438
364
|
return 2;
|
|
439
365
|
}
|
|
440
366
|
if (!parsed.url) {
|
|
441
|
-
error("source
|
|
367
|
+
error(t("cli.source.urlRequired"));
|
|
442
368
|
return 2;
|
|
443
369
|
}
|
|
444
370
|
const kindResult = SourceKindSchema.safeParse(parsed.kind);
|
|
445
371
|
if (!kindResult.success) {
|
|
446
|
-
error(
|
|
372
|
+
error(t("cli.source.invalidKind", { kind: parsed.kind }));
|
|
447
373
|
return 2;
|
|
448
374
|
}
|
|
449
375
|
// Compose the object before schema validation so url-format errors et al.
|
|
@@ -474,7 +400,7 @@ export async function addSource(args, options = {}) {
|
|
|
474
400
|
const selectorsResult = SourceSelectorsSchema.safeParse(parsed.selectors);
|
|
475
401
|
if (!selectorsResult.success) {
|
|
476
402
|
const issues = selectorsResult.error.issues.map((i) => `selectors.${i.path.join(".") || "<root>"}: ${i.message}`);
|
|
477
|
-
error(
|
|
403
|
+
error(t("cli.source.validationFailed"));
|
|
478
404
|
for (const issue of issues) {
|
|
479
405
|
error(` - ${issue}`);
|
|
480
406
|
}
|
|
@@ -525,13 +451,13 @@ export async function addSource(args, options = {}) {
|
|
|
525
451
|
// Reject pagination flags on non-json-api kinds early so the user sees
|
|
526
452
|
// a targeted hint instead of a deep schema refinement error ("pagination
|
|
527
453
|
// is required when kind is 'json-api'" makes no sense for `kind: rss`).
|
|
528
|
-
error(
|
|
454
|
+
error(t("cli.source.paginationOnlyJsonApi", { kind: kindResult.data }));
|
|
529
455
|
return 2;
|
|
530
456
|
}
|
|
531
457
|
const validated = SourceSchema.safeParse(candidate);
|
|
532
458
|
if (!validated.success) {
|
|
533
459
|
const issues = validated.error.issues.map((i) => `${i.path.join(".") || "<root>"}: ${i.message}`);
|
|
534
|
-
error(
|
|
460
|
+
error(t("cli.source.validationFailed"));
|
|
535
461
|
for (const issue of issues) {
|
|
536
462
|
error(` - ${issue}`);
|
|
537
463
|
}
|
|
@@ -539,11 +465,11 @@ export async function addSource(args, options = {}) {
|
|
|
539
465
|
}
|
|
540
466
|
const file = sourceFile(cwd, validated.data.id);
|
|
541
467
|
if (await pathExists(file)) {
|
|
542
|
-
error(
|
|
468
|
+
error(t("cli.source.alreadyExists", { id: validated.data.id }));
|
|
543
469
|
return 1;
|
|
544
470
|
}
|
|
545
471
|
await writeFile(file, stringifyYaml(validated.data), "utf8");
|
|
546
|
-
log(
|
|
472
|
+
log(t("cli.source.created", { id: validated.data.id }));
|
|
547
473
|
// ADR-0006 / src/core/filter.ts treats an empty include-keyword list as
|
|
548
474
|
// "match nothing" (firehose guard). A source with no keywords is therefore
|
|
549
475
|
// valid YAML but inert — `watch run` will fetch it and drop every item
|
|
@@ -552,7 +478,7 @@ export async function addSource(args, options = {}) {
|
|
|
552
478
|
// (stderr) so scripts that parse stdout are unaffected and the exit code
|
|
553
479
|
// stays 0.
|
|
554
480
|
if (validated.data.filters.keywords.length === 0) {
|
|
555
|
-
warn(
|
|
481
|
+
warn(t("cli.source.noKeywordsWarn", { id: validated.data.id }));
|
|
556
482
|
}
|
|
557
483
|
return 0;
|
|
558
484
|
}
|
|
@@ -572,7 +498,7 @@ export async function addSource(args, options = {}) {
|
|
|
572
498
|
* structurally edit `sources/<id>.yaml` after generation, same as for
|
|
573
499
|
* any other source.
|
|
574
500
|
*/
|
|
575
|
-
async function addSourceFromRecipe(parsed, cwd, options, log, warn, error) {
|
|
501
|
+
async function addSourceFromRecipe(parsed, cwd, options, log, warn, error, t) {
|
|
576
502
|
const recipeName = parsed.recipe;
|
|
577
503
|
// Defensive — should be guaranteed by the caller, but `parsed.recipe`
|
|
578
504
|
// is typed as `string | undefined` so a quick narrow here keeps the
|
|
@@ -602,7 +528,7 @@ async function addSourceFromRecipe(parsed, cwd, options, log, warn, error) {
|
|
|
602
528
|
forbidden.push("--pagination-*");
|
|
603
529
|
}
|
|
604
530
|
if (forbidden.length > 0) {
|
|
605
|
-
error(
|
|
531
|
+
error(t("cli.source.recipeForbiddenFlags", { recipe: recipeName, flags: forbidden.join(", ") }));
|
|
606
532
|
return 2;
|
|
607
533
|
}
|
|
608
534
|
let loaded;
|
|
@@ -632,7 +558,7 @@ async function addSourceFromRecipe(parsed, cwd, options, log, warn, error) {
|
|
|
632
558
|
// illegal combination). Surface every issue verbatim so recipe
|
|
633
559
|
// authors and end users can both diagnose.
|
|
634
560
|
const issues = validated.error.issues.map((i) => `${i.path.join(".") || "<root>"}: ${i.message}`);
|
|
635
|
-
error(
|
|
561
|
+
error(t("cli.source.recipeInvalidSource", { recipe: recipeName }));
|
|
636
562
|
for (const issue of issues) {
|
|
637
563
|
error(` - ${issue}`);
|
|
638
564
|
}
|
|
@@ -640,17 +566,17 @@ async function addSourceFromRecipe(parsed, cwd, options, log, warn, error) {
|
|
|
640
566
|
}
|
|
641
567
|
const file = sourceFile(cwd, validated.data.id);
|
|
642
568
|
if (await pathExists(file)) {
|
|
643
|
-
error(
|
|
569
|
+
error(t("cli.source.alreadyExists", { id: validated.data.id }));
|
|
644
570
|
return 1;
|
|
645
571
|
}
|
|
646
572
|
await writeFile(file, stringifyYaml(validated.data), "utf8");
|
|
647
|
-
log(
|
|
573
|
+
log(t("cli.source.createdFromRecipe", { id: validated.data.id, recipe: recipeName }));
|
|
648
574
|
// Same firehose-guard hint as the flag-based path: an empty
|
|
649
575
|
// include-keyword list silently drops every fetched item, which
|
|
650
576
|
// surprises users when they thought the recipe came with sensible
|
|
651
577
|
// defaults.
|
|
652
578
|
if (validated.data.filters.keywords.length === 0) {
|
|
653
|
-
warn(
|
|
579
|
+
warn(t("cli.source.noKeywordsWarnRecipe", { id: validated.data.id }));
|
|
654
580
|
}
|
|
655
581
|
return 0;
|
|
656
582
|
}
|
|
@@ -701,16 +627,29 @@ export async function listSources(args, options = {}) {
|
|
|
701
627
|
const cwd = options.cwd ?? process.cwd();
|
|
702
628
|
const log = options.io?.log ?? ((m) => console.log(m));
|
|
703
629
|
const error = options.io?.error ?? ((m) => console.error(m));
|
|
630
|
+
let langState;
|
|
631
|
+
try {
|
|
632
|
+
langState = parseLangFlag(args);
|
|
633
|
+
}
|
|
634
|
+
catch (e) {
|
|
635
|
+
if (e instanceof LangFlagError) {
|
|
636
|
+
error(`source list: ${e.message}`);
|
|
637
|
+
return 2;
|
|
638
|
+
}
|
|
639
|
+
throw e;
|
|
640
|
+
}
|
|
641
|
+
const locale = await resolveWorkspaceLocale({ flag: langState.flag, cwd, warn: error });
|
|
642
|
+
const t = createTranslator(locale);
|
|
704
643
|
let parsed;
|
|
705
644
|
try {
|
|
706
|
-
parsed = parseListArgs(
|
|
645
|
+
parsed = parseListArgs(langState.rest);
|
|
707
646
|
}
|
|
708
647
|
catch (e) {
|
|
709
648
|
error(`source list: ${e instanceof Error ? e.message : String(e)}`);
|
|
710
649
|
return 2;
|
|
711
650
|
}
|
|
712
651
|
if (parsed.help) {
|
|
713
|
-
printListHelp(log);
|
|
652
|
+
printListHelp(t, log);
|
|
714
653
|
return 0;
|
|
715
654
|
}
|
|
716
655
|
// --enabled-only is wired through for forward compatibility; the schema does
|
|
@@ -719,7 +658,7 @@ export async function listSources(args, options = {}) {
|
|
|
719
658
|
// surface stable.
|
|
720
659
|
const dir = sourcesDir(cwd);
|
|
721
660
|
if (!(await pathExists(dir))) {
|
|
722
|
-
log("source
|
|
661
|
+
log(t("cli.source.listNoDir"));
|
|
723
662
|
return 0;
|
|
724
663
|
}
|
|
725
664
|
let entries;
|
|
@@ -732,7 +671,7 @@ export async function listSources(args, options = {}) {
|
|
|
732
671
|
}
|
|
733
672
|
const yamlFiles = entries.filter((f) => f.endsWith(".yaml")).sort();
|
|
734
673
|
if (yamlFiles.length === 0) {
|
|
735
|
-
log("source
|
|
674
|
+
log(t("cli.source.listNoSources"));
|
|
736
675
|
return 0;
|
|
737
676
|
}
|
|
738
677
|
const sources = [];
|
|
@@ -758,22 +697,29 @@ export async function listSources(args, options = {}) {
|
|
|
758
697
|
if (i > 0)
|
|
759
698
|
log("");
|
|
760
699
|
const lastFetchedAt = await readLastFetchedAt(cwd, s.id, error);
|
|
700
|
+
const none = t("cli.source.valueNone");
|
|
761
701
|
log(`${s.id}`);
|
|
762
|
-
log(
|
|
763
|
-
log(
|
|
764
|
-
log(
|
|
765
|
-
log(
|
|
766
|
-
log(
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
702
|
+
log(t("cli.source.fieldKind", { value: s.kind }));
|
|
703
|
+
log(t("cli.source.fieldUrl", { value: s.url }));
|
|
704
|
+
log(t("cli.source.fieldName", { value: s.name ?? none }));
|
|
705
|
+
log(t("cli.source.fieldTags", { value: s.tags.length > 0 ? s.tags.join(",") : none }));
|
|
706
|
+
log(t("cli.source.fieldKeywords", {
|
|
707
|
+
value: s.filters.keywords.length > 0
|
|
708
|
+
? s.filters.keywords.join(",")
|
|
709
|
+
: t("cli.source.keywordsEmpty"),
|
|
710
|
+
}));
|
|
711
|
+
log(t("cli.source.fieldExcludeKeywords", {
|
|
712
|
+
value: s.filters.excludeKeywords.length > 0 ? s.filters.excludeKeywords.join(",") : none,
|
|
713
|
+
}));
|
|
714
|
+
log(t("cli.source.fieldTrustLevel", { value: s.trustLevel }));
|
|
715
|
+
log(t("cli.source.fieldLastFetchedAt", { value: lastFetchedAt }));
|
|
770
716
|
}
|
|
771
717
|
return 0;
|
|
772
718
|
}
|
|
773
719
|
const idWidth = Math.max(2, ...sources.map((s) => s.id.length));
|
|
774
720
|
const kindWidth = Math.max(4, ...sources.map((s) => s.kind.length));
|
|
775
721
|
const urlWidth = Math.max(3, ...sources.map((s) => s.url.length));
|
|
776
|
-
log(`${pad("
|
|
722
|
+
log(`${pad(t("cli.source.listHeaderId"), idWidth)} ${pad(t("cli.source.listHeaderKind"), kindWidth)} ${pad(t("cli.source.listHeaderUrl"), urlWidth)} ${t("cli.source.listHeaderTags")}`);
|
|
777
723
|
for (const s of sources) {
|
|
778
724
|
log(`${pad(s.id, idWidth)} ${pad(s.kind, kindWidth)} ${pad(s.url, urlWidth)} ${s.tags.join(",")}`);
|
|
779
725
|
}
|
|
@@ -810,34 +756,47 @@ export async function removeSource(args, options = {}) {
|
|
|
810
756
|
const cwd = options.cwd ?? process.cwd();
|
|
811
757
|
const log = options.io?.log ?? ((m) => console.log(m));
|
|
812
758
|
const error = options.io?.error ?? ((m) => console.error(m));
|
|
759
|
+
let langState;
|
|
760
|
+
try {
|
|
761
|
+
langState = parseLangFlag(args);
|
|
762
|
+
}
|
|
763
|
+
catch (e) {
|
|
764
|
+
if (e instanceof LangFlagError) {
|
|
765
|
+
error(`source remove: ${e.message}`);
|
|
766
|
+
return 2;
|
|
767
|
+
}
|
|
768
|
+
throw e;
|
|
769
|
+
}
|
|
770
|
+
const locale = await resolveWorkspaceLocale({ flag: langState.flag, cwd, warn: error });
|
|
771
|
+
const t = createTranslator(locale);
|
|
813
772
|
let parsed;
|
|
814
773
|
try {
|
|
815
|
-
parsed = parseRemoveArgs(
|
|
774
|
+
parsed = parseRemoveArgs(langState.rest);
|
|
816
775
|
}
|
|
817
776
|
catch (e) {
|
|
818
777
|
error(`source remove: ${e instanceof Error ? e.message : String(e)}`);
|
|
819
778
|
return 2;
|
|
820
779
|
}
|
|
821
780
|
if (parsed.help) {
|
|
822
|
-
printRemoveHelp(log);
|
|
781
|
+
printRemoveHelp(t, log);
|
|
823
782
|
return 0;
|
|
824
783
|
}
|
|
825
784
|
if (!parsed.id) {
|
|
826
|
-
error("source
|
|
827
|
-
printRemoveHelp(error);
|
|
785
|
+
error(t("cli.source.missingId", { sub: "remove" }));
|
|
786
|
+
printRemoveHelp(t, error);
|
|
828
787
|
return 2;
|
|
829
788
|
}
|
|
830
789
|
if (!isSafeSourceId(parsed.id)) {
|
|
831
|
-
error(
|
|
790
|
+
error(t("cli.source.invalidId", { sub: "remove", id: parsed.id }));
|
|
832
791
|
return 2;
|
|
833
792
|
}
|
|
834
793
|
const file = sourceFile(cwd, parsed.id);
|
|
835
794
|
if (!(await pathExists(file))) {
|
|
836
|
-
error(
|
|
795
|
+
error(t("cli.source.removeNotFound", { id: parsed.id }));
|
|
837
796
|
return 1;
|
|
838
797
|
}
|
|
839
798
|
await unlink(file);
|
|
840
|
-
log(
|
|
799
|
+
log(t("cli.source.deleted", { id: parsed.id }));
|
|
841
800
|
return 0;
|
|
842
801
|
}
|
|
843
802
|
/**
|
|
@@ -869,25 +828,38 @@ export async function testSource(args, options = {}) {
|
|
|
869
828
|
const log = options.io?.log ?? ((m) => console.log(m));
|
|
870
829
|
const warn = options.io?.warn ?? ((m) => console.warn(m));
|
|
871
830
|
const error = options.io?.error ?? ((m) => console.error(m));
|
|
831
|
+
let langState;
|
|
832
|
+
try {
|
|
833
|
+
langState = parseLangFlag(args);
|
|
834
|
+
}
|
|
835
|
+
catch (e) {
|
|
836
|
+
if (e instanceof LangFlagError) {
|
|
837
|
+
error(`source test: ${e.message}`);
|
|
838
|
+
return 2;
|
|
839
|
+
}
|
|
840
|
+
throw e;
|
|
841
|
+
}
|
|
842
|
+
const locale = await resolveWorkspaceLocale({ flag: langState.flag, cwd, warn: error });
|
|
843
|
+
const t = createTranslator(locale);
|
|
872
844
|
let parsed;
|
|
873
845
|
try {
|
|
874
|
-
parsed = parseTestArgs(
|
|
846
|
+
parsed = parseTestArgs(langState.rest);
|
|
875
847
|
}
|
|
876
848
|
catch (e) {
|
|
877
849
|
error(`source test: ${e instanceof Error ? e.message : String(e)}`);
|
|
878
850
|
return 2;
|
|
879
851
|
}
|
|
880
852
|
if (parsed.help) {
|
|
881
|
-
printTestHelp(log);
|
|
853
|
+
printTestHelp(t, log);
|
|
882
854
|
return 0;
|
|
883
855
|
}
|
|
884
856
|
if (!parsed.id) {
|
|
885
|
-
error("source
|
|
886
|
-
printTestHelp(error);
|
|
857
|
+
error(t("cli.source.missingId", { sub: "test" }));
|
|
858
|
+
printTestHelp(t, error);
|
|
887
859
|
return 2;
|
|
888
860
|
}
|
|
889
861
|
if (!isSafeSourceId(parsed.id)) {
|
|
890
|
-
error(
|
|
862
|
+
error(t("cli.source.invalidId", { sub: "test", id: parsed.id }));
|
|
891
863
|
return 2;
|
|
892
864
|
}
|
|
893
865
|
// Check the YAML exists *before* delegating to watchRun. `watchRun` would
|
|
@@ -896,7 +868,7 @@ export async function testSource(args, options = {}) {
|
|
|
896
868
|
// the user typed the id explicitly.
|
|
897
869
|
const file = sourceFile(cwd, parsed.id);
|
|
898
870
|
if (!(await pathExists(file))) {
|
|
899
|
-
error(
|
|
871
|
+
error(t("cli.source.testNotFound", { id: parsed.id }));
|
|
900
872
|
return 1;
|
|
901
873
|
}
|
|
902
874
|
const limit = parsed.limit ?? 10;
|
|
@@ -918,6 +890,9 @@ export async function testSource(args, options = {}) {
|
|
|
918
890
|
warn,
|
|
919
891
|
error,
|
|
920
892
|
progress,
|
|
893
|
+
// Localize the watch-flow progress markers on the same path as the
|
|
894
|
+
// reporter (#337).
|
|
895
|
+
translate: t,
|
|
921
896
|
});
|
|
922
897
|
}
|
|
923
898
|
catch (e) {
|
|
@@ -934,8 +909,8 @@ export async function testSource(args, options = {}) {
|
|
|
934
909
|
const fetched = stats?.fetched ?? 0;
|
|
935
910
|
const filtered = stats?.filtered ?? matched.length;
|
|
936
911
|
log("");
|
|
937
|
-
log(
|
|
938
|
-
log(
|
|
912
|
+
log(t("cli.source.testHeading", { id: parsed.id }));
|
|
913
|
+
log(t("cli.source.testCounts", { fetched, filtered, matched: matched.length }));
|
|
939
914
|
// Facet sweep notice (#256). A dry-run `source test` probes exactly ONE
|
|
940
915
|
// facet value, so keyword verification only reflects that single slice. We
|
|
941
916
|
// surface this as a non-fatal warning regardless of --show-content because
|
|
@@ -945,8 +920,11 @@ export async function testSource(args, options = {}) {
|
|
|
945
920
|
// facet values were not walked.
|
|
946
921
|
const facetSweep = result.diag[parsed.id]?.facetSweep;
|
|
947
922
|
if (facetSweep) {
|
|
948
|
-
warn(
|
|
949
|
-
|
|
923
|
+
warn(t("cli.source.facetSweepNotice", {
|
|
924
|
+
facet: facetSweep.facet,
|
|
925
|
+
testedValue: facetSweep.testedValue,
|
|
926
|
+
totalValues: facetSweep.totalValues,
|
|
927
|
+
}));
|
|
950
928
|
}
|
|
951
929
|
// Render the adapter diag for `kind: json-api` when --show-content is on.
|
|
952
930
|
// The diag block is intentionally gated behind --show-content so the
|
|
@@ -958,58 +936,69 @@ export async function testSource(args, options = {}) {
|
|
|
958
936
|
if (diag) {
|
|
959
937
|
if (diag.selectorAdoption) {
|
|
960
938
|
log("");
|
|
961
|
-
log("
|
|
939
|
+
log(t("cli.source.selectorAdoptionHeading"));
|
|
962
940
|
for (const [field, path] of Object.entries(diag.selectorAdoption)) {
|
|
963
941
|
if (path === null) {
|
|
964
|
-
log(
|
|
942
|
+
log(t("cli.source.selectorNoCandidate", { field }));
|
|
965
943
|
}
|
|
966
944
|
else {
|
|
967
|
-
log(
|
|
945
|
+
log(t("cli.source.selectorAdopted", { field, path }));
|
|
968
946
|
}
|
|
969
947
|
}
|
|
970
948
|
}
|
|
971
949
|
if (diag.paginationPreview) {
|
|
972
950
|
const p = diag.paginationPreview;
|
|
973
951
|
log("");
|
|
974
|
-
log(
|
|
975
|
-
log(
|
|
976
|
-
log(
|
|
952
|
+
log(t("cli.source.paginationPreviewHeading"));
|
|
953
|
+
log(t("cli.source.paginationStrategy", { strategy: p.strategy }));
|
|
954
|
+
log(t("cli.source.paginationNextUrl", {
|
|
955
|
+
nextUrl: p.nextUrl ?? t("cli.source.paginationEndOfPagination"),
|
|
956
|
+
}));
|
|
977
957
|
if (p.linkHeaderNext !== undefined) {
|
|
978
|
-
log(
|
|
958
|
+
log(t("cli.source.paginationLinkNext", {
|
|
959
|
+
value: p.linkHeaderNext ?? t("cli.source.paginationAbsent"),
|
|
960
|
+
}));
|
|
979
961
|
}
|
|
980
962
|
if (p.nextCursor !== undefined) {
|
|
981
|
-
log(
|
|
963
|
+
log(t("cli.source.paginationNextCursor", {
|
|
964
|
+
value: p.nextCursor ?? t("cli.source.paginationAbsent"),
|
|
965
|
+
}));
|
|
982
966
|
}
|
|
983
967
|
}
|
|
984
968
|
}
|
|
985
969
|
}
|
|
986
970
|
if (matched.length === 0) {
|
|
987
|
-
log(
|
|
971
|
+
log(t("cli.source.testNoMatched"));
|
|
988
972
|
return 0;
|
|
989
973
|
}
|
|
990
974
|
const shown = matched.slice(0, limit);
|
|
975
|
+
const none = t("cli.source.valueNone");
|
|
991
976
|
log("");
|
|
992
|
-
log(
|
|
977
|
+
log(t("cli.source.testShowing", { shown: shown.length, total: matched.length }));
|
|
993
978
|
for (let i = 0; i < shown.length; i++) {
|
|
994
979
|
const item = shown[i];
|
|
995
980
|
if (!item)
|
|
996
981
|
continue;
|
|
997
982
|
log("");
|
|
998
|
-
log(
|
|
999
|
-
log(
|
|
1000
|
-
log(
|
|
983
|
+
log(t("cli.source.testItemTitle", { index: i + 1, title: item.title }));
|
|
984
|
+
log(t("cli.source.testItemUrl", { url: item.url }));
|
|
985
|
+
log(t("cli.source.testItemMatchedKeywords", {
|
|
986
|
+
value: item.matchedKeywords.length > 0 ? item.matchedKeywords.join(",") : none,
|
|
987
|
+
}));
|
|
1001
988
|
if (parsed.showContent) {
|
|
1002
989
|
const body = item.summary && item.summary.length > 0
|
|
1003
990
|
? item.summary
|
|
1004
991
|
: typeof item.raw === "string"
|
|
1005
992
|
? item.raw
|
|
1006
993
|
: "";
|
|
1007
|
-
log(
|
|
994
|
+
log(t("cli.source.testItemContent", {
|
|
995
|
+
value: body.length > 0 ? truncatePreview(body, 200) : none,
|
|
996
|
+
}));
|
|
1008
997
|
}
|
|
1009
998
|
}
|
|
1010
999
|
if (matched.length > shown.length) {
|
|
1011
1000
|
log("");
|
|
1012
|
-
log(
|
|
1001
|
+
log(t("cli.source.testMoreItems", { count: matched.length - shown.length }));
|
|
1013
1002
|
}
|
|
1014
1003
|
return 0;
|
|
1015
1004
|
}
|
|
@@ -1027,14 +1016,28 @@ export async function testSource(args, options = {}) {
|
|
|
1027
1016
|
* the recipe library is empty.
|
|
1028
1017
|
*/
|
|
1029
1018
|
export async function recipesSubcommand(args, options = {}) {
|
|
1019
|
+
const cwd = options.cwd ?? process.cwd();
|
|
1030
1020
|
const log = options.io?.log ?? ((m) => console.log(m));
|
|
1031
1021
|
const error = options.io?.error ?? ((m) => console.error(m));
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1022
|
+
let langState;
|
|
1023
|
+
try {
|
|
1024
|
+
langState = parseLangFlag(args);
|
|
1025
|
+
}
|
|
1026
|
+
catch (e) {
|
|
1027
|
+
if (e instanceof LangFlagError) {
|
|
1028
|
+
error(`source recipes: ${e.message}`);
|
|
1029
|
+
return 2;
|
|
1030
|
+
}
|
|
1031
|
+
throw e;
|
|
1032
|
+
}
|
|
1033
|
+
const locale = await resolveWorkspaceLocale({ flag: langState.flag, cwd, warn: error });
|
|
1034
|
+
const t = createTranslator(locale);
|
|
1035
|
+
// The only flag accepted today is `-h` / `--help` (plus the already-stripped
|
|
1036
|
+
// `--lang`). Keep the parser tiny rather than introducing a typed args struct
|
|
1037
|
+
// for a single option — easier to extend if/when filters land.
|
|
1038
|
+
for (const a of langState.rest) {
|
|
1036
1039
|
if (a === "-h" || a === "--help") {
|
|
1037
|
-
printRecipesHelp(log);
|
|
1040
|
+
printRecipesHelp(t, log);
|
|
1038
1041
|
return 0;
|
|
1039
1042
|
}
|
|
1040
1043
|
if (a.startsWith("--")) {
|
|
@@ -1053,7 +1056,7 @@ export async function recipesSubcommand(args, options = {}) {
|
|
|
1053
1056
|
return 1;
|
|
1054
1057
|
}
|
|
1055
1058
|
if (entries.length === 0) {
|
|
1056
|
-
log("source
|
|
1059
|
+
log(t("cli.source.recipesNone"));
|
|
1057
1060
|
return 0;
|
|
1058
1061
|
}
|
|
1059
1062
|
const valid = entries.filter((e) => e.recipe !== null);
|
|
@@ -1061,7 +1064,7 @@ export async function recipesSubcommand(args, options = {}) {
|
|
|
1061
1064
|
if (valid.length > 0) {
|
|
1062
1065
|
const nameWidth = Math.max(4, ...valid.map((e) => e.name.length));
|
|
1063
1066
|
const kindWidth = Math.max(4, ...valid.map((e) => (e.recipe ? e.recipe.kind.length : 0)));
|
|
1064
|
-
log(`${pad("
|
|
1067
|
+
log(`${pad(t("cli.source.recipesHeaderName"), nameWidth)} ${pad(t("cli.source.recipesHeaderKind"), kindWidth)} ${t("cli.source.recipesHeaderDescription")}`);
|
|
1065
1068
|
for (const e of valid) {
|
|
1066
1069
|
if (!e.recipe)
|
|
1067
1070
|
continue;
|
|
@@ -1070,18 +1073,21 @@ export async function recipesSubcommand(args, options = {}) {
|
|
|
1070
1073
|
}
|
|
1071
1074
|
}
|
|
1072
1075
|
else {
|
|
1073
|
-
log("source
|
|
1076
|
+
log(t("cli.source.recipesNoValid"));
|
|
1074
1077
|
}
|
|
1075
1078
|
if (invalid.length > 0) {
|
|
1076
1079
|
log("");
|
|
1077
|
-
log("
|
|
1080
|
+
log(t("cli.source.recipesErrorsHeading"));
|
|
1078
1081
|
for (const e of invalid) {
|
|
1079
|
-
log(
|
|
1082
|
+
log(t("cli.source.recipesErrorRow", {
|
|
1083
|
+
name: e.name,
|
|
1084
|
+
error: e.error ?? t("cli.source.recipesErrorUnknown"),
|
|
1085
|
+
}));
|
|
1080
1086
|
}
|
|
1081
1087
|
}
|
|
1082
1088
|
log("");
|
|
1083
|
-
log("
|
|
1084
|
-
log("
|
|
1089
|
+
log(t("cli.source.recipesApplyHeading"));
|
|
1090
|
+
log(t("cli.source.recipesApplyExample"));
|
|
1085
1091
|
// Returning 0 even when individual recipes have errors keeps the
|
|
1086
1092
|
// listing useful in CI: a single malformed recipe should not break
|
|
1087
1093
|
// the discovery command for the rest of the bundle.
|
|
@@ -1095,11 +1101,28 @@ export async function recipesSubcommand(args, options = {}) {
|
|
|
1095
1101
|
* IO sinks without spawning the full CLI.
|
|
1096
1102
|
*/
|
|
1097
1103
|
export async function runSource(args, options = {}) {
|
|
1104
|
+
const cwd = options.cwd ?? process.cwd();
|
|
1098
1105
|
const log = options.io?.log ?? ((m) => console.log(m));
|
|
1099
1106
|
const error = options.io?.error ?? ((m) => console.error(m));
|
|
1107
|
+
// Resolve the dispatcher help locale from any leading `--lang` (read-only;
|
|
1108
|
+
// each subcommand strips and resolves its own from `rest`).
|
|
1109
|
+
const dispatcherLangFlag = (() => {
|
|
1110
|
+
try {
|
|
1111
|
+
return parseLangFlag(args).flag;
|
|
1112
|
+
}
|
|
1113
|
+
catch {
|
|
1114
|
+
return undefined;
|
|
1115
|
+
}
|
|
1116
|
+
})();
|
|
1117
|
+
const dispatcherLocale = await resolveWorkspaceLocale({
|
|
1118
|
+
flag: dispatcherLangFlag,
|
|
1119
|
+
cwd,
|
|
1120
|
+
warn: error,
|
|
1121
|
+
});
|
|
1122
|
+
const t = createTranslator(dispatcherLocale);
|
|
1100
1123
|
const [sub, ...rest] = args;
|
|
1101
1124
|
if (!sub || sub === "-h" || sub === "--help" || sub === "help") {
|
|
1102
|
-
printSourceHelp(log);
|
|
1125
|
+
printSourceHelp(t, log);
|
|
1103
1126
|
return sub ? 0 : 2;
|
|
1104
1127
|
}
|
|
1105
1128
|
switch (sub) {
|
|
@@ -1114,14 +1137,15 @@ export async function runSource(args, options = {}) {
|
|
|
1114
1137
|
case "test":
|
|
1115
1138
|
return testSource(rest, options);
|
|
1116
1139
|
default:
|
|
1117
|
-
error(
|
|
1118
|
-
printSourceHelp(error);
|
|
1140
|
+
error(t("cli.source.unknownSubcommand", { sub }));
|
|
1141
|
+
printSourceHelp(t, error);
|
|
1119
1142
|
return 2;
|
|
1120
1143
|
}
|
|
1121
1144
|
}
|
|
1122
1145
|
export const sourceCommand = {
|
|
1123
1146
|
name: "source",
|
|
1124
1147
|
summary: "Manage feed sources (add | list | recipes | remove | test)",
|
|
1148
|
+
summaryKey: "cli.summary.source",
|
|
1125
1149
|
run: (args) => runSource(args),
|
|
1126
1150
|
};
|
|
1127
1151
|
//# sourceMappingURL=source.js.map
|