···30### First Steps
3132For a comprehensive walkthrough including task management, time tracking, notes, and media tracking, see the [Quickstart Guide](website/docs/Quickstart.md).
00000000000000000000000000000000000000000000000000
···30### First Steps
3132For a comprehensive walkthrough including task management, time tracking, notes, and media tracking, see the [Quickstart Guide](website/docs/Quickstart.md).
33+34+## Development
35+36+Noteleaf uses [Task](https://taskfile.dev) for build automation. Development builds include additional tooling commands not available in production builds.
37+38+### Building
39+40+```sh
41+# Production build
42+task build
43+44+# Development build (with version info and dev tools)
45+task build:dev
46+47+# Run tests
48+task test
49+task cov # ...with coverage
50+```
51+52+### Development Tools
53+54+Dev builds (`task build:dev`) include a `tools` subcommand with maintenance utilities:
55+56+**Documentation Generation:**
57+58+```sh
59+# Generate Docusaurus documentation
60+noteleaf tools docgen --format docusaurus --out website/docs/manual
61+62+# Generate man pages
63+noteleaf tools docgen --format man --out docs/manual
64+```
65+66+**Data Synchronization:**
67+68+```sh
69+# Fetch Leaflet lexicons from GitHub
70+noteleaf tools fetch lexicons
71+72+# Fetch from a specific commit
73+noteleaf tools fetch lexicons --sha abc123def
74+75+# Generic GitHub repository archive fetcher
76+noteleaf tools fetch gh-repo \
77+ --repo owner/repo \
78+ --path schemas/ \
79+ --output local/schemas/
80+```
81+82+Production builds (`task build:rc`, `task build:prod`) use the `-tags prod` flag to exclude dev tools.
···1+//go:build !prod
2+3+package main
4+5+import (
6+ "github.com/spf13/cobra"
7+ "github.com/stormlightlabs/noteleaf/tools"
8+)
9+10+// registerTools adds development tools to the root command
11+func registerTools(root *cobra.Command) {
12+ root.AddCommand(tools.NewToolsCommand(root))
13+}
+8
cmd/tools_prod.go
···00000000
···1+//go:build prod
2+3+package main
4+5+import "github.com/spf13/cobra"
6+7+// registerTools is a no-op in production builds
8+func registerTools(*cobra.Command) {}
+3-6
tools/docgen.go
···001package tools
23import (
···324 }
325326 for _, cmd := range root.Commands() {
327- if cmd.Name() == path[0] || contains(cmd.Aliases, path[0]) {
328 if len(path) == 1 {
329 return cmd
330 }
···334335 return nil
336}
337-338-// contains checks if a string is in a slice
339-func contains(slice []string, str string) bool {
340- return slices.Contains(slice, str)
341-}
···1+//go:build !prod
2+3+package tools
4+5+import (
6+ "context"
7+8+ "github.com/spf13/cobra"
9+)
10+11+// NewLexiconsCommand creates a command for fetching Leaflet lexicons
12+func NewLexiconsCommand() *cobra.Command {
13+ var sha string
14+ var output string
15+16+ cmd := &cobra.Command{
17+ Use: "lexicons",
18+ Short: "Fetch Leaflet lexicons from GitHub",
19+ Long: `Fetches Leaflet lexicons from the hyperlink-academy/leaflet repository.
20+21+This is a convenience wrapper around gh-repo with pre-configured defaults
22+for the Leaflet lexicon repository.`,
23+ Example: ` # Fetch latest lexicons
24+ noteleaf tools fetch lexicons
25+26+ # Fetch from a specific commit
27+ noteleaf tools fetch lexicons --sha abc123def
28+29+ # Fetch to a custom directory
30+ noteleaf tools fetch lexicons --output ./tmp/lexicons`,
31+ RunE: func(cmd *cobra.Command, args []string) error {
32+ config := ArchiveConfig{
33+ Repo: "hyperlink-academy/leaflet",
34+ Path: "lexicons/pub/leaflet/",
35+ Output: output,
36+ SHA: sha,
37+ FormatJSON: true,
38+ }
39+40+ ctx := cmd.Context()
41+ if ctx == nil {
42+ ctx = context.Background()
43+ }
44+45+ return fetchAndExtractArchive(ctx, config, cmd.OutOrStdout())
46+ },
47+ }
48+ cmd.Flags().StringVar(&sha, "sha", "", "Specific commit SHA (default: latest)")
49+ cmd.Flags().StringVar(&output, "output", "lexdocs/leaflet/", "Output directory for lexicons")
50+ return cmd
51+}
+19
tools/registry.go
···0000000000000000000
···1+//go:build !prod
2+3+package tools
4+5+import "github.com/spf13/cobra"
6+7+// NewToolsCommand creates a parent command for all development tools
8+func NewToolsCommand(root *cobra.Command) *cobra.Command {
9+ cmd := &cobra.Command{
10+ Use: "tools",
11+ Short: "Development and maintenance tools",
12+ Long: `Development tools for documentation generation, data synchronization,
13+and maintenance tasks. These commands are only available in dev builds.`,
14+ }
15+ cmd.AddCommand(NewDocGenCommand(root))
16+ cmd.AddCommand(NewFetchCommand())
17+18+ return cmd
19+}