Skip to content

feat(dawgrun): CLI mode#84

Merged
seanjSO merged 4 commits into
mainfrom
seanj/dawgrun-cli
May 21, 2026
Merged

feat(dawgrun): CLI mode#84
seanjSO merged 4 commits into
mainfrom
seanj/dawgrun-cli

Conversation

@seanjSO
Copy link
Copy Markdown
Contributor

@seanjSO seanjSO commented May 19, 2026

Description

Adds a CLI mode to dawgrun, enabling users (and agents) to run queries, copy datasets, etc.
Note that this does not have any changes in the production path.

Type of Change

  • Chore (a change that does not modify the application functionality)
  • Bug fix (a change that fixes an issue)
  • New feature / enhancement (a change that adds new functionality)
  • Refactor (no behaviour change)
  • Test coverage
  • Build / CI / tooling
  • Documentation

Testing

  • Unit tests added / updated
  • Integration tests added / updated
  • Full test suite run (make test_all with CONNECTION_STRING set)

Screenshots (if appropriate):

Driver Impact

  • PostgreSQL driver (drivers/pg)
  • Neo4j driver (drivers/neo4j)

Checklist

  • Code is formatted
  • All existing tests pass
  • go.mod / go.sum are up to date if dependencies changed

Summary by CodeRabbit

  • New Features

    • One-shot CLI mode alongside the interactive REPL; CLI reads config when present.
    • Save/load named backend connections with new save-connections / load-connections commands.
    • Config file support with sample format and default path.
    • Query output: JSON or table rendering with improved formatting.
    • Optional styled (ANSI) output can be disabled for non-terminal output.
  • Documentation

    • README and RFC updated with CLI/REPL, commands, config, and styling notes.
  • Tests

    • New unit tests covering CLI/REPL command execution, config persistence, connections, and styling.

Review Change Stack

@seanjSO seanjSO self-assigned this May 19, 2026
@seanjSO seanjSO added enhancement New feature or request go Pull requests that update go code labels May 19, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 19, 2026

Walkthrough

Adds one-shot CLI mode to dawgrun, implements JSON-backed connection persistence and a concurrency-safe Scope, extracts text rendering helpers, controls styled output, and updates commands and main routing to use the new abstractions.

Changes

CLI mode and config infrastructure for dawgrun

Layer / File(s) Summary
Config persistence types and connection state tracking
tools/dawgrun/pkg/types/config.go, tools/dawgrun/pkg/commands/commandscope.go
Adds Config/ConnectionConfig JSON persistence and a thread-safe Scope to track open connections, configs, and kind maps with close semantics and RunMode support.
Text rendering utilities and Cypher output
tools/dawgrun/pkg/texttools/style.go, tools/dawgrun/pkg/texttools/cypher.go
Introduces IndentLines, HighlightText, and CypherOutputJSON/CypherOutputTable to centralize indentation, highlighting, and terminal-aware query result rendering.
Command context enhancement with styled output and config support
tools/dawgrun/pkg/commands/commandcontext.go, tools/dawgrun/pkg/commands/commandcontext_test.go
CommandContext gains appConfigBaseDir, CommandOutput gains styled-output control, and new EnsureConnection/OpenConnection helpers manage lazy/explicit connection opening; output methods delegate to texttools.
Load and save connection configuration commands
tools/dawgrun/pkg/commands/config.go, tools/dawgrun/pkg/commands/config_test.go, tools/dawgrun/pkg/commands/registry.go
Adds load-connections and save-connections commands with resolveConfigPath, config round-trip and legacy-format tests, and registry entries for the new commands.
Existing command refactoring for new abstractions
tools/dawgrun/pkg/commands/db.go, tools/dawgrun/pkg/commands/cypher.go, tools/dawgrun/pkg/commands/opengraph.go, tools/dawgrun/pkg/commands/help.go, tools/dawgrun/pkg/commands/runtime.go, tools/dawgrun/pkg/commands/helpers.go
listConnectionsCmd now shows open vs configured-unopened connections; open delegates to openConnection/openDAWGSDatabase; commands use EnsureConnection; help adds renderHelp and "all"; quit guards CLI mode; old helpers removed in favor of texttools.
Main entry point: CLI vs REPL routing and config initialization
tools/dawgrun/cmd/dawgrun/main.go, tools/dawgrun/cmd/dawgrun/main_test.go
main() resolves app config base dir, loads default config connections, routes to cliMain or replMain, and provides runCommandWithOptions to build CommandContext with styled-output control; tests cover command execution, styled-output disabling, and default config loading.
Documentation and configuration reference updates
tools/dawgrun/.gitignore, tools/dawgrun/README.md, tools/dawgrun/docs/RFC.md
Path-specific .gitignore for /dawgrun; README documents REPL/CLI modes, sample config.json, CLI-mode styling behavior; RFC updates to reflect CLI constraints and new commands.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐰 I hop from REPL into the CLI light,
Configs saved softly through the quiet night,
Styled bytes dim when the terminal's away,
Connections sleep until you call them to play.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 3.08% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(dawgrun): CLI mode' directly and clearly summarizes the main change—adding CLI mode functionality to the dawgrun tool.
Description check ✅ Passed The PR description covers the main motivation (adding CLI mode), includes relevant type-of-change checkboxes (Chore and Build/CI/tooling), and indicates testing (Unit tests added). However, code formatting and test-pass checkboxes are unchecked despite these being important for merge criteria.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch seanj/dawgrun-cli

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
Copy Markdown

@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: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tools/dawgrun/pkg/commands/config.go`:
- Around line 36-45: When loading connections in the loop that calls
openConnection for each entry in config.Connections, avoid leaving a partially
applied state by tracking successfully opened connections (e.g., opened :=
[]string{}) and on any openConnection error iterate over opened to roll them
back: call an existing teardown API (or implement one) such as
closeConnection(ctx, name) or removeConnection(name) to close resources and
remove them from the in-memory registry, then return the original error (or an
aggregated error if you prefer); update the loop around openConnection and
ensure opened is appended only after a successful open and cleaned up on error.

In `@tools/dawgrun/pkg/commands/db.go`:
- Around line 186-187: The error message currently includes the raw connStr
which may leak credentials; update the fmt.Errorf call in the DB open path (the
return using driverName and connStr) to omit or redact connStr and instead
include only safe identifiers like driverName or a connection identifier.
Replace fmt.Errorf("error opening %s database connection '%s': %w", driverName,
connStr, err) with a message that does not embed connStr (e.g. fmt.Errorf("error
opening %s database connection: %w", driverName, err)) or use a
sanitized/redacted version of connStr if you must show it.

In `@tools/dawgrun/README.md`:
- Around line 54-64: Replace the indented code examples in the README CLI
section with fenced code blocks using triple backticks and a language tag (use
"text") so markdownlint MD046 is satisfied; for each example that currently
shows lines like "dawgrun >", "dawgrun parse \"match (n) return n limit 1\"",
"dawgrun > list-connections", "dawgrun > save-connections", "dawgrun >
load-connections", and the two examples with paths, wrap the example lines with
```text and ``` (opening before the example and closing after) rather than using
indentation, and apply the same fenced-block change to the other occurrences in
the same README section.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7c3893c9-4ed3-44c8-8dee-f346eb88638a

📥 Commits

Reviewing files that changed from the base of the PR and between 0ee0b16 and 3bbd653.

📒 Files selected for processing (20)
  • tools/dawgrun/.gitignore
  • tools/dawgrun/README.md
  • tools/dawgrun/cmd/dawgrun/main.go
  • tools/dawgrun/cmd/dawgrun/main_test.go
  • tools/dawgrun/docs/RFC.md
  • tools/dawgrun/pkg/commands/commandcontext.go
  • tools/dawgrun/pkg/commands/commandcontext_test.go
  • tools/dawgrun/pkg/commands/commandscope.go
  • tools/dawgrun/pkg/commands/config.go
  • tools/dawgrun/pkg/commands/config_test.go
  • tools/dawgrun/pkg/commands/cypher.go
  • tools/dawgrun/pkg/commands/db.go
  • tools/dawgrun/pkg/commands/help.go
  • tools/dawgrun/pkg/commands/helpers.go
  • tools/dawgrun/pkg/commands/opengraph.go
  • tools/dawgrun/pkg/commands/registry.go
  • tools/dawgrun/pkg/commands/runtime.go
  • tools/dawgrun/pkg/texttools/cypher.go
  • tools/dawgrun/pkg/texttools/style.go
  • tools/dawgrun/pkg/types/config.go
💤 Files with no reviewable changes (1)
  • tools/dawgrun/pkg/commands/helpers.go

Comment thread tools/dawgrun/pkg/commands/config.go
Comment thread tools/dawgrun/pkg/commands/db.go Outdated
Comment thread tools/dawgrun/README.md
Comment on lines +54 to +64
Run without arguments to start the REPL:

dawgrun >

Pass a command and its arguments to execute that command once and exit:

dawgrun parse "match (n) return n limit 1"

CLI mode reads `$XDG_CONFIG_HOME/dawgrun/config.json` (or the platform
equivalent) if it exists, so commands can refer to configured
connection names without an interactive `open` first.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use fenced code blocks to satisfy markdownlint MD046.

These newly added command examples are indented code blocks, but markdownlint expects fenced blocks in this repo style (warnings at Lines 56, 60, 105, 112, 116, 120).

Suggested doc fix
-Run without arguments to start the REPL:
-
-    dawgrun >
+Run without arguments to start the REPL:
+```text
+dawgrun >
+```

-Pass a command and its arguments to execute that command once and exit:
-
-    dawgrun parse "match (n) return n limit 1"
+Pass a command and its arguments to execute that command once and exit:
+```text
+dawgrun parse "match (n) return n limit 1"
+```

-To list open and configured connection names directly:
-
-    dawgrun > list-connections
+To list open and configured connection names directly:
+```text
+dawgrun > list-connections
+```

-Save the currently open connections to the default config file:
-
-    dawgrun > save-connections
+Save the currently open connections to the default config file:
+```text
+dawgrun > save-connections
+```

-Load and open connections from the default config file:
-
-    dawgrun > load-connections
+Load and open connections from the default config file:
+```text
+dawgrun > load-connections
+```

-Both commands accept an optional config path:
-
-    dawgrun > save-connections ./dawgrun.local.json
-    dawgrun > load-connections ./dawgrun.local.json
+Both commands accept an optional config path:
+```text
+dawgrun > save-connections ./dawgrun.local.json
+dawgrun > load-connections ./dawgrun.local.json
+```

Also applies to: 103-121

🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 56-56: Code block style
Expected: fenced; Actual: indented

(MD046, code-block-style)


[warning] 60-60: Code block style
Expected: fenced; Actual: indented

(MD046, code-block-style)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tools/dawgrun/README.md` around lines 54 - 64, Replace the indented code
examples in the README CLI section with fenced code blocks using triple
backticks and a language tag (use "text") so markdownlint MD046 is satisfied;
for each example that currently shows lines like "dawgrun >", "dawgrun parse
\"match (n) return n limit 1\"", "dawgrun > list-connections", "dawgrun >
save-connections", "dawgrun > load-connections", and the two examples with
paths, wrap the example lines with ```text and ``` (opening before the example
and closing after) rather than using indentation, and apply the same
fenced-block change to the other occurrences in the same README section.

Copy link
Copy Markdown
Contributor

@kpom-specter kpom-specter left a comment

Choose a reason for hiding this comment

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

Love the direction! This sets us up for more/different way of interacting with the data

Copy link
Copy Markdown

@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.

Caution

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

⚠️ Outside diff range comments (2)
tools/dawgrun/pkg/commands/commandscope.go (1)

85-92: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Invalidate the cached kind map when replacing a connection.

AddConnection updates the handle/config but keeps any existing connKindMaps[name]. Rebinding the same logical name can then reuse stale kind metadata from the previous backend.

Suggested fix
 func (s *Scope) AddConnection(name string, querier graph.Database, config types.ConnectionConfig) {
 	s.mu.Lock()
 	defer s.mu.Unlock()
 
 	s.connections[name] = querier
 	s.connectionConfigs[name] = config
+	delete(s.connKindMaps, name)
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tools/dawgrun/pkg/commands/commandscope.go` around lines 85 - 92,
AddConnection currently replaces s.connections[name] and
s.connectionConfigs[name] but leaves stale metadata in s.connKindMaps[name];
update AddConnection (on type Scope) to invalidate the cached kind map for the
given name when rebinding a connection by removing or clearing
s.connKindMaps[name] (e.g., delete from map or set to nil) while holding s.mu,
so the next use will rebuild fresh kind metadata.
tools/dawgrun/pkg/commands/config.go (1)

39-58: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Preserve configured entries even when load-connections cannot open them.

Right now only successful opens are recorded in scope. If one connection fails to open, that entry disappears from session state, and a later save-connections will rewrite the config without it. Seed the loaded configs into scope before the open loop so failed entries remain visible as configured-but-unopened.

Suggested fix
 			if len(config.Connections) == 0 {
 				fmt.Fprintf(ctx.output, "No connections found in %s\n", configPath)
 				return nil
 			}
 
+			ctx.scope.SetConnectionConfigs(config.Connections)
+
 			var connErrs error
 			openedConns := 0
 			for _, connName := range slices.Sorted(maps.Keys(config.Connections)) {
 				connConfig := config.Connections[connName]
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tools/dawgrun/pkg/commands/config.go` around lines 39 - 58, Seed the session
scope with the configured connections before attempting to open them so failed
opens stay recorded: iterate the keys of config.Connections and add each config
entry into the runtime scope (the same map/structure used by save-connections)
prior to the loop that calls openConnection; then keep the existing open loop
(which uses openConnection, connErrs, openedConns, configPath) to attempt to
open each connection and only update openedConns/logging on success. Ensure the
symbol you write to is the same scope/state used by save-connections so a later
save will include failed-but-configured entries.
🧹 Nitpick comments (1)
tools/dawgrun/pkg/commands/help.go (1)

59-66: ⚡ Quick win

Sort help all output for deterministic command ordering.

Line 59 iterates cmdRegistry directly, so help all output order is nondeterministic across runs.

♻️ Proposed fix
-				for name, cmd := range cmdRegistry {
+				for _, name := range slices.Sorted(maps.Keys(cmdRegistry)) {
+					cmd := cmdRegistry[name]
 					// skip commands that are disabled for this run mode
 					if slices.Contains(cmd.DisallowRunModes, ctx.scope.GetRunMode()) {
 						continue
 					}
 
 					fmt.Fprintf(ctx.output, "%s", renderHelp(name, cmd))
 				}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tools/dawgrun/pkg/commands/help.go` around lines 59 - 66, The help output
iterates cmdRegistry in map order causing nondeterministic listing; to fix,
collect the map keys (command names) into a slice, sort them (e.g.,
sort.Strings), then iterate the sorted names and for each lookup cmd :=
cmdRegistry[name] apply the same DisallowRunModes check (using
cmd.DisallowRunModes and ctx.scope.GetRunMode()) and call
fmt.Fprintf(ctx.output, "%s", renderHelp(name, cmd)); this preserves existing
filtering (renderHelp, ctx.output) but ensures deterministic ordering.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@tools/dawgrun/pkg/commands/commandscope.go`:
- Around line 85-92: AddConnection currently replaces s.connections[name] and
s.connectionConfigs[name] but leaves stale metadata in s.connKindMaps[name];
update AddConnection (on type Scope) to invalidate the cached kind map for the
given name when rebinding a connection by removing or clearing
s.connKindMaps[name] (e.g., delete from map or set to nil) while holding s.mu,
so the next use will rebuild fresh kind metadata.

In `@tools/dawgrun/pkg/commands/config.go`:
- Around line 39-58: Seed the session scope with the configured connections
before attempting to open them so failed opens stay recorded: iterate the keys
of config.Connections and add each config entry into the runtime scope (the same
map/structure used by save-connections) prior to the loop that calls
openConnection; then keep the existing open loop (which uses openConnection,
connErrs, openedConns, configPath) to attempt to open each connection and only
update openedConns/logging on success. Ensure the symbol you write to is the
same scope/state used by save-connections so a later save will include
failed-but-configured entries.

---

Nitpick comments:
In `@tools/dawgrun/pkg/commands/help.go`:
- Around line 59-66: The help output iterates cmdRegistry in map order causing
nondeterministic listing; to fix, collect the map keys (command names) into a
slice, sort them (e.g., sort.Strings), then iterate the sorted names and for
each lookup cmd := cmdRegistry[name] apply the same DisallowRunModes check
(using cmd.DisallowRunModes and ctx.scope.GetRunMode()) and call
fmt.Fprintf(ctx.output, "%s", renderHelp(name, cmd)); this preserves existing
filtering (renderHelp, ctx.output) but ensures deterministic ordering.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6d30fffa-b478-43a6-9260-480e7ef9c0b4

📥 Commits

Reviewing files that changed from the base of the PR and between 3bbd653 and c4c5447.

📒 Files selected for processing (11)
  • tools/dawgrun/README.md
  • tools/dawgrun/cmd/dawgrun/main.go
  • tools/dawgrun/cmd/dawgrun/main_test.go
  • tools/dawgrun/pkg/commands/commandcontext.go
  • tools/dawgrun/pkg/commands/commandcontext_test.go
  • tools/dawgrun/pkg/commands/commandscope.go
  • tools/dawgrun/pkg/commands/config.go
  • tools/dawgrun/pkg/commands/config_test.go
  • tools/dawgrun/pkg/commands/db.go
  • tools/dawgrun/pkg/commands/help.go
  • tools/dawgrun/pkg/commands/runtime.go
✅ Files skipped from review due to trivial changes (1)
  • tools/dawgrun/README.md

@seanjSO seanjSO merged commit 9131d97 into main May 21, 2026
9 checks passed
@seanjSO seanjSO deleted the seanj/dawgrun-cli branch May 21, 2026 15:33
@kpom-specter kpom-specter mentioned this pull request May 21, 2026
15 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request go Pull requests that update go code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants