Skip to content

Add wsh wavepath command for getting Wave paths #1545

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Merged
merged 3 commits into from
Dec 17, 2024
Merged

Conversation

esimkowitz
Copy link
Member

@esimkowitz esimkowitz commented Dec 17, 2024

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced a new command wavepath to retrieve paths for configuration, data, and log files via CLI.
    • Added PathCommand functionality to handle path-related commands in the application.
    • Enhanced layout management with improved handling of ephemeral nodes.
  • Bug Fixes

    • Improved error handling and validation for the new wavepath command.
  • Documentation

    • Updated documentation to include usage instructions and examples for the wavepath command.
  • Type Enhancements

    • Added new properties and types to support path-related functionalities and ephemeral node management.

Copy link
Contributor

coderabbitai bot commented Dec 17, 2024

Walkthrough

The pull request introduces a new wavepath command and associated functionality across multiple files. The changes enable retrieving and managing paths for configuration, data, and log directories in the Wave Terminal application. A new RPC command PathCommand is implemented to support path-related operations, with the ability to open paths internally or externally. The modifications span frontend, backend, and CLI components, adding support for ephemeral nodes and enhancing path management capabilities.

Changes

File Change Summary
frontend/app/store/wshclientapi.ts Added PathCommand method to RpcApiType class
frontend/layout/lib/layoutModel.ts Enhanced handling of ephemeral nodes in layout management
frontend/types/gotypes.d.ts Added ephemeral property to types and new PathCommandData type
go.mod Updated dependencies, added open-golang package
pkg/waveobj/wtype.go Added Ephemeral field to LayoutActionData struct
pkg/wshrpc/wshclient/wshclient.go Added PathCommand function
pkg/wshrpc/wshrpctypes.go Added PathCommand method and PathCommandData type
pkg/wshrpc/wshserver/wshserver.go Implemented PathCommand method for path handling
cmd/wsh/cmd/wshcmd-wavepath.go New CLI command for path retrieval and management
docs/docs/wsh-reference.mdx Added documentation for new wavepath command

Sequence Diagram

sequenceDiagram
    participant User
    participant CLI
    participant RPCClient
    participant WshServer
    
    User->>CLI: Execute wavepath command
    CLI->>RPCClient: Call PathCommand
    RPCClient->>WshServer: Send path request
    WshServer-->>RPCClient: Return path
    RPCClient-->>CLI: Provide path
    alt Open Internal
        CLI->>WshServer: Create block with path
    end
    alt Open External
        CLI->>System: Open path in external application
    end
Loading

Poem

🐰 A Rabbit's Path to Delight

Through config, data, and log so bright,
Wavepath hops with command might!
Ephemeral nodes dance with glee,
Open paths, set my spirit free!
Terminal magic, pure and light! 🌟

Tip

CodeRabbit's docstrings feature is now available as part of our Early Access Program! Simply use the command @coderabbitai generate docstrings to have CodeRabbit automatically generate docstrings for your pull request. We would love to hear your feedback on Discord.


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

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 (5)
cmd/wsh/cmd/wshcmd-path.go (2)

12-19: Enhance command documentation with examples and detailed description

Consider adding usage examples and a more detailed description to help users understand the command better.

 var pathCommand = &cobra.Command{
 	Use:       "path [flags] config|data|log",
-	Short:     "Get paths to various waveterm files and directories",
+	Short:     "Get paths to various Waveterm files and directories",
+	Long:      "Get paths to various Waveterm files and directories. Use flags to open paths in a new block or external application.",
+	Example: `  # Get config file path
+  wsh path config
+  # Open data directory in default application
+  wsh path data --open-external
+  # Open log file in a new block
+  wsh path log --open`,
 	ValidArgs: []string{"config", "data", "log"},
 	Args:      cobra.MatchAll(cobra.OnlyValidArgs, cobra.ExactArgs(1)),
 	Run:       runPathCommand,
 	PreRunE:   preRunSetupRpcClient,
 }

21-25: Consider making --open and --open-external flags mutually exclusive

Opening a path both internally and externally might lead to unexpected behavior.

Add flag validation in PreRunE:

 func init() {
 	pathCommand.Flags().BoolP("open", "o", false, "Open the path in a new block")
 	pathCommand.Flags().BoolP("open-external", "O", false, "Open the path in the default external application")
+	oldPreRunE := pathCommand.PreRunE
+	pathCommand.PreRunE = func(cmd *cobra.Command, args []string) error {
+		if err := oldPreRunE(cmd, args); err != nil {
+			return err
+		}
+		open, _ := cmd.Flags().GetBool("open")
+		openExternal, _ := cmd.Flags().GetBool("open-external")
+		if open && openExternal {
+			return fmt.Errorf("--open and --open-external flags cannot be used together")
+		}
+		return nil
+	}
 	rootCmd.AddCommand(pathCommand)
 }
pkg/waveobj/wtype.go (1)

211-211: Add documentation for the Ephemeral field

The purpose and behavior of the Ephemeral field should be documented.

 type LayoutActionData struct {
 	ActionType string `json:"actiontype"`
 	BlockId    string `json:"blockid"`
 	NodeSize   *uint  `json:"nodesize,omitempty"`
 	IndexArr   *[]int `json:"indexarr,omitempty"`
 	Focused    bool   `json:"focused"`
 	Magnified  bool   `json:"magnified"`
-	Ephemeral  bool   `json:"ephemeral"`
+	// Ephemeral indicates whether the block should be treated as temporary
+	// and cleaned up when the window is closed
+	Ephemeral bool `json:"ephemeral"`
 }
pkg/wshrpc/wshrpctypes.go (1)

609-614: Consider adding documentation for PathType values.

While the struct is well-designed, it would benefit from:

  1. Documentation comments describing valid values for the PathType field
  2. Constants defining the allowed path types
  3. Validation logic for the path type values
+// PathType values: "config", "data", "log", etc.
+const (
+    PathTypeConfig = "config"
+    PathTypeData   = "data"
+    PathTypeLog    = "log"
+)
+
 type PathCommandData struct {
     PathType     string `json:"pathtype"`
     Open         bool   `json:"open"`
     OpenExternal bool   `json:"openexternal"`
     TabId        string `json:"tabid" wshcontext:"TabId"`
 }
frontend/types/gotypes.d.ts (1)

404-404: Consider making ephemeral property optional

The ephemeral property in LayoutActionData is marked as required, but it might be better to make it optional for backward compatibility.

-        ephemeral: boolean;
+        ephemeral?: boolean;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f5305cc and 6c67ac6.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (9)
  • cmd/wsh/cmd/wshcmd-path.go (1 hunks)
  • frontend/app/store/wshclientapi.ts (1 hunks)
  • frontend/layout/lib/layoutModel.ts (1 hunks)
  • frontend/types/gotypes.d.ts (3 hunks)
  • go.mod (1 hunks)
  • pkg/waveobj/wtype.go (1 hunks)
  • pkg/wshrpc/wshclient/wshclient.go (1 hunks)
  • pkg/wshrpc/wshrpctypes.go (3 hunks)
  • pkg/wshrpc/wshserver/wshserver.go (3 hunks)
🔇 Additional comments (9)
go.mod (1)

23-23: Verify security status of open-golang dependency

The github.com/skratchdot/open-golang package hasn't been updated since 2020. Consider alternatives or verify its security status.

✅ Verification successful

Based on the results, I can generate the final response:

Package github.com/skratchdot/open-golang appears safe to use

While the package hasn't been updated since January 2020, the verification shows:

  • No security vulnerabilities reported in GitHub's advisory database
  • Simple, focused functionality with minimal attack surface
  • No critical open issues (17 total issues, mostly feature requests/discussions)

The package's inactivity is not a major concern given its stable, single-purpose nature of providing cross-platform file opening capabilities.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for known vulnerabilities and activity status

# Check latest commit date and activity
gh api repos/skratchdot/open-golang/commits/master --jq '.commit.committer.date'

# Check open issues and PRs
gh api repos/skratchdot/open-golang/issues --jq 'length'

# Check for security advisories
gh api graphql -f query='
{
  securityVulnerabilities(first: 5, ecosystem: GO, package: "github.com/skratchdot/open-golang") {
    nodes {
      advisory {
        summary
        severity
        publishedAt
      }
      vulnerableVersionRange
    }
  }
}'

# Look for alternative packages
rg -l 'import.*"os/exec".*xdg-open|start|open' 

Length of output: 5074

frontend/app/store/wshclientapi.ts (1)

205-208: LGTM! The PathCommand implementation follows established patterns.

The implementation is consistent with other RPC commands in the class and properly handles types and error cases.

pkg/wshrpc/wshclient/wshclient.go (1)

250-254: LGTM! The PathCommand function follows established patterns.

The implementation is consistent with other RPC command functions and properly handles the RPC communication and error cases.

pkg/wshrpc/wshrpctypes.go (1)

294-294: LGTM! The Ephemeral field addition is well-structured.

The field follows Go naming conventions and is properly tagged for JSON serialization.

pkg/wshrpc/wshserver/wshserver.go (2)

188-188: LGTM: Ephemeral field added to CreateBlockCommand

The addition of the Ephemeral field to the layout action is consistent with the changes in the frontend types.


836-870: ⚠️ Potential issue

Verify error handling and path security

The PathCommand implementation has a few concerns that need to be addressed:

  1. The path construction could potentially lead to path traversal if not properly sanitized
  2. Error handling could be more specific for different failure scenarios
  3. The external path opening could pose security risks if not properly validated

Consider applying these improvements:

 func (ws *WshServer) PathCommand(ctx context.Context, data wshrpc.PathCommandData) (string, error) {
+    if err := validatePathType(data.PathType); err != nil {
+        return "", fmt.Errorf("invalid path type: %w", err)
+    }
+
     var path string
     switch pathType {
     case "config":
         path = wavebase.GetWaveConfigDir()
     case "data":
         path = wavebase.GetWaveDataDir()
     case "log":
         path = filepath.Join(wavebase.GetWaveDataDir(), "waveapp.log")
+    default:
+        return "", fmt.Errorf("unsupported path type: %s", pathType)
     }
 
+    // Ensure the path exists and is accessible
+    if _, err := os.Stat(path); err != nil {
+        return "", fmt.Errorf("path access error: %w", err)
+    }
+
     if openInternal && openExternal {
         return "", fmt.Errorf("open and openExternal cannot both be true")
     }
 
     if openInternal {
         _, err := ws.CreateBlockCommand(ctx, wshrpc.CommandCreateBlockData{BlockDef: &waveobj.BlockDef{Meta: map[string]any{
             waveobj.MetaKey_View: "preview",
             waveobj.MetaKey_File: path,
         }}, Ephemeral: true, TabId: data.TabId})
 
         if err != nil {
-            return path, fmt.Errorf("error opening path: %w", err)
+            return "", fmt.Errorf("error opening path internally: %w", err)
         }
     } else if openExternal {
+        // Validate path before opening externally
+        if err := validateExternalPath(path); err != nil {
+            return "", fmt.Errorf("invalid external path: %w", err)
+        }
+
         err := open.Run(path)
         if err != nil {
-            return path, fmt.Errorf("error opening path: %w", err)
+            return "", fmt.Errorf("error opening path externally: %w", err)
         }
     }
     return path, nil
 }

Run the following script to check for similar path handling patterns in the codebase:

frontend/types/gotypes.d.ts (2)

567-573: LGTM: PathCommandData type definition

The type definition is well-structured and includes all necessary properties for path command handling.


142-142: LGTM: Optional ephemeral property in CommandCreateBlockData

The optional ephemeral property is correctly typed as boolean and aligns with the backend changes.

frontend/layout/lib/layoutModel.ts (1)

415-419: LGTM: Ephemeral node handling

The implementation correctly handles ephemeral nodes by creating them through newEphemeralNode when the action indicates it's ephemeral.

Comment on lines 27 to 41
func runPathCommand(cmd *cobra.Command, args []string) {
pathType := args[0]
open, _ := cmd.Flags().GetBool("open")
openExternal, _ := cmd.Flags().GetBool("open-external")
path, err := wshclient.PathCommand(RpcClient, wshrpc.PathCommandData{
PathType: pathType,
Open: open,
OpenExternal: openExternal,
}, nil)
if err != nil {
WriteStderr("Error getting path: %v\n", err)
return
}
WriteStdout("%s\n", path)
}
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

Improve error handling in runPathCommand

The function ignores potential flag retrieval errors and could provide more specific error messages.

 func runPathCommand(cmd *cobra.Command, args []string) {
 	pathType := args[0]
-	open, _ := cmd.Flags().GetBool("open")
-	openExternal, _ := cmd.Flags().GetBool("open-external")
+	open, err := cmd.Flags().GetBool("open")
+	if err != nil {
+		WriteStderr("Error getting open flag: %v\n", err)
+		return
+	}
+	openExternal, err := cmd.Flags().GetBool("open-external")
+	if err != nil {
+		WriteStderr("Error getting open-external flag: %v\n", err)
+		return
+	}
 	path, err := wshclient.PathCommand(RpcClient, wshrpc.PathCommandData{
 		PathType:     pathType,
 		Open:         open,
 		OpenExternal: openExternal,
 	}, nil)
 	if err != nil {
-		WriteStderr("Error getting path: %v\n", err)
+		WriteStderr("Error getting %s path: %v\n", pathType, err)
 		return
 	}
 	WriteStdout("%s\n", path)
 }
📝 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
func runPathCommand(cmd *cobra.Command, args []string) {
pathType := args[0]
open, _ := cmd.Flags().GetBool("open")
openExternal, _ := cmd.Flags().GetBool("open-external")
path, err := wshclient.PathCommand(RpcClient, wshrpc.PathCommandData{
PathType: pathType,
Open: open,
OpenExternal: openExternal,
}, nil)
if err != nil {
WriteStderr("Error getting path: %v\n", err)
return
}
WriteStdout("%s\n", path)
}
func runPathCommand(cmd *cobra.Command, args []string) {
pathType := args[0]
open, err := cmd.Flags().GetBool("open")
if err != nil {
WriteStderr("Error getting open flag: %v\n", err)
return
}
openExternal, err := cmd.Flags().GetBool("open-external")
if err != nil {
WriteStderr("Error getting open-external flag: %v\n", err)
return
}
path, err := wshclient.PathCommand(RpcClient, wshrpc.PathCommandData{
PathType: pathType,
Open: open,
OpenExternal: openExternal,
}, nil)
if err != nil {
WriteStderr("Error getting %s path: %v\n", pathType, err)
return
}
WriteStdout("%s\n", path)
}

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 (8)
cmd/wsh/cmd/wshcmd-wavepath.go (4)

36-43: Simplify argument validation by checking for len(args) != 1

Currently, the code separately handles the cases when no arguments or too many arguments are provided. You can simplify the argument validation by checking if the number of arguments is not equal to one, and provide a single error message.

Apply this diff to simplify the validation:

 if len(args) != 1 {
     OutputHelpMessage(cmd)
-    if len(args) == 0 {
-        return fmt.Errorf("no arguments. wsh wavepath requires a type argument (config, data, or log)")
-    }
-    if len(args) > 1 {
-        return fmt.Errorf("too many arguments. wsh wavepath requires exactly one argument")
-    }
+    return fmt.Errorf("wsh wavepath requires exactly one argument (config, data, or log)")
 }

46-49: Consider defining valid path types as a constant or map for scalability

To improve maintainability and scalability, especially if more path types might be added in the future, consider defining the valid path types as a slice or map and checking against it.

Here's how you might implement it:

var validPathTypes = map[string]struct{}{
    "config": {},
    "data":   {},
    "log":    {},
}

if _, ok := validPathTypes[pathType]; !ok {
    OutputHelpMessage(cmd)
    return fmt.Errorf("invalid path type %q. must be one of: config, data, log", pathType)
}

100-103: Use io.SeekStart constant instead of 0 for file seeking

For better readability and to avoid magic numbers, use the io.SeekStart constant when seeking from the start of the file.

Apply this diff:

-_, err = file.Seek(offset, 0)
+_, err = file.Seek(offset, io.SeekStart)

106-109: Handle potential partial reads when reading the file

The file.Read(buf) call might read fewer bytes than requested. To ensure you read as much as possible, consider using io.ReadAtLeast or io.ReadFull.

Apply this diff to handle partial reads:

-n, err := file.Read(buf)
+_, err := io.ReadFull(file, buf)
 if err != nil && err != io.EOF {
     return fmt.Errorf("reading file: %w", err)
 }
+// Adjust buffer size if fewer bytes were read
+if err == io.EOF {
+    buf = buf[:n]
+}
docs/docs/wsh-reference.mdx (4)

698-704: Enhance command syntax presentation for clarity

For better readability and consistency, add the shell prompt symbol and use syntax highlighting in the command usage example.

Apply this diff:

 ```bash
-wsh wavepath {config|data|log}
+$
+wsh wavepath {config|data|log}

---

`708-711`: **Clarify the exact number of lines shown with `--tail` flag**

The description uses `~100 lines`, which may imply an approximate number. Since the code displays exactly the last 100 lines, consider updating the description for accuracy.



Apply this diff:

```diff
 - `-t, --tail` - show the last ~100 lines of the log file (only valid for log path)
+- `-t, --tail` - show the last 100 lines of the log file (only valid for `log` path)

725-726: Use long-form flags in examples for clarity

In the example commands, consider using the long-form flags for better understanding, especially for users unfamiliar with the shorthand.

Apply this diff:

-wsh wavepath -o log
+wsh wavepath --open log

727-729: Consistently use long-form flags in examples

Continue using long-form flags for consistency and clarity in the examples.

Apply this diff:

-wsh wavepath -O config
+wsh wavepath --open-external config
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6c67ac6 and cb558fd.

📒 Files selected for processing (2)
  • cmd/wsh/cmd/wshcmd-wavepath.go (1 hunks)
  • docs/docs/wsh-reference.mdx (1 hunks)
🔇 Additional comments (1)
cmd/wsh/cmd/wshcmd-wavepath.go (1)

113-118: Handle case where no newline is found when skipping partial line

When skipping the partial line at the start, if no newline character is found, the entire buffer might be skipped. Ensure that this case is handled appropriately to avoid losing data.

Run the following script to verify how the code behaves when no newline is found:

Comment on lines +56 to +58
open, _ := cmd.Flags().GetBool("open")
openExternal, _ := cmd.Flags().GetBool("open-external")

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

Add validation to prevent conflicting --open and --open-external flags

Currently, if both --open and --open-external flags are set, the behavior may be undefined or undesirable. Consider adding validation to ensure these flags are not used together.

Apply this diff to add the validation:

 open, _ := cmd.Flags().GetBool("open")
 openExternal, _ := cmd.Flags().GetBool("open-external")

+if open && openExternal {
+    return fmt.Errorf("--open and --open-external cannot be used together")
+}

 path, err := wshclient.PathCommand(RpcClient, wshrpc.PathCommandData{
     PathType:     pathType,
     Open:         open,
     OpenExternal: openExternal,

Committable suggestion skipped: line range outside the PR's diff.

@sawka sawka changed the title Add wsh path command for getting Wave paths Add wsh wavepath command for getting Wave paths Dec 17, 2024
@sawka sawka merged commit 0a3dadb into main Dec 17, 2024
10 checks passed
@sawka sawka deleted the evan/path-command branch December 17, 2024 22:11
xxyy2024 pushed a commit to xxyy2024/waveterm_aipy that referenced this pull request Jun 24, 2025
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants