Skip to content

Conversation

@zokhcat
Copy link
Contributor

@zokhcat zokhcat commented Sep 8, 2025

Summary by CodeRabbit

  • New Features

    • Added top-level "category" command with subcommands: list, pull, push, commit.
    • list: view categories for a workspace and mode (default: live) with structured output.
    • pull: download workspace categories to local JSON.
    • push: upload local categories to a workspace.
    • commit: finalize categories for a workspace with optional commit message.
    • Interactive progress indicators when running commands interactively.
  • Other

    • Category assets now supported in sync flow.
    • Reduced sensitive info in debug logs.
  • Documentation

    • New docs for category commands; removed autogenerated timestamps.
  • Chores

    • Dependency upgrades (viper and indirect modules).

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 8, 2025

Walkthrough

Adds a new "category" CLI group with list/pull/push/commit subcommands, JSON file helpers, management client models and APIs for preference categories, sync integration for categories, root command registration, documentation pages, and dependency updates.

Changes

Cohort / File(s) Summary
CLI: category command group
internal/commands/category/category.go, internal/commands/category/category_list.go, internal/commands/category/category_pull.go, internal/commands/category/category_push.go, internal/commands/category/category_commit.go
Adds category Cobra command and subcommands: list (fetch/display), pull (fetch → file), push (read file → upload), commit (finalize with message). Registers flags (workspace, mode, commit-message, output) and uses TTY-aware spinner for interactive feedback.
CLI: helpers
internal/commands/category/helpers.go
Adds WriteToFile and ReadFromFile helpers to read/write indented JSON under ./suprsend/category.
Root integration
internal/commands/root.go
Imports and registers category.CategoryCmd on the root command and adjusts subcommand registration order; sets rootCmd.DisableAutoGenTag = true.
Management API: categories
mgmnt/category.go
Adds models (PreferenceCategoryResponse, Category, Section, Subcategory) and management methods on SS_MgmntClient: ListCategories(workspace, mode), PushCategories(workspace, categories), FinalizeCategories(workspace, commitMsg) performing HTTP GET/POST/PATCH requests.
Sync: assets extended
internal/commands/sync.go
Extends sync flow to support categories asset (List → write → read → Push) and threads mode through schema sync calls.
Mgmt client logging tweak
mgmnt/client.go
Removes service token from debug log output in client construction.
Docs: autogenerated pages
docs/suprsend_category*.md, docs/*.md (multiple)
Adds documentation for category commands and removes autogenerated Cobra timestamp lines from many docs.
Dependency updates
go.mod
Bumps github.com/spf13/viper and several indirect dependencies; minor dependency graph adjustments.
Output formatting tweak
internal/utils/outpututil.go
Changes table merge mode from hierarchical to none for struct table output.

Sequence Diagram(s)

sequenceDiagram
  actor User
  participant CLI as CLI (category list)
  participant Utils as Utils (Get client)
  participant API as Mgmt API

  User->>CLI: suprsend category list --workspace W --mode M
  CLI->>CLI: start spinner if TTY
  CLI->>Utils: GetSuprSendMgmntClient()
  CLI->>API: GET /v1/W/preference_category/?mode=M
  API-->>CLI: PreferenceCategoryResponse
  CLI->>CLI: flatten & format output
  CLI-->>User: display (table/json)
  CLI->>CLI: stop spinner
Loading
sequenceDiagram
  actor User
  participant CLI as CLI (category pull)
  participant Utils as Utils (Get client)
  participant API as Mgmt API
  participant FS as File System

  User->>CLI: suprsend category pull --workspace W --mode M
  CLI->>CLI: start spinner if TTY
  CLI->>Utils: GetSuprSendMgmntClient()
  CLI->>API: GET /v1/W/preference_category/?mode=M
  API-->>CLI: PreferenceCategoryResponse
  CLI->>FS: WriteToFile("./suprsend/category/categories_preferences.json")
  CLI->>CLI: stop spinner / report
Loading
sequenceDiagram
  actor User
  participant CLI as CLI (category push)
  participant FS as File System
  participant Utils as Utils (Get client)
  participant API as Mgmt API

  User->>CLI: suprsend category push --workspace W
  CLI->>CLI: start spinner if TTY
  CLI->>FS: ReadFromFile("./suprsend/category/categories_preferences.json")
  CLI->>Utils: GetSuprSendMgmntClient()
  CLI->>API: POST /v1/W/preference_category/ (JSON payload)
  API-->>CLI: 2xx / error
  CLI->>CLI: stop spinner / log result
Loading
sequenceDiagram
  actor User
  participant CLI as CLI (category commit)
  participant Utils as Utils (Get client)
  participant API as Mgmt API

  User->>CLI: suprsend category commit --workspace W --commit-message "msg"
  CLI->>CLI: start spinner if TTY
  CLI->>Utils: GetSuprSendMgmntClient()
  CLI->>API: PATCH /v1/W/preference_category/commit/?commit_message=msg
  API-->>CLI: 2xx / error
  CLI->>CLI: stop spinner / log result
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Pre-merge checks (2 passed, 1 warning)

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title “feat: pref categories.” succinctly identifies the primary change—adding preference categories functionality—and uses the project’s conventional commit style to flag this as a feature addition, making it clear to reviewers what the pull request introduces.

Poem

"I'm a rabbit with a tiny key,
Categories hop and land for me.
I pull the crumbs, I push with flair,
I list and commit with rabbit care.
Hoppity-hop, the changes flee! 🐰"

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/pref-cat

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 12

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
internal/commands/root.go (1)

41-41: Fix user-facing typo.

“Output Tyle” → “Output Type”.

- rootCmd.PersistentFlags().StringVarP(&conf.OutputType, "output", "o", "pretty", "Output Tyle (pretty, yaml, json)")
+ rootCmd.PersistentFlags().StringVarP(&conf.OutputType, "output", "o", "pretty", "Output Type (pretty, yaml, json)")
🧹 Nitpick comments (15)
internal/commands/category/helpers.go (1)

19-32: Avoid parameter name “filepath” and return strongly-typed data.

The parameter name collides with the stdlib package name and returning interface{} forces downstream type assertions.

-func ReadFromFile(filepath string) (interface{}, error) {
-	jsonData, err := os.ReadFile(filepath)
+func ReadFromFile(path string) (interface{}, error) {
+	jsonData, err := os.ReadFile(path)
 	if err != nil {
-		return nil, fmt.Errorf("failed to read file: %w", err)
+		return nil, fmt.Errorf("failed to read file: %w", err)
 	}

Consider adding a typed helper to reduce json number/string surprises:

// new helper (outside the shown ranges)
func ReadFromFileInto(path string, dest any) error {
	b, err := os.ReadFile(path)
	if err != nil { return fmt.Errorf("failed to read file: %w", err) }
	if err := json.Unmarshal(b, dest); err != nil { return fmt.Errorf("failed to unmarshal data: %w", err) }
	return nil
}
mgmnt/category.go (1)

60-62: Include response body in errors for better diagnostics.

Status alone is low-signal when debugging API failures.

-	return nil, fmt.Errorf("request failed with status: %s", resp.Status())
+	return nil, fmt.Errorf("request failed with status: %s, body: %s", resp.Status(), resp.String())

Apply similarly in PushCategories and FinalizeCategories.

Also applies to: 85-86, 105-107

internal/commands/root.go (2)

13-13: Package layout deviates from command registration guideline.

Guidelines specify registering subcommands via init() in internal/commands/**/!(root).go against rootCmd. Importing a separate package (category) suggests those files aren’t in package commands, forcing central registration here.

Two options:

  • Preferred: make internal/commands/category/* use package commands and register CategoryCmd in its own init(); then drop this import from root.go.
  • Or: document the deviation and update guidelines to reflect centralized registration in root.go.

69-69: Let CategoryCmd self-register via init() (if you switch to package commands).

Keeps root.go focused on root config and matches the stated guideline.

If you adopt self-registration, remove this line from root.go and add in internal/commands/category/category.go:

// in package commands
func init() { rootCmd.AddCommand(CategoryCmd) }
internal/commands/category/category_pull.go (2)

21-29: Use cmd.Context() for spinner; improves cancellation/propagation.

-      cancel := p.Start(context.Background())
+      cancel := p.Start(cmd.Context())

45-46: Add shorthand for mode to match list command (-m).

-  categoryPullCmd.PersistentFlags().String("mode", "live", "Mode to pull categories from")
+  categoryPullCmd.PersistentFlags().StringP("mode", "m", "live", "Mode to pull categories from")
internal/commands/category/category_push.go (3)

28-29: Use cmd.Context() for spinner.

-      cancel := p.Start(context.Background())
+      cancel := p.Start(cmd.Context())

36-41: Go naming and clearer error logs.

-    mgmnt_client := utils.GetSuprSendMgmntClient()
-    err = mgmnt_client.PushCategories(workspace, categories)
+    mgmntClient := utils.GetSuprSendMgmntClient()
+    err = mgmntClient.PushCategories(workspace, categories)
     if err != nil {
-      log.WithError(err).Error("Couldn't push categories")
+      log.WithError(err).WithField("workspace", workspace).Error("Couldn't push categories")
       return
     }

32-35: Include file path in read error for faster debugging.

-    if err != nil {
-      log.WithError(err).Error("Couldn't read categories from file")
+    if err != nil {
+      log.WithError(err).WithField("file", path.Join(dirPath, "categories_preferences.json")).Error("Couldn't read categories from file")
       return
     }
internal/commands/category/category_commit.go (2)

26-27: Use cmd.Context() for spinner.

-      cancel := p.Start(context.Background())
+      cancel := p.Start(cmd.Context())

30-38: Go naming + richer error context.

-    mgmnt_client := utils.GetSuprSendMgmntClient()
-    err := mgmnt_client.FinalizeCategories(workspace, commitMsg)
+    mgmntClient := utils.GetSuprSendMgmntClient()
+    err := mgmntClient.FinalizeCategories(workspace, commitMsg)
     if err != nil {
-      log.WithError(err).Error("Couldn't commit categories")
+      log.WithError(err).WithFields(log.Fields{
+        "workspace":      workspace,
+        "commit_message": commitMsg,
+      }).Error("Couldn't commit categories")
       return
     }
internal/commands/category/category_list.go (4)

32-33: Use cmd.Context() for spinner.

-      cancel := p.Start(context.Background())
+      cancel := p.Start(cmd.Context())

36-44: Go naming and consistent success message.

-    mgmnt_client := utils.GetSuprSendMgmntClient()
-    categories, err := mgmnt_client.ListCategories(workspace, mode)
+    mgmntClient := utils.GetSuprSendMgmntClient()
+    categories, err := mgmntClient.ListCategories(workspace, mode)
     if err != nil {
       log.WithError(err).Error("Couldn't fetch categories")
       return
     }
     if p != nil {
       p.Stop(fmt.Sprintf("Listed %d categories from %s", len(categories.Categories), workspace))
     }

46-61: Minor: simplify empty output branch.

You can always call utils.OutputData(displayItems, outputType); if displayItems is empty, it will serialize to []. The special-case for piped output is unnecessary.

-    if len(displayItems) == 0 && utils.IsOutputPiped() {
-      utils.OutputData([]interface{}{}, outputType)
-      return
-    }
-
-    utils.OutputData(displayItems, outputType)
+    utils.OutputData(displayItems, outputType)

18-25: Optional: align flags across subcommands.

list supports -m/--mode; pull should also offer -m. Consider making --mode a persistent flag on CategoryCmd if multiple subcommands use it.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b0b7b1c and 9be99c2.

📒 Files selected for processing (8)
  • internal/commands/category/category.go (1 hunks)
  • internal/commands/category/category_commit.go (1 hunks)
  • internal/commands/category/category_list.go (1 hunks)
  • internal/commands/category/category_pull.go (1 hunks)
  • internal/commands/category/category_push.go (1 hunks)
  • internal/commands/category/helpers.go (1 hunks)
  • internal/commands/root.go (2 hunks)
  • mgmnt/category.go (1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
internal/commands/**/!(root).go

📄 CodeRabbit inference engine (.cursor/rules/command-registration.mdc)

Register each subcommand by calling rootCmd.AddCommand(...) in the subcommand’s own init() function

Files:

  • internal/commands/category/helpers.go
  • internal/commands/category/category_push.go
  • internal/commands/category/category.go
  • internal/commands/category/category_pull.go
  • internal/commands/category/category_commit.go
  • internal/commands/category/category_list.go
mgmnt/**/*.go

📄 CodeRabbit inference engine (.cursor/rules/cli-structure.mdc)

Place management and client-related Go code under the mgmnt/ directory

Files:

  • mgmnt/category.go
internal/commands/root.go

📄 CodeRabbit inference engine (.cursor/rules/cli-structure.mdc)

Define the root command and global flags in internal/commands/root.go

internal/commands/root.go: Define the CLI root command as rootCmd in internal/commands/root.go
Set global flags on rootCmd within the init() function in internal/commands/root.go

Files:

  • internal/commands/root.go
internal/commands/*.go

📄 CodeRabbit inference engine (.cursor/rules/cli-structure.mdc)

Register subcommands via init() functions in files under internal/commands/

Files:

  • internal/commands/root.go

Comment on lines 31 to 39
mgmnt_client := utils.GetSuprSendMgmntClient()
categories, err := mgmnt_client.ListCategories(workspace, mode)
if err != nil {
log.WithError(err).Error("Couldn't fetch categories")
return
}
WriteToFile(categories, "categories_preferences.json")
if p != nil {
p.Stop(fmt.Sprintf("Pulled categories from %s", workspace))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Handle file write errors; fail with non-zero exit on I/O issues.

-    WriteToFile(categories, "categories_preferences.json")
+    if err := WriteToFile(categories, "categories_preferences.json"); err != nil {
+      log.WithError(err).Error("Couldn't write categories to file")
+      return
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
mgmnt_client := utils.GetSuprSendMgmntClient()
categories, err := mgmnt_client.ListCategories(workspace, mode)
if err != nil {
log.WithError(err).Error("Couldn't fetch categories")
return
}
WriteToFile(categories, "categories_preferences.json")
if p != nil {
p.Stop(fmt.Sprintf("Pulled categories from %s", workspace))
mgmnt_client := utils.GetSuprSendMgmntClient()
categories, err := mgmnt_client.ListCategories(workspace, mode)
if err != nil {
log.WithError(err).Error("Couldn't fetch categories")
return
}
if err := WriteToFile(categories, "categories_preferences.json"); err != nil {
log.WithError(err).Error("Couldn't write categories to file")
return
}
if p != nil {
p.Stop(fmt.Sprintf("Pulled categories from %s", workspace))
🤖 Prompt for AI Agents
In internal/commands/category/category_pull.go around lines 31 to 39, the call
to WriteToFile ignores I/O errors; update the code to capture the returned error
from WriteToFile, log it with log.WithError(...).Error or .Fatal (including
context like filename and workspace), and exit non‑zero (e.g., os.Exit(1)) when
a write fails so the process fails on I/O issues; ensure progress cleanup
(p.Stop) still runs when appropriate.

Comment on lines +3 to +8
import (
"fmt"
"time"

"github.com/suprsend/cli/internal/client"
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

URL-encode commit message (and avoid package shadowing).

Commit messages with spaces or special chars will break the query string; import net/url and don’t shadow it with a local “url” var where you need QueryEscape.

 import (
 	"fmt"
 	"time"
 
 	"github.com/suprsend/cli/internal/client"
+	"net/url"
 )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import (
"fmt"
"time"
"github.com/suprsend/cli/internal/client"
)
import (
"fmt"
"time"
"github.com/suprsend/cli/internal/client"
"net/url"
)
🤖 Prompt for AI Agents
In mgmnt/category.go around lines 3–8, the code must import net/url and avoid
shadowing the package with a local variable named "url"; add "net/url" to the
import block, replace any local variable named "url" (e.g., rename to encodedMsg
or commitMsgEscaped), and use url.QueryEscape(theCommitMessage) when building
the query string so commit messages with spaces/special characters are safely
URL-encoded.

@gauravverma
Copy link
Contributor

@zokhcat check coderabbit comments and resolve them

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
docs/suprsend_generate-types_dart.md (1)

21-26: Fix typo: “Output Tyle” → “Output Type”.

User-facing flag description has a typo.

Prefer fixing the source flag help in the Cobra command and regenerating docs. If you must patch this file:

-  -o, --output string          Output Tyle (pretty, yaml, json) (default "pretty")
+  -o, --output string          Output Type (pretty, yaml, json) (default "pretty")
internal/commands/sync.go (1)

35-41: Include categories in --assets all; fix valid-options message.

“All” should sync categories; update error message accordingly.

Apply:

-		case "all":
-			assetsToSync = []string{"workflows", "schemas"}
+		case "all":
+			assetsToSync = []string{"workflows", "schemas", "categories"}
@@
-			log.Errorf("Invalid asset type: '%s'. Valid options are: all, workflows, schemas", assets)
+			log.Errorf("Invalid asset type: '%s'. Valid options are: all, workflows, schemas, categories", assets)

Also applies to: 44-45

♻️ Duplicate comments (1)
internal/commands/category/helpers.go (1)

10-21: Nice: directory creation is now safe and portable.

MkdirAll error is handled and paths use filepath.Join; this resolves the earlier review.

🧹 Nitpick comments (23)
docs/suprsend_generate-types_dart.md (1)

32-32: markdownlint MD001 on autogenerated footer.

Heading level jumps to h6; either suppress for this line or adjust via generator config. If you want a local suppression here, apply:

-###### Auto generated by spf13/cobra on 9-Sep-2025
+<!-- markdownlint-disable-next-line MD001 -->
+###### Auto generated by spf13/cobra on 9-Sep-2025

Alternatively, disable MD001 for Cobra-generated docs in markdownlint config to avoid churn.

docs/suprsend_completion_bash.md (1)

54-54: Timestamp bump OK; silence MD001 for Cobra footer.

Autogenerated date looks fine. The H6 footer triggers markdownlint MD001; since these files are generated, prefer a linter override rather than manual edits.

Add/extend markdownlint-cli2 config to ignore MD001 for Cobra docs:

{
  "$schema": "https://raw.githubusercontent.com/DavidAnson/markdownlint-cli2/main/schema/markdownlint-cli2-config-schema.json",
  "globs": [
    { "globs": ["docs/suprsend_*.md"], "config": { "MD001": false } }
  ]
}
docs/suprsend_completion_zsh.md (1)

56-56: Timestamp bump OK; silence MD001 for Cobra footer.

Same MD001 heading jump from H3 to H6 due to the autogenerated footer. Handle via markdownlint-cli2 override instead of editing generated docs.

See suggested config in the bash completion doc comment.

docs/suprsend_workflow_push.md (1)

35-35: Timestamp bump OK; suppress MD001 for autogenerated footer.

No content change; address markdownlint MD001 via config for Cobra-generated pages.

Use the repo-wide markdownlint-cli2 override as suggested earlier.

docs/suprsend_profile_list.md (1)

33-33: Date refresh acknowledged; handle MD001 via linter config.

Avoid hand-editing generated files; suppress MD001 for these docs.

Reuse the markdownlint-cli2 override shown previously.

docs/suprsend_profile.md (1)

34-34: Footer date OK; suppress MD001 and MD010 (tabs) for generated docs.

This page also hits MD010 due to tabs in Cobra’s “SEE ALSO” bullets; since it’s generated, prefer lint overrides.

Extend markdownlint-cli2 config:

{
  "$schema": "https://raw.githubusercontent.com/DavidAnson/markdownlint-cli2/main/schema/markdownlint-cli2-config-schema.json",
  "globs": [
    { "globs": ["docs/suprsend_*.md"], "config": { "MD001": false } },
    { "globs": ["docs/suprsend_profile.md"], "config": { "MD010": false } }
  ]
}
docs/suprsend_schema_push.md (1)

35-35: Timestamp update fine; suppress MD001 for Cobra footer via linter config.

Keep docs generated; handle the rule in config.

Leverage the same markdownlint-cli2 override.

docs/suprsend_workflow.md (1)

39-39: Footer date looks good; address MD001 via markdownlint config.

Generated H6 footer can be excluded from MD001 checks.

Apply the existing override for docs/suprsend_*.md.

docs/suprsend_workflow_disable.md (1)

34-34: Date bump OK; mute MD001 for autogenerated footer.

No content diffs; manage the linter warning centrally.

Use the markdownlint-cli2 override proposed above.

docs/suprsend_profile_modify.md (1)

37-37: Timestamp bump is fine; address markdownlint footer noise

The Cobra footer triggers MD001. Prefer disabling MD001 for this generated line repo-wide instead of editing each doc.

Add to .markdownlint.json:

{
  "MD001": false
}
docs/suprsend_version.md (1)

13-16: Examples point to a user-specific build path; replace with CLI usage

Hard-coded /home/.../go-build paths are confusing and non-portable. Use “suprsend version …” in Examples so docs match real usage.

Update the command’s Example string (e.g., internal/commands/version.go):

-cmd.Example = `
-/home/zokhcat/.cache/go-build/.../main version
-/home/zokhcat/.cache/go-build/.../main version -o=json
-/home/zokhcat/.cache/go-build/.../main version -o=yaml
-/home/zokhcat/.cache/go-build/.../main version -o=short
-`
+cmd.Example = `
+suprsend version
+suprsend version -o=json
+suprsend version -o=yaml
+suprsend version -o=short
+`
docs/suprsend_category_list.md (3)

9-11: Add code-fence languages (markdownlint MD040).

Specify languages for fences; suggest bash for usage and text for options.

Apply:

-```
+```bash
 suprsend category list [flags]

Options

- +text
-h, --help help for list
-m, --mode string Mode of preferences to list (default "live")


### Options inherited from parent commands

-```
+```text
      --config string          config file (default: $HOME/.suprsend.yaml)
  -n, --no-color               Disable color output (default: $NO_COLOR)
-  -o, --output string          Output Tyle (pretty, yaml, json) (default "pretty")
+  -o, --output string          Output Type (pretty, yaml, json) (default "pretty")
  -s, --service-token string   Service token (default: $SUPRSEND_SERVICE_TOKEN)
  -v, --verbosity string       Log level (debug, info, warn, error, fatal, panic) (default "info")
-      --workspace string       Workspace to push categories to (default "staging")
+      --workspace string       Workspace to list categories from (default "staging")


Also applies to: 15-18, 22-29

---

`33-33`: **Replace hard tab with spaces (markdownlint MD010).**

Apply:

```diff
-* [suprsend category](suprsend_category.md)	 - Manage preference categories
+* [suprsend category](suprsend_category.md) - Manage preference categories

35-35: Heading level jump (MD001). Consider standardizing or ignoring for auto-gen.

If you keep Cobra auto-gen as-is, add a markdownlint ignore for docs; else change to h4.

Apply (if modifying docs):

-###### Auto generated by spf13/cobra on 9-Sep-2025
+#### Auto generated by spf13/cobra on 9-Sep-2025

Or add docs/ to .markdownlintignore for MD001/MD040/MD046.

internal/commands/category/helpers.go (2)

23-34: Avoid shadowing the imported filepath package; improve error detail.

Rename the parameter and include the path in errors for better diagnostics.

Apply:

-func ReadFromFile(filepath string) (interface{}, error) {
-	jsonData, err := os.ReadFile(filepath)
+func ReadFromFile(path string) (interface{}, error) {
+	jsonData, err := os.ReadFile(path)
 	if err != nil {
-		return nil, fmt.Errorf("failed to read file: %w", err)
+		return nil, fmt.Errorf("failed to read file %s: %w", path, err)
 	}
 	var data interface{}
 	err = json.Unmarshal(jsonData, &data)
 	if err != nil {
 		return nil, fmt.Errorf("failed to unmarshal data: %w", err)
 	}
 	return data, nil
 }

10-21: Optional: make writes atomic to avoid partial-file corruption.

Write to a temp file then rename.

Apply:

-	return os.WriteFile(filename, jsonData, 0644)
+	tmp := filename + ".tmp"
+	if err := os.WriteFile(tmp, jsonData, 0o644); err != nil {
+		return err
+	}
+	return os.Rename(tmp, filename)
docs/suprsend_category_commit.md (2)

9-11: Add languages to fenced code blocks (MD040/MD046).

Apply:

-```
+```bash
 suprsend category commit [flags]

Options

- +text
--commit-message string Commit message
-h, --help help for commit
--workspace string Workspace to commit categories to (default "staging")


### Options inherited from parent commands

-```
+```text
      --config string          config file (default: $HOME/.suprsend.yaml)
  -n, --no-color               Disable color output (default: $NO_COLOR)
-  -o, --output string          Output Tyle (pretty, yaml, json) (default "pretty")
+  -o, --output string          Output Type (pretty, yaml, json) (default "pretty")
  -s, --service-token string   Service token (default: $SUPRSEND_SERVICE_TOKEN)
  -v, --verbosity string       Log level (debug, info, warn, error, fatal, panic) (default "info")


Also applies to: 15-19, 23-29

---

`33-33`: **Replace hard tab with spaces (MD010).**

Apply:

```diff
-* [suprsend category](suprsend_category.md)	 - Manage preference categories
+* [suprsend category](suprsend_category.md) - Manage preference categories
docs/suprsend_category_push.md (3)

9-11: Add languages to fenced code blocks; standardize formatting.

Apply:

-```
+```bash
 suprsend category push [flags]

Options

- +text
-h, --help help for push


### Options inherited from parent commands

-```
+```text
      --config string          config file (default: $HOME/.suprsend.yaml)
  -n, --no-color               Disable color output (default: $NO_COLOR)
-  -o, --output string          Output Tyle (pretty, yaml, json) (default "pretty")
+  -o, --output string          Output Type (pretty, yaml, json) (default "pretty")
  -s, --service-token string   Service token (default: $SUPRSEND_SERVICE_TOKEN)
  -v, --verbosity string       Log level (debug, info, warn, error, fatal, panic) (default "info")
      --workspace string       Workspace to push categories to (default "staging")


Also applies to: 15-17, 21-28

---

`32-32`: **Replace hard tab with spaces (MD010) or ignore auto-gen.**

Apply:

```diff
-* [suprsend category](suprsend_category.md)	 - Manage preference categories
+* [suprsend category](suprsend_category.md) - Manage preference categories

34-34: Heading level jump (MD001).

Either reduce to h4 or exclude auto-generated docs from MD001/MD046 checks.

-###### Auto generated by spf13/cobra on 9-Sep-2025
+#### Auto generated by spf13/cobra on 9-Sep-2025
internal/commands/sync.go (2)

51-57: Inject the management client into syncWorkflows for consistency.

Avoid re-creating the client; pass it like schemas/categories do.

Apply:

-		mgmnt_client := utils.GetSuprSendMgmntClient()
+		mgmnt_client := utils.GetSuprSendMgmntClient()
@@
-			case "workflows":
-				syncWorkflows(fromWorkspace, toWorkspace, mode)
+			case "workflows":
+				syncWorkflows(mgmnt_client, fromWorkspace, toWorkspace, mode)

And update the function:

-func syncWorkflows(fromWorkspace, toWorkspace, mode string) {
+func syncWorkflows(mgmnt_client *mgmnt.SS_MgmntClient, fromWorkspace, toWorkspace, mode string) {
@@
-	mgmnt_client := utils.GetSuprSendMgmntClient()

Also applies to: 70-79


171-196: Avoid unnecessary write→read roundtrip; push fetched categories directly.

Reduces I/O and failure points.

Apply:

-func syncCategories(mgmnt_client *mgmnt.SS_MgmntClient, fromWorkspace, toWorkspace, mode string) {
-	dirPath := filepath.Join(".", "suprsend", "category")
-	categoriesResp, err := mgmnt_client.ListCategories(fromWorkspace, mode)
+func syncCategories(mgmnt_client *mgmnt.SS_MgmntClient, fromWorkspace, toWorkspace, mode string) {
+	categoriesResp, err := mgmnt_client.ListCategories(fromWorkspace, mode)
 	if err != nil {
 		log.WithError(err).Error("Error getting categories")
 		return
 	}
 	log.Infof("Pulling categories from %s ... \n", fromWorkspace)
-	err = category.WriteToFile(categoriesResp, "categories_preferences.json")
-	if err != nil {
-		log.WithError(err).Error("Error saving categories")
-		return
-	}
-	filePath := filepath.Join(dirPath, "categories_preferences.json")
-	categories, err := category.ReadFromFile(filePath)
-	if err != nil {
-		log.WithError(err).Error("Error reading categories file")
-		return
-	}
-	err = mgmnt_client.PushCategories(toWorkspace, categories)
+	if err := mgmnt_client.PushCategories(toWorkspace, categoriesResp); err != nil {
 		if err != nil {
 			log.WithError(err).Error("Error pushing categories")
 			return
 		}
-	}
-	log.Printf("Pushed categories to %s\n", toWorkspace)
+	}
+	log.Printf("Pushed categories to %s\n", toWorkspace)
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9be99c2 and 38e847e.

📒 Files selected for processing (47)
  • docs/suprsend.md (2 hunks)
  • docs/suprsend_category.md (1 hunks)
  • docs/suprsend_category_commit.md (1 hunks)
  • docs/suprsend_category_list.md (1 hunks)
  • docs/suprsend_category_pull.md (1 hunks)
  • docs/suprsend_category_push.md (1 hunks)
  • docs/suprsend_completion.md (1 hunks)
  • docs/suprsend_completion_bash.md (1 hunks)
  • docs/suprsend_completion_fish.md (1 hunks)
  • docs/suprsend_completion_powershell.md (1 hunks)
  • docs/suprsend_completion_zsh.md (1 hunks)
  • docs/suprsend_generate-types.md (1 hunks)
  • docs/suprsend_generate-types_dart.md (1 hunks)
  • docs/suprsend_generate-types_go.md (1 hunks)
  • docs/suprsend_generate-types_java.md (1 hunks)
  • docs/suprsend_generate-types_kotlin.md (1 hunks)
  • docs/suprsend_generate-types_python.md (1 hunks)
  • docs/suprsend_generate-types_swift.md (1 hunks)
  • docs/suprsend_generate-types_typescript.md (1 hunks)
  • docs/suprsend_profile.md (1 hunks)
  • docs/suprsend_profile_add.md (1 hunks)
  • docs/suprsend_profile_list.md (1 hunks)
  • docs/suprsend_profile_modify.md (1 hunks)
  • docs/suprsend_profile_remove.md (1 hunks)
  • docs/suprsend_profile_use.md (1 hunks)
  • docs/suprsend_schema.md (1 hunks)
  • docs/suprsend_schema_commit.md (1 hunks)
  • docs/suprsend_schema_list.md (1 hunks)
  • docs/suprsend_schema_pull.md (1 hunks)
  • docs/suprsend_schema_push.md (1 hunks)
  • docs/suprsend_schema_reset.md (1 hunks)
  • docs/suprsend_start-mcp-server.md (1 hunks)
  • docs/suprsend_start-mcp-server_list-tools.md (1 hunks)
  • docs/suprsend_sync.md (1 hunks)
  • docs/suprsend_version.md (2 hunks)
  • docs/suprsend_workflow.md (1 hunks)
  • docs/suprsend_workflow_disable.md (1 hunks)
  • docs/suprsend_workflow_enable.md (1 hunks)
  • docs/suprsend_workflow_list.md (1 hunks)
  • docs/suprsend_workflow_pull.md (1 hunks)
  • docs/suprsend_workflow_push.md (1 hunks)
  • internal/commands/category/category.go (1 hunks)
  • internal/commands/category/category_list.go (1 hunks)
  • internal/commands/category/category_pull.go (1 hunks)
  • internal/commands/category/category_push.go (1 hunks)
  • internal/commands/category/helpers.go (1 hunks)
  • internal/commands/sync.go (5 hunks)
✅ Files skipped from review due to trivial changes (21)
  • docs/suprsend_generate-types_python.md
  • docs/suprsend_start-mcp-server_list-tools.md
  • docs/suprsend_workflow_enable.md
  • docs/suprsend_generate-types_go.md
  • docs/suprsend_profile_add.md
  • docs/suprsend_generate-types_kotlin.md
  • docs/suprsend_category.md
  • docs/suprsend_start-mcp-server.md
  • docs/suprsend_completion.md
  • docs/suprsend_generate-types_java.md
  • docs/suprsend_category_pull.md
  • docs/suprsend_generate-types.md
  • docs/suprsend_completion_fish.md
  • docs/suprsend_schema_commit.md
  • docs/suprsend_profile_use.md
  • docs/suprsend_completion_powershell.md
  • docs/suprsend_sync.md
  • docs/suprsend_generate-types_swift.md
  • docs/suprsend_schema.md
  • docs/suprsend_generate-types_typescript.md
  • docs/suprsend_workflow_list.md
🚧 Files skipped from review as they are similar to previous changes (4)
  • internal/commands/category/category_list.go
  • internal/commands/category/category_pull.go
  • internal/commands/category/category_push.go
  • internal/commands/category/category.go
🧰 Additional context used
📓 Path-based instructions (3)
internal/commands/*.go

📄 CodeRabbit inference engine (.cursor/rules/cli-structure.mdc)

Register subcommands via init() functions in files under internal/commands/

Files:

  • internal/commands/sync.go
internal/commands/**/!(root).go

📄 CodeRabbit inference engine (.cursor/rules/command-registration.mdc)

Register each subcommand by calling rootCmd.AddCommand(...) in the subcommand’s own init() function

Files:

  • internal/commands/sync.go
  • internal/commands/category/helpers.go
docs/**/*.md

📄 CodeRabbit inference engine (.cursor/rules/cli-structure.mdc)

Store CLI command and usage documentation as Markdown under docs/

Files:

  • docs/suprsend.md
  • docs/suprsend_category_commit.md
  • docs/suprsend_category_list.md
  • docs/suprsend_category_push.md
  • docs/suprsend_completion_bash.md
  • docs/suprsend_completion_zsh.md
  • docs/suprsend_generate-types_dart.md
  • docs/suprsend_profile.md
  • docs/suprsend_profile_list.md
  • docs/suprsend_profile_modify.md
  • docs/suprsend_profile_remove.md
  • docs/suprsend_schema_list.md
  • docs/suprsend_schema_pull.md
  • docs/suprsend_schema_push.md
  • docs/suprsend_schema_reset.md
  • docs/suprsend_version.md
  • docs/suprsend_workflow.md
  • docs/suprsend_workflow_disable.md
  • docs/suprsend_workflow_pull.md
  • docs/suprsend_workflow_push.md
🧠 Learnings (5)
📚 Learning: 2025-08-25T08:53:18.379Z
Learnt from: CR
PR: suprsend/cli#0
File: .cursor/rules/cli-structure.mdc:0-0
Timestamp: 2025-08-25T08:53:18.379Z
Learning: Applies to cmd/suprsend/main.go : The CLI entry point is cmd/suprsend/main.go and should invoke commands.Execute()

Applied to files:

  • internal/commands/sync.go
  • docs/suprsend.md
  • docs/suprsend_version.md
📚 Learning: 2025-08-25T08:53:18.379Z
Learnt from: CR
PR: suprsend/cli#0
File: .cursor/rules/cli-structure.mdc:0-0
Timestamp: 2025-08-25T08:53:18.379Z
Learning: Applies to internal/commands/*.go : Register subcommands via init() functions in files under internal/commands/

Applied to files:

  • internal/commands/sync.go
📚 Learning: 2025-08-25T08:53:44.887Z
Learnt from: CR
PR: suprsend/cli#0
File: .cursor/rules/command-registration.mdc:0-0
Timestamp: 2025-08-25T08:53:44.887Z
Learning: Applies to cmd/suprsend/main.go : Ensure the main entry point calls `commands.Execute()` to run the CLI

Applied to files:

  • internal/commands/sync.go
📚 Learning: 2025-08-25T08:53:44.887Z
Learnt from: CR
PR: suprsend/cli#0
File: .cursor/rules/command-registration.mdc:0-0
Timestamp: 2025-08-25T08:53:44.887Z
Learning: Applies to internal/commands/**/!(root).go : Register each subcommand by calling `rootCmd.AddCommand(...)` in the subcommand’s own `init()` function

Applied to files:

  • internal/commands/sync.go
📚 Learning: 2025-08-25T08:53:18.379Z
Learnt from: CR
PR: suprsend/cli#0
File: .cursor/rules/cli-structure.mdc:0-0
Timestamp: 2025-08-25T08:53:18.379Z
Learning: Applies to internal/utils/banner.go : Print the CLI banner from internal/utils/banner.go

Applied to files:

  • internal/commands/sync.go
🧬 Code graph analysis (1)
internal/commands/sync.go (2)
mgmnt/client.go (1)
  • SS_MgmntClient (25-31)
internal/commands/category/helpers.go (2)
  • WriteToFile (10-21)
  • ReadFromFile (23-34)
🪛 markdownlint-cli2 (0.17.2)
docs/suprsend_category_commit.md

11-11: Hard tabs
Column: 1

(MD010, no-hard-tabs)


15-15: Hard tabs
Column: 1

(MD010, no-hard-tabs)


20-20: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


20-20: Code block style
Expected: indented; Actual: fenced

(MD046, code-block-style)


26-26: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


26-26: Code block style
Expected: indented; Actual: fenced

(MD046, code-block-style)


33-33: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


33-33: Code block style
Expected: indented; Actual: fenced

(MD046, code-block-style)

docs/suprsend_category_list.md

9-9: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


15-15: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


22-22: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


33-33: Hard tabs
Column: 44

(MD010, no-hard-tabs)


35-35: Heading levels should only increment by one level at a time
Expected: h4; Actual: h6

(MD001, heading-increment)

docs/suprsend_category_push.md

5-5: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


11-11: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


20-20: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


30-30: Hard tabs
Column: 56

(MD010, no-hard-tabs)


32-32: Heading levels should only increment by one level at a time
Expected: h4; Actual: h6

(MD001, heading-increment)

docs/suprsend_completion_bash.md

54-54: Heading levels should only increment by one level at a time
Expected: h4; Actual: h6

(MD001, heading-increment)

docs/suprsend_completion_zsh.md

56-56: Heading levels should only increment by one level at a time
Expected: h4; Actual: h6

(MD001, heading-increment)

docs/suprsend_generate-types_dart.md

32-32: Heading levels should only increment by one level at a time
Expected: h4; Actual: h6

(MD001, heading-increment)

docs/suprsend_profile.md

34-34: Hard tabs
Column: 42

(MD010, no-hard-tabs)

docs/suprsend_profile_list.md

33-33: Heading levels should only increment by one level at a time
Expected: h4; Actual: h6

(MD001, heading-increment)

docs/suprsend_profile_modify.md

37-37: Heading levels should only increment by one level at a time
Expected: h4; Actual: h6

(MD001, heading-increment)

docs/suprsend_profile_remove.md

30-30: Heading levels should only increment by one level at a time
Expected: h4; Actual: h6

(MD001, heading-increment)

docs/suprsend_schema_list.md

37-37: Heading levels should only increment by one level at a time
Expected: h4; Actual: h6

(MD001, heading-increment)

docs/suprsend_schema_pull.md

36-36: Heading levels should only increment by one level at a time
Expected: h4; Actual: h6

(MD001, heading-increment)

docs/suprsend_schema_push.md

35-35: Heading levels should only increment by one level at a time
Expected: h4; Actual: h6

(MD001, heading-increment)

docs/suprsend_schema_reset.md

34-34: Heading levels should only increment by one level at a time
Expected: h4; Actual: h6

(MD001, heading-increment)

docs/suprsend_version.md

40-40: Heading levels should only increment by one level at a time
Expected: h4; Actual: h6

(MD001, heading-increment)

docs/suprsend_workflow.md

39-39: Heading levels should only increment by one level at a time
Expected: h4; Actual: h6

(MD001, heading-increment)

docs/suprsend_workflow_disable.md

34-34: Heading levels should only increment by one level at a time
Expected: h4; Actual: h6

(MD001, heading-increment)

docs/suprsend_workflow_pull.md

36-36: Heading levels should only increment by one level at a time
Expected: h4; Actual: h6

(MD001, heading-increment)

docs/suprsend_workflow_push.md

35-35: Heading levels should only increment by one level at a time
Expected: h4; Actual: h6

(MD001, heading-increment)

🔇 Additional comments (10)
docs/suprsend_generate-types_dart.md (1)

32-32: LGTM: timestamp refresh is correct.

Autogenerated date bumped to 9-Sep-2025; no content change.

docs/suprsend.md (1)

25-25: SEE ALSO addition for “category” looks good

Matches new CLI group. No issues.

docs/suprsend_schema_pull.md (1)

36-36: Timestamp update acknowledged

No content change; OK.

docs/suprsend_profile_remove.md (1)

30-30: Timestamp update acknowledged

No content change; OK.

docs/suprsend_schema_reset.md (1)

34-34: Timestamp update acknowledged

No content change; OK.

docs/suprsend_schema_list.md (1)

37-37: Timestamp update acknowledged

No content change; OK.

docs/suprsend_workflow_pull.md (1)

36-36: Timestamp update acknowledged

No content change; OK.

docs/suprsend_version.md (1)

40-40: Timestamp update acknowledged

No content change; OK.

internal/commands/sync.go (2)

190-191: No action required: PushCategories’s signature is func (..., categories interface{}), so passing the concrete slice from categoriesResp.Categories into its interface{} parameter is valid.


19-68: syncCmd registration OK Registered in internal/commands/root.go via rootCmd.AddCommand(syncCmd); no changes required.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
mgmnt/client.go (1)

94-129: Harden the bridge call: add timeouts, fix URL join, check HTTP status, and limit body reads.

Currently the request can hang (no timeout), may hit a double-slash URL, and ignores non-200 statuses. Suggest the following refactor.

Apply this diff within the function:

@@
-  // Create a new HTTP client
-  client := &http.Client{}
+  // Create a new HTTP client with sane timeout
+  client := &http.Client{Timeout: 30 * time.Second}
@@
-  // Create a new GET request
-  req, err := http.NewRequest("GET", c.hub_base_URL+"/v1/"+workspace+"/ws_key/bridge/", nil)
+  // Build URL without leading slash (base already normalized with trailing slash)
+  fullURL := c.hub_base_URL + "v1/" + workspace + "/ws_key/bridge/"
+  // Create a new GET request with context timeout
+  ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
+  defer cancel()
+  req, err := http.NewRequestWithContext(ctx, http.MethodGet, fullURL, nil)
@@
-  // Send the request
+  // Send the request
   response, err := client.Do(req)
   if err != nil {
     log.Info("Error sending request: ", err)
     return "", "", err
   }
   defer response.Body.Close()
 
-  body, err := io.ReadAll(response.Body)
+  // Fail fast on non-200 responses (read small snippet for diagnostics)
+  if response.StatusCode != http.StatusOK {
+    snippet, _ := io.ReadAll(io.LimitReader(response.Body, 4096))
+    return "", "", fmt.Errorf("bridge API %s returned %d: %s", fullURL, response.StatusCode, strings.TrimSpace(string(snippet)))
+  }
+
+  body, err := io.ReadAll(io.LimitReader(response.Body, 1<<20)) // cap at 1MB
   if err != nil {
     log.Info("Error reading response body: ", err)
     return "", "", err
   }
@@
-  err = json.Unmarshal(body, &workspaceDetails)
-  if err != nil {
-    return "", "", errors.New("failed to initialize suprsend workspace client")
-  }
+  if err := json.Unmarshal(body, &workspaceDetails); err != nil {
+    return "", "", fmt.Errorf("decode bridge API response: %w", err)
+  }

And add these imports at the top:

 import (
+  "context"
   "encoding/json"
   "errors"
+  "fmt"
   "io"
   "net/http"
   "os"
   "strings"
+  "time"
 )
🧹 Nitpick comments (2)
mgmnt/client.go (2)

25-31: Thread-safety for workspaceClients map (verify usage).

If this client may be used from multiple goroutines, protect workspaceClients with a mutex (or use sync.Map). Otherwise, ignore.

Also applies to: 71-87


33-38: Consider returning an error instead of exiting in a library constructor.

log.Fatal() exits the process; returning an error would be more library-friendly. Keep if this is strictly CLI-only.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 38e847e and f4fb990.

📒 Files selected for processing (1)
  • mgmnt/client.go (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
mgmnt/**/*.go

📄 CodeRabbit inference engine (.cursor/rules/cli-structure.mdc)

Place management and client-related Go code under the mgmnt/ directory

Files:

  • mgmnt/client.go
🔇 Additional comments (1)
mgmnt/client.go (1)

66-66: Good hardening: token no longer logged.

Removing the service token from debug logs reduces accidental secret exposure. LGTM.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
go.mod (1)

70-70: Pseudo-version for sourcegraph/conc: prefer a tagged release for stability.

Pinning to a commit-based pseudo-version risks unexpected changes. Consider moving to the latest stable tag for conc.

-	github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
+	# Prefer a semver tag (example shown; adjust to an actual tag used in the repo)
+	github.com/sourcegraph/conc v0.3.0 // indirect

If we actually use conc directly, promote it to a direct require; otherwise let MVS choose via indirects.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f4fb990 and 0d51cc5.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (1)
  • go.mod (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-25T08:53:18.379Z
Learnt from: CR
PR: suprsend/cli#0
File: .cursor/rules/cli-structure.mdc:0-0
Timestamp: 2025-08-25T08:53:18.379Z
Learning: Applies to internal/config/config.go : Manage configuration in internal/config/config.go using Viper for config files and environment variables

Applied to files:

  • go.mod
🔇 Additional comments (4)
go.mod (4)

84-84: No errgroup or semaphore usage detected in the codebase; dependency update requires no additional verification.


68-73: Validate CLI and file operations: smoke test flag parsing, case handling, and file I/O to ensure the transitive upgrades of locafero, afero, cast, and pflag haven’t introduced regressions.


86-86: Drop i18n regression check for indirect x/text dependency
No import of golang.org/x/text found in the codebase, so width/locale-sensitive regression tests aren’t applicable.

Likely an incorrect or invalid review comment.


16-16: No viper.Unmarshal or mapstructure usage—v1.21.0 bump is safe. Config only calls SetConfigFile/AddConfigPath, AutomaticEnv, BindEnv, GetBool and ReadInConfig; no breaking changes expected.

github.com/xeipuuv/gojsonschema v1.2.0 // indirect
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Potential typosquat: go.yaml.in/yaml/v3 looks incorrect; remove it.

Canonical YAML module paths are gopkg.in/yaml.v3 or github.com/go-yaml/yaml. This go.yaml.in/yaml/v3 is suspicious and could break builds or pose a supply-chain risk.

Apply:

-	go.yaml.in/yaml/v3 v3.0.4 // indirect

Then:

go mod tidy -v
rg -n --type=go 'go\.yaml\.in/yaml/v3' || echo "No references found"

If any imports exist, replace them with gopkg.in/yaml.v3.

🤖 Prompt for AI Agents
In go.mod around line 80, the module entry "go.yaml.in/yaml/v3" is a typosquat
and must be removed; replace any occurrences in source imports with the
canonical "gopkg.in/yaml.v3" (or switch to "github.com/go-yaml/yaml" if you
prefer that variant), then run go mod tidy to update go.mod/go.sum and verify
there are no remaining references with a ripgrep search; if ripgrep finds
imports update those files to the canonical path and re-run go mod tidy until no
references remain.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (2)
mgmnt/category.go (2)

55-66: SetResult must receive a pointer; also add a safe assertion.

Avoid panics and ensure Resty unmarshals into the provided struct.

-        SetResult(PreferenceCategoryResponse{}).
-        Get(url)
+        SetResult(&PreferenceCategoryResponse{}).
+        Get(endpoint)
@@
-    result := resp.Result().(*PreferenceCategoryResponse)
-    return result, nil
+    res, ok := resp.Result().(*PreferenceCategoryResponse)
+    if !ok || res == nil {
+        return nil, fmt.Errorf("unexpected response type for categories")
+    }
+    return res, nil

3-8: URL-encode commit_message and avoid future package shadowing.

Commit messages with spaces/special chars break the request. Also prepare imports so url refers to net/url, not a local var.

 import (
     "fmt"
+    "net/url"
     "time"
 
     "github.com/suprsend/cli/internal/client"
 )
-    endpoint := fmt.Sprintf("%sv1/%s/preference_category/commit/?commit_message=%s", c.mgmnt_base_URL, workspace, commitMsg)
+    // Encode path and query parts
+    escapedWS := url.PathEscape(workspace)
+    escMsg := url.QueryEscape(commitMsg)
+    endpoint := fmt.Sprintf("%sv1/%s/preference_category/commit/?commit_message=%s", c.mgmnt_base_URL, escapedWS, escMsg)
-    resp, err := client.R().
+    resp, err := httpc.R().
         SetDebug(c.debug).
         SetHeader("Authorization", "ServiceToken "+c.serviceToken).
-        Patch(url)
+        Patch(endpoint)

Also applies to: 91-99

🧹 Nitpick comments (5)
internal/commands/category/category_list.go (4)

25-25: Polish help text grammar (“preference categories”).

Use singular “preference” here.

-    Long:  "List preferences categories in a workspace",
+    Long:  "List preference categories in a workspace",

14-20: Add yaml tags for consistent JSON/YAML keys.

YAML output will currently use Go field names (e.g., RootCategory). Add yaml tags to mirror json tags.

 type CategoryTableRow struct {
-    RootCategory             string `json:"root_category"`
-    Section                  string `json:"section"`
-    CategoryName             string `json:"category_name"`
-    DefaultPreference        string `json:"default_preference"`
-    DefaultMandatoryChannels string `json:"default_mandatory_channels"`
+    RootCategory             string `json:"root_category" yaml:"root_category"`
+    Section                  string `json:"section" yaml:"section"`
+    CategoryName             string `json:"category_name" yaml:"category_name"`
+    DefaultPreference        string `json:"default_preference" yaml:"default_preference"`
+    DefaultMandatoryChannels string `json:"default_mandatory_channels" yaml:"default_mandatory_channels"`
 }

42-45: Improve error logs with context (workspace, mode).

Makes troubleshooting easier and keeps logs uniform.

-        log.WithError(err).Error("Couldn't fetch categories")
+        log.WithError(err).
+            WithFields(log.Fields{"workspace": workspace, "mode": mode}).
+            Error("couldn't fetch categories")

46-48: Guard against nil response to avoid a panic.

If the HTTP layer returns a nil pointer, the loop below will panic.

         outputType, _ := cmd.Flags().GetString("output")
 
+        if categories == nil {
+            log.Error("nil category response received")
+            return
+        }
+
         // Create flattened table rows
mgmnt/category.go (1)

47-47: Avoid package shadowing by renaming local client var to httpc.

Prevents hiding the imported client package and improves readability.

-    client := client.NewHTTPClient()
+    httpc := client.NewHTTPClient()

Also applies to: 70-70, 92-92

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0d51cc5 and a15ca87.

📒 Files selected for processing (2)
  • internal/commands/category/category_list.go (1 hunks)
  • mgmnt/category.go (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
mgmnt/**/*.go

📄 CodeRabbit inference engine (.cursor/rules/cli-structure.mdc)

Place management and client-related Go code under the mgmnt/ directory

Files:

  • mgmnt/category.go
internal/commands/**/!(root).go

📄 CodeRabbit inference engine (.cursor/rules/command-registration.mdc)

Register each subcommand by calling rootCmd.AddCommand(...) in the subcommand’s own init() function

Files:

  • internal/commands/category/category_list.go
🧠 Learnings (1)
📚 Learning: 2025-08-25T08:53:18.379Z
Learnt from: CR
PR: suprsend/cli#0
File: .cursor/rules/cli-structure.mdc:0-0
Timestamp: 2025-08-25T08:53:18.379Z
Learning: Applies to mgmnt/**/*.go : Place management and client-related Go code under the mgmnt/ directory

Applied to files:

  • mgmnt/category.go
🧬 Code graph analysis (2)
mgmnt/category.go (2)
mgmnt/client.go (1)
  • SS_MgmntClient (25-31)
internal/client/httpclient.go (1)
  • NewHTTPClient (11-27)
internal/commands/category/category_list.go (4)
mgmnt/category.go (1)
  • Section (24-31)
internal/utils/outpututil.go (2)
  • IsOutputPiped (25-34)
  • OutputData (51-61)
internal/utils/sdk_instance.go (1)
  • GetSuprSendMgmntClient (23-25)
internal/commands/category/category.go (1)
  • CategoryCmd (5-9)

Comment on lines +47 to +49
client := client.NewHTTPClient()
defer client.Close()
url := fmt.Sprintf("%sv1/%s/preference_category/?mode=%s", c.mgmnt_base_URL, workspace, mode)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Potential compile/runtime issue: resty.Client doesn’t expose Close(). Use CloseIdleConnections (or remove).

Calling client.Close() will fail; prefer closing idle connections on the underlying http.Client.

-    client := client.NewHTTPClient()
-    defer client.Close()
+    httpc := client.NewHTTPClient()
+    defer httpc.GetClient().CloseIdleConnections()
-    url := fmt.Sprintf("%sv1/%s/preference_category/?mode=%s", c.mgmnt_base_URL, workspace, mode)
+    endpoint := fmt.Sprintf("%sv1/%s/preference_category/?mode=%s", c.mgmnt_base_URL, workspace, mode)
-    client := client.NewHTTPClient()
-    defer client.Close()
-    url := fmt.Sprintf("%sv1/%s/preference_category/", c.mgmnt_base_URL, workspace)
+    httpc := client.NewHTTPClient()
+    defer httpc.GetClient().CloseIdleConnections()
+    endpoint := fmt.Sprintf("%sv1/%s/preference_category/", c.mgmnt_base_URL, workspace)
-    client := client.NewHTTPClient()
-    defer client.Close()
-    url := fmt.Sprintf("%sv1/%s/preference_category/commit/?commit_message=%s", c.mgmnt_base_URL, workspace, commitMsg)
+    httpc := client.NewHTTPClient()
+    defer httpc.GetClient().CloseIdleConnections()
+    endpoint := fmt.Sprintf("%sv1/%s/preference_category/commit/?commit_message=%s", c.mgmnt_base_URL, workspace, commitMsg)

Also applies to: 70-73, 92-95

🤖 Prompt for AI Agents
In mgmnt/category.go around lines 47-49 (also apply same fix at 70-73 and
92-95): the code calls client.Close() on a resty.Client which doesn't exist and
will not compile; replace that call by closing idle connections on the
underlying net/http client — call client.GetClient() and invoke
CloseIdleConnections() (guarding for nil if needed), or simply remove the
Close() call if you don't need to close connections; update all three locations
accordingly.

Comment on lines +49 to +56
url := fmt.Sprintf("%sv1/%s/preference_category/?mode=%s", c.mgmnt_base_URL, workspace, mode)

resp, err := client.R().
SetDebug(c.debug).
SetHeader("Authorization", "ServiceToken "+c.serviceToken).
SetHeader("Content-Type", "application/json").
SetResult(PreferenceCategoryResponse{}).
Get(url)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Also escape workspace path segment and use the renamed client var.

Prevents issues if workspace contains reserved chars; keeps naming consistent after the httpc rename.

-    url := fmt.Sprintf("%sv1/%s/preference_category/?mode=%s", c.mgmnt_base_URL, workspace, mode)
-    resp, err := client.R().
+    escapedWS := url.PathEscape(workspace)
+    endpoint := fmt.Sprintf("%sv1/%s/preference_category/?mode=%s", c.mgmnt_base_URL, escapedWS, mode)
+    resp, err := httpc.R().
         SetDebug(c.debug).
         SetHeader("Authorization", "ServiceToken "+c.serviceToken).
         SetHeader("Content-Type", "application/json").
-        SetResult(PreferenceCategoryResponse{}).
-        Get(url)
+        SetResult(&PreferenceCategoryResponse{}).
+        Get(endpoint)
-    url := fmt.Sprintf("%sv1/%s/preference_category/", c.mgmnt_base_URL, workspace)
-    resp, err := client.R().
+    escapedWS := url.PathEscape(workspace)
+    endpoint := fmt.Sprintf("%sv1/%s/preference_category/", c.mgmnt_base_URL, escapedWS)
+    resp, err := httpc.R().
         SetDebug(c.debug).
         SetHeader("Authorization", "ServiceToken "+c.serviceToken).
         SetHeader("Content-Type", "application/json").
         SetBody(categories).
-        Post(url)
+        Post(endpoint)

Also applies to: 74-80

🤖 Prompt for AI Agents
In mgmnt/category.go around lines 49 to 56, the workspace path segment is
included raw in the URL and the HTTP client variable was renamed; update the
code to URL-escape the workspace segment (use url.PathEscape(workspace)) when
building the fmt.Sprintf URL and replace the old client variable with the
renamed httpc variable when making the request
(SetDebug/SetHeader/SetResult/Get). Make the same two changes for the other
occurrence at lines 74-80.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (5)
docs/suprsend.md (1)

17-17: Fix typo: “Output Tyle” → “Output Type” (correct at source, then regenerate docs).

This is already flagged earlier; keep a single source of truth in the flag help.

Upstream change (example, root persistent flag):

-  -o, --output string          Output Tyle (pretty, yaml, json) (default "pretty")
+  -o, --output string          Output Type (pretty, yaml, json) (default "pretty")
docs/suprsend_category_push.md (1)

24-24: Fix typo: “Output Tyle” → “Output Type”.

Matches prior comments across docs; regenerate after fixing flag help in code.

-  -o, --output string          Output Tyle (pretty, yaml, json) (default "pretty")
+  -o, --output string          Output Type (pretty, yaml, json) (default "pretty")
docs/suprsend_category_commit.md (1)

26-26: Fix typo: “Output Tyle” → “Output Type”.

Same issue as other pages.

-  -o, --output string          Output Tyle (pretty, yaml, json) (default "pretty")
+  -o, --output string          Output Type (pretty, yaml, json) (default "pretty")
docs/suprsend_category.md (1)

21-21: Fix typo: “Output Tyle” → “Output Type”.

-  -o, --output string          Output Tyle (pretty, yaml, json) (default "pretty")
+  -o, --output string          Output Type (pretty, yaml, json) (default "pretty")
docs/suprsend_category_pull.md (1)

25-25: Fix typo: “Output Tyle” → “Output Type”.

-  -o, --output string          Output Tyle (pretty, yaml, json) (default "pretty")
+  -o, --output string          Output Type (pretty, yaml, json) (default "pretty")
🧹 Nitpick comments (10)
docs/suprsend.md (1)

25-25: Replace hard tab with spaces in SEE ALSO bullet.

Tabs break markdownlint (MD010) and some renderers.

-* [suprsend category](suprsend_category.md)	 - Manage preference categories
+* [suprsend category](suprsend_category.md)  - Manage preference categories
docs/suprsend_category_push.md (2)

9-11: Add fenced code languages and keep formatting consistent.

Silences MD040 and improves rendering.

-```
+```bash
 suprsend category push [flags]

- +text
-h, --help help for push


-```
+```text
      --config string          config file (default: $HOME/.suprsend.yaml)
  -n, --no-color               Disable color output (default: $NO_COLOR)
  -o, --output string          Output Type (pretty, yaml, json) (default "pretty")
  -s, --service-token string   Service token (default: $SUPRSEND_SERVICE_TOKEN)
  -v, --verbosity string       Log level (debug, info, warn, error, fatal, panic) (default "info")
      --workspace string       Workspace to push categories to (default "staging")


Also applies to: 15-17, 21-28

---

`32-32`: **Replace hard tab with spaces in SEE ALSO bullet.**

MD010 no-hard-tabs.


```diff
-* [suprsend category](suprsend_category.md)	 - Manage preference categories
+* [suprsend category](suprsend_category.md)  - Manage preference categories
docs/suprsend_category_commit.md (1)

9-11: Add fenced code languages.

Addresses MD040.

-```
+```bash
 suprsend category commit [flags]

- +text
--commit-message string Commit message
-h, --help help for commit
--workspace string Workspace to commit categories to (default "staging")


-```
+```text
      --config string          config file (default: $HOME/.suprsend.yaml)
  -n, --no-color               Disable color output (default: $NO_COLOR)
  -o, --output string          Output Type (pretty, yaml, json) (default "pretty")
  -s, --service-token string   Service token (default: $SUPRSEND_SERVICE_TOKEN)
  -v, --verbosity string       Log level (debug, info, warn, error, fatal, panic) (default "info")


Also applies to: 15-19, 23-29

</blockquote></details>
<details>
<summary>docs/suprsend_category.md (3)</summary><blockquote>

`13-13`: **Generalize workspace flag help (command group).**

“push categories to” is subcommand-specific; use neutral phrasing.


```diff
-      --workspace string   Workspace to push categories to (default "staging")
+      --workspace string   Workspace to use (default "staging")

11-14: Add fenced code languages.

Silences MD040.

-```
+```text
   -h, --help               help for category
       --workspace string   Workspace to use (default "staging")

- +text
--config string config file (default: $HOME/.suprsend.yaml)
-n, --no-color Disable color output (default: $NO_COLOR)
-o, --output string Output Type (pretty, yaml, json) (default "pretty")
-s, --service-token string Service token (default: $SUPRSEND_SERVICE_TOKEN)
-v, --verbosity string Log level (debug, info, warn, error, fatal, panic) (default "info")

Also applies to: 18-24


28-33: Replace hard tabs with spaces in SEE ALSO bullets.

MD010 no-hard-tabs.

-* [suprsend](suprsend.md)	 - CLI to interact with SuprSend, a Notification Infrastructure
-* [suprsend category commit](suprsend_category_commit.md)	 - Commit categories
-* [suprsend category list](suprsend_category_list.md)	 - List categories
-* [suprsend category pull](suprsend_category_pull.md)	 - Pull categories from a workspace
-* [suprsend category push](suprsend_category_push.md)	 - Push categories to a workspace
+* [suprsend](suprsend.md)  - CLI to interact with SuprSend, a Notification Infrastructure
+* [suprsend category commit](suprsend_category_commit.md)  - Commit categories
+* [suprsend category list](suprsend_category_list.md)  - List categories
+* [suprsend category pull](suprsend_category_pull.md)  - Pull categories from a workspace
+* [suprsend category push](suprsend_category_push.md)  - Push categories to a workspace
docs/suprsend_category_pull.md (3)

28-28: Align workspace flag help with pull action.

Use “pull categories from”.

-      --workspace string       Workspace to push categories to (default "staging")
+      --workspace string       Workspace to pull categories from (default "staging")

9-11: Add fenced code languages.

Addresses MD040.

-```
+```bash
 suprsend category pull [flags]

- +text
-h, --help help for pull
--mode string Mode to pull categories from (default "live")


-```
+```text
      --config string          config file (default: $HOME/.suprsend.yaml)
  -n, --no-color               Disable color output (default: $NO_COLOR)
  -o, --output string          Output Type (pretty, yaml, json) (default "pretty")
  -s, --service-token string   Service token (default: $SUPRSEND_SERVICE_TOKEN)
  -v, --verbosity string       Log level (debug, info, warn, error, fatal, panic) (default "info")
      --workspace string       Workspace to pull categories from (default "staging")


Also applies to: 15-18, 22-29

---

`33-33`: **Replace hard tab with spaces in SEE ALSO bullet.**


```diff
-* [suprsend category](suprsend_category.md)	 - Manage preference categories
+* [suprsend category](suprsend_category.md)  - Manage preference categories
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a15ca87 and 519aba4.

📒 Files selected for processing (42)
  • docs/suprsend.md (1 hunks)
  • docs/suprsend_category.md (1 hunks)
  • docs/suprsend_category_commit.md (1 hunks)
  • docs/suprsend_category_list.md (1 hunks)
  • docs/suprsend_category_pull.md (1 hunks)
  • docs/suprsend_category_push.md (1 hunks)
  • docs/suprsend_completion.md (0 hunks)
  • docs/suprsend_completion_bash.md (0 hunks)
  • docs/suprsend_completion_fish.md (0 hunks)
  • docs/suprsend_completion_powershell.md (0 hunks)
  • docs/suprsend_completion_zsh.md (0 hunks)
  • docs/suprsend_generate-types.md (0 hunks)
  • docs/suprsend_generate-types_dart.md (0 hunks)
  • docs/suprsend_generate-types_go.md (0 hunks)
  • docs/suprsend_generate-types_java.md (0 hunks)
  • docs/suprsend_generate-types_kotlin.md (0 hunks)
  • docs/suprsend_generate-types_python.md (0 hunks)
  • docs/suprsend_generate-types_swift.md (0 hunks)
  • docs/suprsend_generate-types_typescript.md (0 hunks)
  • docs/suprsend_profile.md (0 hunks)
  • docs/suprsend_profile_add.md (0 hunks)
  • docs/suprsend_profile_list.md (0 hunks)
  • docs/suprsend_profile_modify.md (0 hunks)
  • docs/suprsend_profile_remove.md (0 hunks)
  • docs/suprsend_profile_use.md (0 hunks)
  • docs/suprsend_schema.md (0 hunks)
  • docs/suprsend_schema_commit.md (0 hunks)
  • docs/suprsend_schema_list.md (0 hunks)
  • docs/suprsend_schema_pull.md (0 hunks)
  • docs/suprsend_schema_push.md (0 hunks)
  • docs/suprsend_schema_reset.md (0 hunks)
  • docs/suprsend_start-mcp-server.md (0 hunks)
  • docs/suprsend_start-mcp-server_list-tools.md (0 hunks)
  • docs/suprsend_sync.md (0 hunks)
  • docs/suprsend_version.md (1 hunks)
  • docs/suprsend_workflow.md (0 hunks)
  • docs/suprsend_workflow_disable.md (0 hunks)
  • docs/suprsend_workflow_enable.md (0 hunks)
  • docs/suprsend_workflow_list.md (0 hunks)
  • docs/suprsend_workflow_pull.md (0 hunks)
  • docs/suprsend_workflow_push.md (0 hunks)
  • internal/commands/root.go (3 hunks)
💤 Files with no reviewable changes (34)
  • docs/suprsend_completion_zsh.md
  • docs/suprsend_completion.md
  • docs/suprsend_profile_list.md
  • docs/suprsend_completion_bash.md
  • docs/suprsend_completion_powershell.md
  • docs/suprsend_sync.md
  • docs/suprsend_schema_reset.md
  • docs/suprsend_generate-types_java.md
  • docs/suprsend_completion_fish.md
  • docs/suprsend_schema_push.md
  • docs/suprsend_workflow_enable.md
  • docs/suprsend_profile_use.md
  • docs/suprsend_profile_remove.md
  • docs/suprsend_profile_add.md
  • docs/suprsend_workflow.md
  • docs/suprsend_schema_commit.md
  • docs/suprsend_start-mcp-server.md
  • docs/suprsend_generate-types_go.md
  • docs/suprsend_workflow_push.md
  • docs/suprsend_workflow_pull.md
  • docs/suprsend_workflow_list.md
  • docs/suprsend_generate-types_swift.md
  • docs/suprsend_generate-types.md
  • docs/suprsend_schema.md
  • docs/suprsend_schema_pull.md
  • docs/suprsend_schema_list.md
  • docs/suprsend_generate-types_python.md
  • docs/suprsend_generate-types_kotlin.md
  • docs/suprsend_generate-types_dart.md
  • docs/suprsend_workflow_disable.md
  • docs/suprsend_profile.md
  • docs/suprsend_start-mcp-server_list-tools.md
  • docs/suprsend_generate-types_typescript.md
  • docs/suprsend_profile_modify.md
✅ Files skipped from review due to trivial changes (1)
  • docs/suprsend_category_list.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • docs/suprsend_version.md
  • internal/commands/root.go
🧰 Additional context used
📓 Path-based instructions (1)
docs/**/*.md

📄 CodeRabbit inference engine (.cursor/rules/cli-structure.mdc)

Store CLI command and usage documentation as Markdown under docs/

Files:

  • docs/suprsend.md
  • docs/suprsend_category.md
  • docs/suprsend_category_commit.md
  • docs/suprsend_category_pull.md
  • docs/suprsend_category_push.md
🧠 Learnings (1)
📚 Learning: 2025-08-25T08:53:18.379Z
Learnt from: CR
PR: suprsend/cli#0
File: .cursor/rules/cli-structure.mdc:0-0
Timestamp: 2025-08-25T08:53:18.379Z
Learning: Applies to cmd/suprsend/main.go : The CLI entry point is cmd/suprsend/main.go and should invoke commands.Execute()

Applied to files:

  • docs/suprsend.md
🪛 markdownlint-cli2 (0.17.2)
docs/suprsend.md

25-25: Hard tabs
Column: 44

(MD010, no-hard-tabs)

docs/suprsend_category.md

9-9: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


15-15: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


22-22: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


33-33: Hard tabs
Column: 44

(MD010, no-hard-tabs)

docs/suprsend_category_commit.md

5-5: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


11-11: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


22-22: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


29-29: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

docs/suprsend_category_pull.md

9-9: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


15-15: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


23-23: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


33-33: Hard tabs
Column: 44

(MD010, no-hard-tabs)

docs/suprsend_category_push.md

11-11: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


18-18: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


28-28: Hard tabs
Column: 26

(MD010, no-hard-tabs)


29-29: Hard tabs
Column: 58

(MD010, no-hard-tabs)


30-30: Hard tabs
Column: 54

(MD010, no-hard-tabs)


31-31: Hard tabs
Column: 54

(MD010, no-hard-tabs)


32-32: Hard tabs
Column: 54

(MD010, no-hard-tabs)

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
internal/utils/outpututil.go (2)

192-195: Make merge behavior adaptive: MergeNone when piped, hierarchical in TTY

Keeps machine-readability for pipes while preserving compact visuals in interactive terminals.

Apply this minimal inline diff:

-                    MergeMode: tw.MergeNone,
+                    MergeMode: func() tw.MergeMode {
+                        if IsOutputPiped() || viper.GetBool("TABLE_NO_MERGE") {
+                            return tw.MergeNone
+                        }
+                        return tw.MergeHierarchical
+                    }(),

178-186: Header visibility seems inconsistent (ShowHeader: Off, but headers are set and header line is On)

If human-readable headers are desired in TTY, enable them; keep them off when piped.

Apply this diff to toggle headers based on TTY:

-                Separators: tw.Separators{BetweenRows: tw.Off, BetweenColumns: tw.On, ShowHeader: tw.Off, ShowFooter: tw.Off},
+                Separators: tw.Separators{
+                    BetweenRows:  tw.Off,
+                    BetweenColumns: tw.On,
+                    ShowHeader: func() tw.OnOff {
+                        if IsOutputPiped() {
+                            return tw.Off
+                        }
+                        return tw.On
+                    }(),
+                    ShowFooter: tw.Off,
+                },

Please confirm the intended behavior for category list output:

  • When run interactively, do you want a visible header row?
  • When output is piped/redirected, should headers remain hidden?

Also applies to: 200-207

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 519aba4 and b78b1ab.

📒 Files selected for processing (1)
  • internal/utils/outpututil.go (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
internal/utils/outpututil.go

📄 CodeRabbit inference engine (.cursor/rules/cli-structure.mdc)

Handle output formatting in internal/utils/outpututil.go

Files:

  • internal/utils/outpututil.go
🧠 Learnings (1)
📚 Learning: 2025-08-25T08:53:18.379Z
Learnt from: CR
PR: suprsend/cli#0
File: .cursor/rules/cli-structure.mdc:0-0
Timestamp: 2025-08-25T08:53:18.379Z
Learning: Applies to internal/utils/outpututil.go : Handle output formatting in internal/utils/outpututil.go

Applied to files:

  • internal/utils/outpututil.go
🔇 Additional comments (1)
internal/utils/outpututil.go (1)

192-195: LGTM: switching to non-merged rows improves flat/CSV-friendly output

This aligns with the new category list UX where repeated values per row are desirable.

@gauravverma gauravverma merged commit af266f3 into main Sep 10, 2025
1 check passed
@gauravverma gauravverma deleted the feat/pref-cat branch September 10, 2025 16:33
@coderabbitai coderabbitai bot mentioned this pull request Sep 10, 2025
@coderabbitai coderabbitai bot mentioned this pull request Oct 8, 2025
@coderabbitai coderabbitai bot mentioned this pull request Dec 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants