Преглед изворни кода

cli: chatto date format configurable via CHEAPO_DATE_FORMAT (default compact 02.01.)

Paul Klumpp пре 2 дана
родитељ
комит
93b891efb4
5 измењених фајлова са 23 додато и 8 уклоњено
  1. 7 0
      .env.example
  2. 5 0
      AGENTS.md
  3. 7 4
      cmd/cheapo/chatto.go
  4. 3 3
      cmd/cheapo/main.go
  5. 1 1
      internal/mcpserver/mcpserver.go

+ 7 - 0
.env.example

@@ -0,0 +1,7 @@
+# .env in the project root (godotenv). Never commit the real .env file.
+CHATTO_TOKEN="<token>"               # set by the operator
+# CHATTO_BASE_URL=https://chat.chatto.run   # optional, is the default
+
+# Date format for chatto-send output (Go time layout). Default: 02.01.
+# CHEAPO_DATE_FORMAT=02.01.2006 15:04
+CHEAPO_DATE_FORMAT=02.01.

+ 5 - 0
AGENTS.md

@@ -96,6 +96,11 @@ How it gets the info:
   `internal/mcpserver`.
 - User-facing strings in English (CLI output, help texts, error messages),
   code comments in English.
+- **Unambiguous date outputs:** prefer ISO-8601 (RFC-3339 / `2006-01-02`)
+  for machine-readable/structured surfaces (CLI `--json`, MCP `offer` wire type);
+  compact locale-style formats (e.g. `02.01.`) are only for human-facing chat
+  messages and must be overridable via `CHEAPO_DATE_FORMAT`. Avoid ambiguous
+  `DD.MM.`/`MM/DD` outputs without a year.
 - Wrap errors with context: `fmt.Errorf("epic: ...: %w", err)`.
 - New store platforms (Prime, GOG, …) follow the provider pattern (above).
 - **Chatto client:** `internal/chatto` is a hand-built Connect-JSON client

+ 7 - 4
cmd/cheapo/chatto.go

@@ -64,19 +64,22 @@ func formatGames(games []game.Game, mode string) string {
 	b.WriteString("| Game | Store | Price | Period |\n")
 	b.WriteString("|---|---|---|---|\n")
 	for _, g := range games {
+		dateFmt := os.Getenv("CHEAPO_DATE_FORMAT")
+		if dateFmt == "" {
+			dateFmt = "02.01."
+		}
 		period := "—"
 		if g.Kind == "upcoming" && !g.StartDate.IsZero() && !g.EndDate.IsZero() {
 			period = fmt.Sprintf("from %s, until %s",
-				g.StartDate.Local().Format("02.01."),
-				g.EndDate.Local().Format("02.01."))
+				g.StartDate.Local().Format(dateFmt),
+				g.EndDate.Local().Format(dateFmt))
 		} else if !g.EndDate.IsZero() {
-			period = "until " + g.EndDate.Local().Format("02.01.")
+			period = "until " + g.EndDate.Local().Format(dateFmt)
 		}
 		fmt.Fprintf(&b, "| **%s** | [%s](%s) | %s | %s |\n",
 			escapePipe(g.Title), g.Store, g.URL, priceCell(g), period)
 	}
 
-	b.WriteString("\n_As of now — free from/until 17:00 Europe/Berlin each._")
 	return b.String()
 }
 

+ 3 - 3
cmd/cheapo/main.go

@@ -41,8 +41,8 @@ References: https://github.com/vogler/free-games-claimer
 		SilenceUsage: true,
 	}
 
-	root.PersistentFlags().StringVar(&flagCountry, "country", "DE", "ISO country code for store region (epic)")
-	root.PersistentFlags().StringVar(&flagLocale, "locale", "de", "store locale (e.g. de, en-US)")
+	root.PersistentFlags().StringVar(&flagCountry, "country", "DE", "ISO country code for store region; determines currency/availability (epic only)")
+	root.PersistentFlags().StringVar(&flagLocale, "locale", "de", "display locale for Epic (formatting only, e.g. de -> '22,39 €', en-US -> '€22.39'; currency comes from --country)")
 	root.PersistentFlags().BoolVar(&flagJSON, "json", false, "output as JSON")
 	root.PersistentFlags().StringVar(&flagStore, "store", "all", "which store(s): epic, steam, gog, all")
 
@@ -113,7 +113,7 @@ func printGames(cmd *cobra.Command, games []game.Game) error {
 				g.StartDate.Local().Format("02.01.2006 15:04"),
 				g.EndDate.Local().Format("02.01.2006 15:04"))
 		} else if !g.EndDate.IsZero() {
-			fmt.Fprintf(out, "   Free until: %s\n", g.EndDate.Local().Format("02.01.2006 15:04 (MST)"))
+			fmt.Fprintf(out, "   Free until: %s\n", g.EndDate.UTC().Format(time.RFC3339))
 		}
 		fmt.Fprintf(out, "   %s\n", g.URL)
 		fmt.Fprintln(out)

+ 1 - 1
internal/mcpserver/mcpserver.go

@@ -217,7 +217,7 @@ type listArgs struct {
 	Mode    string `json:"mode,omitempty" jsonschema:"what to list: free (current giveaways, default), upcoming (announced future Epic giveaways) or deals (discounted games)"`
 	Store   string `json:"store,omitempty" jsonschema:"which store: epic, steam, gog or all (default all)"`
 	Country string `json:"country,omitempty" jsonschema:"ISO country code for the Epic store region, e.g. DE (default DE)"`
-	Locale  string `json:"locale,omitempty" jsonschema:"store locale, e.g. de or en-US (default de)"`
+	Locale  string `json:"locale,omitempty" jsonschema:"Epic display locale (formatting only, e.g. de -> '22,39 €', en-US -> '€22.39'; currency comes from country)"`
 }
 
 // offer is the wire form of game.Game. It exists because game.Game marshals