@fragno-dev/cli 0.1.13 → 0.1.15

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/dist/cli.js CHANGED
@@ -1,12 +1,18 @@
1
1
  #!/usr/bin/env node
2
- import { cli, define, parseArgs, resolveArgs } from "gunshi";
2
+ import { cli, define } from "gunshi";
3
3
  import { mkdir, writeFile } from "node:fs/promises";
4
- import { dirname, relative, resolve } from "node:path";
4
+ import { dirname, join, relative, resolve } from "node:path";
5
5
  import { executeMigrations, generateMigrationsOrSchema } from "@fragno-dev/db/generation-engine";
6
6
  import { FragnoDatabase, isFragnoDatabase } from "@fragno-dev/db";
7
7
  import { fragnoDatabaseAdapterNameFakeSymbol, fragnoDatabaseAdapterVersionFakeSymbol } from "@fragno-dev/db/adapters";
8
8
  import { instantiatedFragmentFakeSymbol } from "@fragno-dev/core/api/fragment-instantiation";
9
9
  import { loadConfig } from "c12";
10
+ import { getAllSubjects, getSubject, getSubjectChildren, getSubjectParent, getSubjects } from "@fragno-dev/corpus";
11
+ import { marked } from "marked";
12
+ import { markedTerminal } from "marked-terminal";
13
+ import { stripVTControlCharacters } from "node:util";
14
+ import { readFileSync } from "node:fs";
15
+ import { fileURLToPath } from "node:url";
10
16
 
11
17
  //#region src/utils/find-fragno-databases.ts
12
18
  async function importFragmentFile(path) {
@@ -258,76 +264,592 @@ const infoCommand = define({
258
264
  }
259
265
  });
260
266
 
267
+ //#endregion
268
+ //#region src/utils/format-search-results.ts
269
+ /**
270
+ * Merge search results by URL, grouping sections and content under each URL (without hash)
271
+ */
272
+ function mergeResultsByUrl(results, baseUrl) {
273
+ const mergedMap = /* @__PURE__ */ new Map();
274
+ for (const result of results) {
275
+ const baseUrlWithoutHash = result.url.split("#")[0];
276
+ const existing = mergedMap.get(baseUrlWithoutHash);
277
+ if (existing) existing.sections.push({
278
+ content: result.content,
279
+ type: result.type
280
+ });
281
+ else {
282
+ const urlWithMd = `${baseUrlWithoutHash}.md`;
283
+ const fullUrl = `https://${baseUrl}${baseUrlWithoutHash}`;
284
+ const fullUrlWithMd = `https://${baseUrl}${urlWithMd}`;
285
+ mergedMap.set(baseUrlWithoutHash, {
286
+ url: baseUrlWithoutHash,
287
+ urlWithMd,
288
+ fullUrl,
289
+ fullUrlWithMd,
290
+ title: result.type === "page" ? result.content : void 0,
291
+ breadcrumbs: result.breadcrumbs,
292
+ type: result.type,
293
+ sections: [{
294
+ content: result.content,
295
+ type: result.type
296
+ }]
297
+ });
298
+ }
299
+ }
300
+ return Array.from(mergedMap.values());
301
+ }
302
+ /**
303
+ * Format merged results as markdown
304
+ */
305
+ function formatAsMarkdown(mergedResults) {
306
+ const lines = [];
307
+ for (const result of mergedResults) {
308
+ const title = result.title || result.sections[0]?.content || "Untitled";
309
+ lines.push(`## Page: '${title}'`);
310
+ if (result.breadcrumbs && result.breadcrumbs.length > 0) {
311
+ lines.push(" " + result.breadcrumbs.join(" > "));
312
+ lines.push("");
313
+ }
314
+ lines.push("URLs:");
315
+ lines.push(` - ${result.fullUrl}`);
316
+ lines.push(` - ${result.fullUrlWithMd}`);
317
+ lines.push("");
318
+ if (result.sections.length > 1) {
319
+ lines.push("Relevant sections:");
320
+ for (let i = 0; i < result.sections.length; i++) {
321
+ const section = result.sections[i];
322
+ if (i === 0 && result.type === "page" && section.content === result.title) continue;
323
+ lines.push(` - ${section.content}`);
324
+ }
325
+ lines.push("");
326
+ }
327
+ lines.push("---");
328
+ lines.push("");
329
+ }
330
+ return lines.join("\n");
331
+ }
332
+ /**
333
+ * Format merged results as JSON
334
+ */
335
+ function formatAsJson(mergedResults) {
336
+ return JSON.stringify(mergedResults, null, 2);
337
+ }
338
+
339
+ //#endregion
340
+ //#region src/commands/search.ts
341
+ const searchCommand = define({
342
+ name: "search",
343
+ description: "Search the Fragno documentation",
344
+ args: {
345
+ limit: {
346
+ type: "number",
347
+ description: "Maximum number of results to show",
348
+ default: 10
349
+ },
350
+ json: {
351
+ type: "boolean",
352
+ description: "Output results in JSON format",
353
+ default: false
354
+ },
355
+ markdown: {
356
+ type: "boolean",
357
+ description: "Output results in Markdown format (default)",
358
+ default: true
359
+ },
360
+ "base-url": {
361
+ type: "string",
362
+ description: "Base URL for the documentation site",
363
+ default: "fragno.dev"
364
+ }
365
+ },
366
+ run: async (ctx) => {
367
+ const query = ctx.positionals.join(" ");
368
+ if (!query || query.trim().length === 0) throw new Error("Please provide a search query");
369
+ const jsonMode = ctx.values.json;
370
+ const baseUrl = ctx.values["base-url"];
371
+ if (!jsonMode) console.log(`Searching for: "${query}"\n`);
372
+ try {
373
+ const encodedQuery = encodeURIComponent(query);
374
+ const response = await fetch(`https://${baseUrl}/api/search?query=${encodedQuery}`);
375
+ if (!response.ok) throw new Error(`API request failed with status ${response.status}`);
376
+ const results = await response.json();
377
+ const limit = ctx.values.limit;
378
+ const limitedResults = results.slice(0, limit);
379
+ if (limitedResults.length === 0) {
380
+ if (jsonMode) console.log("[]");
381
+ else console.log("No results found.");
382
+ return;
383
+ }
384
+ const mergedResults = mergeResultsByUrl(limitedResults, baseUrl);
385
+ if (jsonMode) console.log(formatAsJson(mergedResults));
386
+ else {
387
+ console.log(`Found ${results.length} result${results.length === 1 ? "" : "s"}${results.length > limit ? ` (showing ${limit})` : ""}\n`);
388
+ console.log(formatAsMarkdown(mergedResults));
389
+ }
390
+ } catch (error) {
391
+ if (error instanceof Error) throw new Error(`Search failed: ${error.message}`);
392
+ throw new Error("Search failed: An unknown error occurred");
393
+ }
394
+ }
395
+ });
396
+
397
+ //#endregion
398
+ //#region src/commands/corpus.ts
399
+ marked.use(markedTerminal());
400
+ /**
401
+ * Build markdown content for multiple subjects
402
+ */
403
+ function buildSubjectsMarkdown(subjects) {
404
+ let fullMarkdown = "";
405
+ for (const subject of subjects) {
406
+ fullMarkdown += `# ${subject.title}\n\n`;
407
+ if (subject.description) fullMarkdown += `${subject.description}\n\n`;
408
+ if (subject.imports) fullMarkdown += `### Imports\n\n\`\`\`typescript\n${subject.imports}\n\`\`\`\n\n`;
409
+ if (subject.prelude.length > 0) {
410
+ fullMarkdown += `### Prelude\n\n`;
411
+ for (const block of subject.prelude) fullMarkdown += `\`\`\`typescript\n${block.code}\n\`\`\`\n\n`;
412
+ }
413
+ for (const section of subject.sections) fullMarkdown += `## ${section.heading}\n\n${section.content}\n\n`;
414
+ }
415
+ return fullMarkdown;
416
+ }
417
+ /**
418
+ * Add line numbers to content
419
+ */
420
+ function addLineNumbers(content, startFrom = 1) {
421
+ const lines = content.split("\n");
422
+ const maxDigits = String(startFrom + lines.length - 1).length;
423
+ return lines.map((line, index) => {
424
+ const lineNum = startFrom + index;
425
+ return `${String(lineNum).padStart(maxDigits, " ")}│ ${line}`;
426
+ }).join("\n");
427
+ }
428
+ /**
429
+ * Filter content by line range
430
+ */
431
+ function filterByLineRange(content, startLine, endLine) {
432
+ const lines = content.split("\n");
433
+ const start = Math.max(0, startLine - 1);
434
+ const end = Math.min(lines.length, endLine);
435
+ return lines.slice(start, end).join("\n");
436
+ }
437
+ /**
438
+ * Extract headings and code block information with line numbers
439
+ */
440
+ function extractHeadingsAndBlocks(subjects) {
441
+ let output = "";
442
+ let currentLine = 1;
443
+ let lastOutputLine = 0;
444
+ const addGapIfNeeded = () => {
445
+ if (lastOutputLine > 0 && currentLine > lastOutputLine + 1) output += ` │\n`;
446
+ };
447
+ output += "Use --start N --end N flags to show specific line ranges\n\n";
448
+ for (const subject of subjects) {
449
+ addGapIfNeeded();
450
+ output += `${currentLine.toString().padStart(4, " ")}│ # ${subject.title}\n`;
451
+ lastOutputLine = currentLine;
452
+ currentLine += 1;
453
+ output += `${currentLine.toString().padStart(4, " ")}│\n`;
454
+ lastOutputLine = currentLine;
455
+ currentLine += 1;
456
+ if (subject.description) {
457
+ const descLines = subject.description.split("\n");
458
+ for (const line of descLines) {
459
+ output += `${currentLine.toString().padStart(4, " ")}│ ${line}\n`;
460
+ lastOutputLine = currentLine;
461
+ currentLine += 1;
462
+ }
463
+ output += `${currentLine.toString().padStart(4, " ")}│\n`;
464
+ lastOutputLine = currentLine;
465
+ currentLine += 1;
466
+ }
467
+ if (subject.imports) {
468
+ addGapIfNeeded();
469
+ output += `${currentLine.toString().padStart(4, " ")}│ ### Imports\n`;
470
+ lastOutputLine = currentLine;
471
+ currentLine += 1;
472
+ output += `${currentLine.toString().padStart(4, " ")}│\n`;
473
+ lastOutputLine = currentLine;
474
+ currentLine += 1;
475
+ output += `${currentLine.toString().padStart(4, " ")}│ \`\`\`typescript\n`;
476
+ lastOutputLine = currentLine;
477
+ currentLine += 1;
478
+ const importLines = subject.imports.split("\n");
479
+ for (const line of importLines) {
480
+ output += `${currentLine.toString().padStart(4, " ")}│ ${line}\n`;
481
+ lastOutputLine = currentLine;
482
+ currentLine += 1;
483
+ }
484
+ output += `${currentLine.toString().padStart(4, " ")}│ \`\`\`\n`;
485
+ lastOutputLine = currentLine;
486
+ currentLine += 1;
487
+ output += `${currentLine.toString().padStart(4, " ")}│\n`;
488
+ lastOutputLine = currentLine;
489
+ currentLine += 1;
490
+ }
491
+ if (subject.prelude.length > 0) {
492
+ addGapIfNeeded();
493
+ output += `${currentLine.toString().padStart(4, " ")}│ ### Prelude\n`;
494
+ lastOutputLine = currentLine;
495
+ currentLine += 1;
496
+ output += `${currentLine.toString().padStart(4, " ")}│\n`;
497
+ lastOutputLine = currentLine;
498
+ currentLine += 1;
499
+ for (const block of subject.prelude) {
500
+ const id = block.id || "(no-id)";
501
+ const blockStartLine = currentLine + 1;
502
+ const codeLines = block.code.split("\n").length;
503
+ const blockEndLine = currentLine + 1 + codeLines;
504
+ output += `${currentLine.toString().padStart(4, " ")}│ - id: \`${id}\`, L${blockStartLine}-${blockEndLine}\n`;
505
+ lastOutputLine = currentLine;
506
+ currentLine += codeLines + 3;
507
+ }
508
+ lastOutputLine = currentLine - 1;
509
+ }
510
+ const sectionToExamples = /* @__PURE__ */ new Map();
511
+ for (const example of subject.examples) for (const section of subject.sections) if (section.content.includes(example.code.substring(0, Math.min(50, example.code.length)))) {
512
+ if (!sectionToExamples.has(section.heading)) sectionToExamples.set(section.heading, []);
513
+ sectionToExamples.get(section.heading).push(example);
514
+ break;
515
+ }
516
+ for (const section of subject.sections) {
517
+ addGapIfNeeded();
518
+ output += `${currentLine.toString().padStart(4, " ")}│ ## ${section.heading}\n`;
519
+ lastOutputLine = currentLine;
520
+ currentLine += 1;
521
+ const examples = sectionToExamples.get(section.heading) || [];
522
+ if (examples.length > 0) {
523
+ const sectionStartLine = currentLine;
524
+ const lines = section.content.split("\n");
525
+ for (const example of examples) {
526
+ const id = example.id || "(no-id)";
527
+ let blockStartLine = sectionStartLine;
528
+ let blockEndLine = sectionStartLine;
529
+ let foundBlock = false;
530
+ for (let i = 0; i < lines.length; i++) if (lines[i].trim().startsWith("```") && true) {
531
+ const codeStart = i + 1;
532
+ let matches = true;
533
+ const exampleLines = example.code.split("\n");
534
+ for (let j = 0; j < Math.min(3, exampleLines.length); j++) if (lines[codeStart + j]?.trim() !== exampleLines[j]?.trim()) {
535
+ matches = false;
536
+ break;
537
+ }
538
+ if (matches) {
539
+ blockStartLine = sectionStartLine + i + 1;
540
+ blockEndLine = sectionStartLine + i + exampleLines.length;
541
+ foundBlock = true;
542
+ break;
543
+ }
544
+ }
545
+ if (foundBlock) output += `${currentLine.toString().padStart(4, " ")}│ - id: \`${id}\`, L${blockStartLine}-${blockEndLine}\n`;
546
+ else output += `${currentLine.toString().padStart(4, " ")}│ - id: \`${id}\`\n`;
547
+ lastOutputLine = currentLine;
548
+ }
549
+ }
550
+ const sectionLines = section.content.split("\n");
551
+ for (const _line of sectionLines) currentLine += 1;
552
+ currentLine += 1;
553
+ lastOutputLine = currentLine - 1;
554
+ }
555
+ }
556
+ return output;
557
+ }
558
+ /**
559
+ * Print subjects with the given options
560
+ */
561
+ async function printSubjects(subjects, options) {
562
+ if (options.headingsOnly) {
563
+ const headingsOutput = extractHeadingsAndBlocks(subjects);
564
+ console.log(headingsOutput);
565
+ return;
566
+ }
567
+ const markdown = buildSubjectsMarkdown(subjects);
568
+ let output = await marked.parse(markdown);
569
+ const startLine = options.startLine ?? 1;
570
+ if (options.startLine !== void 0 || options.endLine !== void 0) {
571
+ const end = options.endLine ?? output.split("\n").length;
572
+ output = filterByLineRange(output, startLine, end);
573
+ }
574
+ if (options.showLineNumbers) output = addLineNumbers(output, startLine);
575
+ console.log(output);
576
+ }
577
+ /**
578
+ * Find and print code blocks by ID
579
+ */
580
+ async function printCodeBlockById(id, topics, showLineNumbers) {
581
+ const subjects = topics.length > 0 ? getSubject(...topics) : getAllSubjects();
582
+ const matches = [];
583
+ for (const subject of subjects) {
584
+ const fullMarkdown = buildSubjectsMarkdown([subject]);
585
+ const renderedLines = (await marked.parse(fullMarkdown)).split("\n");
586
+ for (const block of subject.prelude) if (block.id === id) {
587
+ let startLine;
588
+ let endLine;
589
+ const codeLines = block.code.split("\n");
590
+ const firstCodeLine = codeLines[0].trim();
591
+ for (let i = 0; i < renderedLines.length; i++) if (stripVTControlCharacters(renderedLines[i]).trim() === firstCodeLine) {
592
+ startLine = i + 1;
593
+ endLine = i + codeLines.length;
594
+ break;
595
+ }
596
+ matches.push({
597
+ subjectId: subject.id,
598
+ subjectTitle: subject.title,
599
+ section: "Prelude",
600
+ code: block.code,
601
+ type: "prelude",
602
+ startLine,
603
+ endLine
604
+ });
605
+ }
606
+ for (const example of subject.examples) if (example.id === id) {
607
+ let sectionName = "Unknown Section";
608
+ let startLine;
609
+ let endLine;
610
+ for (const section of subject.sections) if (section.content.includes(example.code.substring(0, Math.min(50, example.code.length)))) {
611
+ sectionName = section.heading;
612
+ const codeLines = example.code.split("\n");
613
+ const firstCodeLine = codeLines[0].trim();
614
+ for (let i = 0; i < renderedLines.length; i++) if (stripVTControlCharacters(renderedLines[i]).trim() === firstCodeLine) {
615
+ startLine = i + 1;
616
+ endLine = i + codeLines.length;
617
+ break;
618
+ }
619
+ break;
620
+ }
621
+ matches.push({
622
+ subjectId: subject.id,
623
+ subjectTitle: subject.title,
624
+ section: sectionName,
625
+ code: example.code,
626
+ type: "example",
627
+ startLine,
628
+ endLine
629
+ });
630
+ }
631
+ }
632
+ if (matches.length === 0) {
633
+ console.error(`Error: No code block found with id "${id}"`);
634
+ if (topics.length > 0) console.error(`Searched in topics: ${topics.join(", ")}`);
635
+ else console.error("Searched in all available topics");
636
+ process.exit(1);
637
+ }
638
+ for (let i = 0; i < matches.length; i++) {
639
+ const match = matches[i];
640
+ if (matches.length > 1 && i > 0) console.log("\n---\n");
641
+ let matchMarkdown = `# ${match.subjectTitle}\n\n`;
642
+ matchMarkdown += `## ${match.section}\n\n`;
643
+ if (showLineNumbers && match.startLine && match.endLine) console.log(`Lines ${match.startLine}-${match.endLine} (use with --start/--end)\n`);
644
+ matchMarkdown += `\`\`\`typescript\n${match.code}\n\`\`\`\n`;
645
+ const rendered = await marked.parse(matchMarkdown);
646
+ console.log(rendered);
647
+ }
648
+ }
649
+ /**
650
+ * Print information about the corpus command
651
+ */
652
+ function printCorpusHelp() {
653
+ console.log("Fragno Corpus - Code examples and documentation (similar to LLMs.txt");
654
+ console.log("");
655
+ console.log("Usage: fragno-cli corpus [options] [topic...]");
656
+ console.log("");
657
+ console.log("Options:");
658
+ console.log(" -n, --no-line-numbers Hide line numbers (shown by default)");
659
+ console.log(" -s, --start N Starting line number to display from");
660
+ console.log(" -e, --end N Ending line number to display to");
661
+ console.log(" --headings Show only headings and code block IDs");
662
+ console.log(" --id <id> Retrieve a specific code block by ID");
663
+ console.log("");
664
+ console.log("Examples:");
665
+ console.log(" fragno-cli corpus # List all available topics");
666
+ console.log(" fragno-cli corpus defining-routes # Show route definition examples");
667
+ console.log(" fragno-cli corpus --headings database-querying");
668
+ console.log(" # Show structure overview");
669
+ console.log(" fragno-cli corpus --start 10 --end 50 database-querying");
670
+ console.log(" # Show specific lines");
671
+ console.log(" fragno-cli corpus --id create-user # Get code block by ID");
672
+ console.log(" fragno-cli corpus database-adapters kysely-adapter");
673
+ console.log(" # Show multiple topics");
674
+ console.log("");
675
+ console.log("Available topics:");
676
+ const subjects = getSubjects();
677
+ const rootSubjects = [];
678
+ const subjectMap = new Map(subjects.map((s) => [s.id, s]));
679
+ for (const subject of subjects) if (!getSubjectParent(subject.id)) {
680
+ const children = getSubjectChildren(subject.id);
681
+ rootSubjects.push({
682
+ id: subject.id,
683
+ title: subject.title,
684
+ children: children.map((childId) => ({
685
+ id: childId,
686
+ title: subjectMap.get(childId)?.title || childId
687
+ }))
688
+ });
689
+ }
690
+ for (const root of rootSubjects) {
691
+ console.log(` ${root.id.padEnd(30)} ${root.title}`);
692
+ for (let i = 0; i < root.children.length; i++) {
693
+ const child = root.children[i];
694
+ const connector = i === root.children.length - 1 ? "└─" : "├─";
695
+ console.log(` ${connector} ${child.id.padEnd(26)} ${child.title}`);
696
+ }
697
+ }
698
+ }
699
+ const corpusCommand = define({
700
+ name: "corpus",
701
+ description: "View code examples and documentation for Fragno",
702
+ args: {
703
+ "no-line-numbers": {
704
+ type: "boolean",
705
+ short: "n",
706
+ description: "Hide line numbers (line numbers are shown by default)"
707
+ },
708
+ start: {
709
+ type: "number",
710
+ short: "s",
711
+ description: "Starting line number (1-based) to display from"
712
+ },
713
+ end: {
714
+ type: "number",
715
+ short: "e",
716
+ description: "Ending line number (1-based) to display to"
717
+ },
718
+ headings: {
719
+ type: "boolean",
720
+ description: "Show only section headings and code block IDs with line numbers"
721
+ },
722
+ id: {
723
+ type: "string",
724
+ description: "Retrieve a specific code block by ID"
725
+ }
726
+ },
727
+ run: async (ctx) => {
728
+ const topics = ctx.positionals;
729
+ const showLineNumbers = !(ctx.values["no-line-numbers"] ?? false);
730
+ const startLine = ctx.values.start;
731
+ const endLine = ctx.values.end;
732
+ const headingsOnly = ctx.values.headings ?? false;
733
+ const codeBlockId = ctx.values.id;
734
+ if (codeBlockId) {
735
+ await printCodeBlockById(codeBlockId, topics, showLineNumbers);
736
+ return;
737
+ }
738
+ if (topics.length === 0) {
739
+ printCorpusHelp();
740
+ return;
741
+ }
742
+ if (startLine !== void 0 && endLine !== void 0 && startLine > endLine) {
743
+ console.error("Error: --start must be less than or equal to --end");
744
+ process.exit(1);
745
+ }
746
+ try {
747
+ await printSubjects(getSubject(...topics), {
748
+ showLineNumbers,
749
+ startLine,
750
+ endLine,
751
+ headingsOnly
752
+ });
753
+ } catch (error) {
754
+ console.error("Error loading topics:", error instanceof Error ? error.message : error);
755
+ console.log("\nRun 'fragno-cli corpus' to see available topics.");
756
+ process.exit(1);
757
+ }
758
+ }
759
+ });
760
+
261
761
  //#endregion
262
762
  //#region src/cli.ts
763
+ const __dirname = dirname(fileURLToPath(import.meta.url));
764
+ const version = JSON.parse(readFileSync(join(__dirname, "../package.json"), "utf-8")).version;
263
765
  const dbSubCommands = /* @__PURE__ */ new Map();
264
766
  dbSubCommands.set("generate", generateCommand);
265
767
  dbSubCommands.set("migrate", migrateCommand);
266
768
  dbSubCommands.set("info", infoCommand);
267
- function printDbHelp() {
268
- console.log("Database management commands for Fragno");
269
- console.log("");
270
- console.log("Usage: fragno-cli db <command> [options]");
271
- console.log("");
272
- console.log("Commands:");
273
- console.log(" generate Generate schema files from FragnoDatabase definitions");
274
- console.log(" migrate Run database migrations");
275
- console.log(" info Display database information and migration status");
276
- console.log("");
277
- console.log("Run 'fragno-cli db <command> --help' for more information.");
278
- }
279
769
  const dbCommand = define({
280
770
  name: "db",
281
- description: "Database management commands",
282
- run: printDbHelp
771
+ description: "Database management commands"
283
772
  });
284
- const rootSubCommands = /* @__PURE__ */ new Map();
285
- rootSubCommands.set("db", dbCommand);
286
773
  const mainCommand = define({
287
774
  name: "fragno-cli",
288
- description: "Fragno CLI - Tools for working with Fragno fragments",
289
- run: () => {
290
- console.log("Fragno CLI - Tools for working with Fragno fragments");
291
- console.log("");
292
- console.log("Usage: fragno-cli <command> [options]");
293
- console.log("");
294
- console.log("Commands:");
295
- console.log(" db Database management commands");
296
- console.log("");
297
- console.log("Run 'fragno-cli <command> --help' for more information.");
298
- }
775
+ description: "Tools for working with Fragno fragments"
299
776
  });
300
777
  if (import.meta.main) try {
301
778
  const args = process.argv.slice(2);
302
- if (args[0] === "db" && args.length > 1) {
779
+ if (args[0] === "search") await cli(args.slice(1), searchCommand, {
780
+ name: "fragno-cli search",
781
+ version
782
+ });
783
+ else if (args[0] === "corpus") await cli(args.slice(1), corpusCommand, {
784
+ name: "fragno-cli corpus",
785
+ version
786
+ });
787
+ else if (args[0] === "db") {
303
788
  const subCommandName = args[1];
304
- if (subCommandName === "--help" || subCommandName === "-h") {
305
- printDbHelp();
306
- process.exit(0);
307
- }
308
- const subCommand = dbSubCommands.get(subCommandName);
309
- if (!subCommand) {
310
- console.error(`Unknown command: ${subCommandName}`);
789
+ if (!subCommandName || subCommandName === "--help" || subCommandName === "-h") {
790
+ console.log("Database management commands");
311
791
  console.log("");
312
- printDbHelp();
313
- process.exit(1);
314
- }
315
- const subArgs = args.slice(2);
316
- const isSubCommandHelp = subArgs.includes("--help") || subArgs.includes("-h");
317
- let hasValidationError = false;
318
- if (!isSubCommandHelp && subCommand.args) {
319
- const tokens = parseArgs(subArgs);
320
- hasValidationError = !!resolveArgs(subCommand.args, tokens).error;
792
+ console.log("USAGE:");
793
+ console.log(" fragno-cli db <COMMAND>");
794
+ console.log("");
795
+ console.log("COMMANDS:");
796
+ console.log(" generate Generate schema files from FragnoDatabase definitions");
797
+ console.log(" migrate Run database migrations");
798
+ console.log(" info Display database information and migration status");
799
+ console.log("");
800
+ console.log("For more info, run any command with the `--help` flag:");
801
+ console.log(" fragno-cli db generate --help");
802
+ console.log(" fragno-cli db migrate --help");
803
+ console.log(" fragno-cli db info --help");
804
+ console.log("");
805
+ console.log("OPTIONS:");
806
+ console.log(" -h, --help Display this help message");
807
+ console.log(" -v, --version Display this version");
808
+ } else if (subCommandName === "--version" || subCommandName === "-v") console.log(version);
809
+ else {
810
+ const subCommand = dbSubCommands.get(subCommandName);
811
+ if (!subCommand) {
812
+ console.error(`Unknown command: ${subCommandName}`);
813
+ console.log("");
814
+ console.log("Run 'fragno-cli db --help' for available commands.");
815
+ process.exit(1);
816
+ }
817
+ await cli(args.slice(2), subCommand, {
818
+ name: `fragno-cli db ${subCommandName}`,
819
+ version
820
+ });
321
821
  }
322
- await cli(subArgs, subCommand);
323
- if (hasValidationError) process.exit(1);
324
- } else if (args[0] === "db") printDbHelp();
325
- else await cli(args, mainCommand, { subCommands: rootSubCommands });
822
+ } else if (!args.length || args[0] === "--help" || args[0] === "-h") {
823
+ console.log("Tools for working with Fragno");
824
+ console.log("");
825
+ console.log("USAGE:");
826
+ console.log(" fragno-cli <COMMAND>");
827
+ console.log("");
828
+ console.log("COMMANDS:");
829
+ console.log(" db Database management commands");
830
+ console.log(" search Search the Fragno documentation");
831
+ console.log(" corpus View code examples and documentation for Fragno");
832
+ console.log("");
833
+ console.log("For more info, run any command with the `--help` flag:");
834
+ console.log(" fragno-cli db --help");
835
+ console.log(" fragno-cli search --help");
836
+ console.log(" fragno-cli corpus --help");
837
+ console.log("");
838
+ console.log("OPTIONS:");
839
+ console.log(" -h, --help Display this help message");
840
+ console.log(" -v, --version Display this version");
841
+ } else if (args[0] === "--version" || args[0] === "-v") console.log(version);
842
+ else {
843
+ console.error(`Unknown command: ${args[0]}`);
844
+ console.log("");
845
+ console.log("Run 'fragno-cli --help' for available commands.");
846
+ process.exit(1);
847
+ }
326
848
  } catch (error) {
327
849
  console.error("Error:", error instanceof Error ? error.message : error);
328
850
  process.exit(1);
329
851
  }
330
852
 
331
853
  //#endregion
332
- export { dbCommand, generateCommand, infoCommand, mainCommand, migrateCommand };
854
+ export { corpusCommand, dbCommand, generateCommand, infoCommand, mainCommand, migrateCommand, searchCommand };
333
855
  //# sourceMappingURL=cli.js.map