felo-ai 0.2.17 → 0.2.18

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/CHANGELOG.md CHANGED
@@ -5,6 +5,19 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.2.18] - 2026-03-14
9
+
10
+ ### Added
11
+
12
+ - **`felo livedoc route <id>`**: add `route` subcommand to CLI for routing relevant resource IDs by query; supports `--max-resources` flag
13
+ - **`felo livedoc retrieve` `--resource-ids`**: add `--resource-ids` option to search within specific resources (comma-separated)
14
+
15
+ ### Fixed
16
+
17
+ - Fix `retrieve` request body field from `content` to `query`
18
+
19
+ ---
20
+
8
21
  ## [0.2.17] - 2026-03-14
9
22
 
10
23
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "felo-ai",
3
- "version": "0.2.17",
3
+ "version": "0.2.18",
4
4
  "description": "Felo AI CLI - real-time search, PPT generation, SuperAgent conversation, LiveDoc management, web fetch, YouTube subtitles, LiveDoc knowledge base, and X (Twitter) search from the terminal",
5
5
  "type": "module",
6
6
  "main": "src/cli.js",
package/src/cli.js CHANGED
@@ -640,12 +640,33 @@ livedocCmd
640
640
  .command("retrieve <short_id>")
641
641
  .description("Semantic search across resources")
642
642
  .requiredOption("--query <query>", "search query")
643
+ .option("--resource-ids <ids>", "comma-separated resource IDs to search within")
643
644
  .option("-j, --json", "output raw JSON")
644
645
  .option("-t, --timeout <seconds>", "request timeout in seconds", "60")
645
646
  .action(async (shortId, opts) => {
646
647
  const timeoutMs = parseInt(opts.timeout, 10) * 1000;
647
648
  const code = await livedoc.retrieve(shortId, {
648
649
  query: opts.query,
650
+ resourceIds: opts.resourceIds,
651
+ json: opts.json,
652
+ timeoutMs: Number.isNaN(timeoutMs) ? 60000 : timeoutMs,
653
+ });
654
+ process.exitCode = code;
655
+ flushStdioThenExit(code);
656
+ });
657
+
658
+ livedocCmd
659
+ .command("route <short_id>")
660
+ .description("Route relevant resource IDs by query")
661
+ .requiredOption("--query <query>", "routing query")
662
+ .option("--max-resources <n>", "max resources to return")
663
+ .option("-j, --json", "output raw JSON")
664
+ .option("-t, --timeout <seconds>", "request timeout in seconds", "60")
665
+ .action(async (shortId, opts) => {
666
+ const timeoutMs = parseInt(opts.timeout, 10) * 1000;
667
+ const code = await livedoc.route(shortId, {
668
+ query: opts.query,
669
+ maxResources: opts.maxResources,
649
670
  json: opts.json,
650
671
  timeoutMs: Number.isNaN(timeoutMs) ? 60000 : timeoutMs,
651
672
  });
package/src/livedoc.js CHANGED
@@ -374,6 +374,36 @@ export async function removeResource(shortId, resourceId, opts = {}) {
374
374
  } finally { stopSpinner(spinnerId); }
375
375
  }
376
376
 
377
+ export async function route(shortId, opts = {}) {
378
+ const apiKey = await getApiKey();
379
+ if (!apiKey) { console.error(NO_KEY_MESSAGE.trim()); return 1; }
380
+ if (!shortId) { process.stderr.write('ERROR: short_id is required.\n'); return 1; }
381
+ if (!opts.query) { process.stderr.write('ERROR: --query is required.\n'); return 1; }
382
+
383
+ const apiBase = await getApiBase();
384
+ const timeoutMs = opts.timeoutMs || DEFAULT_TIMEOUT_MS;
385
+ const spinnerId = startSpinner('Routing relevant resources');
386
+
387
+ try {
388
+ const body = { query: opts.query };
389
+ if (opts.maxResources) {
390
+ const n = parseInt(opts.maxResources, 10);
391
+ if (Number.isFinite(n) && n > 0) body.max_resources = n;
392
+ }
393
+ const payload = await apiRequest('POST', `/livedocs/${shortId}/resources/route`, body, apiKey, apiBase, timeoutMs);
394
+ if (opts.json) { console.log(JSON.stringify(payload, null, 2)); return 0; }
395
+
396
+ const resourceIds = payload?.data || [];
397
+ if (!resourceIds.length) { process.stderr.write('No relevant resources found.\n'); return 0; }
398
+ process.stdout.write(`Found ${resourceIds.length} relevant resource(s):\n\n`);
399
+ for (const id of resourceIds) process.stdout.write(`- ${id}\n`);
400
+ return 0;
401
+ } catch (err) {
402
+ process.stderr.write(`Failed to route resources: ${err?.message || err}\n`);
403
+ return 1;
404
+ } finally { stopSpinner(spinnerId); }
405
+ }
406
+
377
407
  export async function retrieve(shortId, opts = {}) {
378
408
  const apiKey = await getApiKey();
379
409
  if (!apiKey) { console.error(NO_KEY_MESSAGE.trim()); return 1; }
@@ -385,7 +415,10 @@ export async function retrieve(shortId, opts = {}) {
385
415
  const spinnerId = startSpinner('Retrieving from knowledge base');
386
416
 
387
417
  try {
388
- const body = { content: opts.query };
418
+ const body = { query: opts.query };
419
+ if (opts.resourceIds) {
420
+ body.resource_ids = opts.resourceIds.split(',').map(id => id.trim()).filter(Boolean);
421
+ }
389
422
  const payload = await apiRequest('POST', `/livedocs/${shortId}/resources/retrieve`, body, apiKey, apiBase, timeoutMs);
390
423
  if (opts.json) { console.log(JSON.stringify(payload, null, 2)); return 0; }
391
424