Skip to content

add helpful cli hints for ability discovery#3

Merged
dennisdornon merged 4 commits intomainfrom
feat/helpful-cli-hints
Mar 24, 2026
Merged

add helpful cli hints for ability discovery#3
dennisdornon merged 4 commits intomainfrom
feat/helpful-cli-hints

Conversation

@dennisdornon
Copy link
Copy Markdown
Contributor

@dennisdornon dennisdornon commented Mar 24, 2026

Guide new users from login through to running their first ability.

  • login now shows "Next: mainwpcontrol abilities list" after success
  • abilities list prints a copy-pasteable abilities run <name> hint under each row
  • command_not_found hook catches ability names typed as commands and suggests the right syntax, plus did-you-mean for typos
  • README rewritten for progressive disclosure with quick-start flow

Tested locally — login hint, abilities list hints, and command-not-found suggestions all work.

Summary by CodeRabbit

  • Documentation

    • Expanded README with Quick Start, “What Just Happened”, Common Use Cases, Basic Usage, Concepts, Global/Run flags, Advanced Usage, diagnostics, chat mode, jobs, and requirements.
  • New Features

    • Abilities list now shows usage hints for each ability.
    • Login now shows a next-step hint after success.
    • Unrecognized commands now offer helpful “Did you mean…?” suggestions.
  • Tests

    • Updated smoke test expectations for unknown-command behavior.

- abilities list shows copy-pasteable run commands under each ability
- command_not_found hook suggests `abilities run` for ability names
- fuzzy "did you mean?" for typos in command names
Restructure so users hit a working command before reading concepts.
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 24, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5d21d6aa-bde9-4515-bb6e-6e68eb703145

📥 Commits

Reviewing files that changed from the base of the PR and between 01b993f and 023306e.

📒 Files selected for processing (4)
  • README.md
  • src/__tests__/process/smoke.test.ts
  • src/commands/abilities/list.ts
  • src/hooks/command-not-found.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/hooks/command-not-found.ts
  • src/commands/abilities/list.ts

Walkthrough

Adds a custom oclif command_not_found hook with fuzzy suggestions, augments ability listing and login output with styled usage hints, updates tests to expect the new exit code, configures the hook in package.json, and expands and reorganizes README documentation.

Changes

Cohort / File(s) Summary
Documentation
README.md
Rewrote and reorganized README: new "Quick Start", "What Just Happened", "Common Use Cases", "Basic Usage", "Concepts", "Advanced Usage", tables for global/ability flags, env var and safety clarifications, sample config, and consolidated Requirements section.
CLI config
package.json
Added oclif hook registration: oclif.hooks.command_not_found./dist/hooks/command-not-found.js.
Abilities list UI
src/commands/abilities/list.ts
Changed formatted output to include ANSI styling and per-ability indented, dim usage hints (mainwpcontrol abilities run <shortName>); added safety fallbacks when reading table lines.
Login UX
src/commands/login.ts
Appends an informational post-login hint (Next: mainwpcontrol abilities list) after existing warnings.
Command-not-found hook
src/hooks/command-not-found.ts
New oclif hook that normalizes missing command ids (strips mainwp/), recognizes ability-like names to show a run suggestion, computes Levenshtein distances against visible command IDs (including aliases) to offer "Did you mean...?" suggestions using a dynamic threshold, and exits with ExitCode.INPUT_ERROR for errors.
Tests
src/__tests__/process/smoke.test.ts
Updated expectation for non-existent command handling: exit code changed from 2 to 1 while still asserting a "not found" message.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant CLI
    participant Hook as CommandNotFoundHook
    participant Config as CommandRegistry
    participant Output as ErrorOutput

    User->>CLI: run unknown command "some-id"
    CLI->>Hook: emit command_not_found(id)
    Hook->>Hook: normalize id (strip "mainwp/" prefix)
    alt id matches ability-like pattern (-v<digits>)
        Hook->>Output: error "run: mainwpcontrol abilities run <name>"
    else
        Hook->>Config: fetch visible command IDs and aliases
        Hook->>Hook: compute Levenshtein distances
        alt best match within threshold
            Hook->>Output: suggestion "Did you mean: <closest>?"
        else
            Hook->>Output: generic "command not found" + help hint
        end
    end
    Hook->>CLI: exit with INPUT_ERROR (non-zero)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main objective of the changeset: adding CLI hints (informational messages and suggestions) to help users discover and run abilities.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/helpful-cli-hints

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: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@README.md`:
- Around line 21-37: Update the README sample output to match the current
renderer: replace the boxed table with the plain header/separator table style
produced by the formatter (e.g., formatter.renderTable or equivalent) and move
each "mainwpcontrol abilities run ..." hint so it appears directly under its
corresponding ability row (as printed by the abilities list command handler,
e.g., listAbilities or the function in commands/abilities/list.ts) rather than
appended all together at the end.

In `@src/commands/abilities/list.ts`:
- Around line 107-108: The hint currently injects raw ability.name into the
terminal output (shortName used in lines.push), allowing control characters/ANSI
escapes/newlines from the Dashboard to be printed; sanitize the value before
using it by deriving shortName from a cleaned version of ability.name (e.g., run
the name through the same sanitizer used by formatTable or strip control
sequences with a regex like removing ANSI CSI sequences and trimming
newlines/extra whitespace), and then use that sanitized shortName in the
lines.push call so no raw control characters are emitted.

In `@src/hooks/command-not-found.ts`:
- Around line 63-65: The hook currently returns non-conforming exit codes (127
and 2) when a command is not found; update the two this.error calls that build
the command-not-found messages (the one using id, config.bin and displayCmd and
the fallback at the other occurrence) to return a documented CLI exit code
instead of 127/2—use one of the allowed codes (e.g., exit: 1) consistently for
command-not-found so scripts can rely on the published contract.
- Around line 46-51: The current filter for commandIDs lets aliases of hidden
commands through because it only checks cmd.id === cid; change the predicate so
it finds any command where either cmd.id === cid or cmd.aliases includes cid and
excludes the cid when that matching command has hidden === true. Update the
filter used when building commandIDs (the array built from config.commandIDs and
config.commands.flatMap(...)) to use something like finding a command via
config.commands.find(cmd => cmd.id === cid || cmd.aliases?.includes(cid)) and
then filter out when that command?.hidden is true.
- Line 32: The hook handler hook: Hook<'command_not_found'> currently
destructures only { id, config } and incorrectly calls this.error(); update the
parameter destructuring to include context (e.g., { id, config, context }) and
replace any this.error() / this.exit() calls with context.error(...) or
context.exit(...); locate and update all occurrences in the command_not_found
hook implementation (including the blocks around the initial declaration and the
branches noted at the other occurrences) so the hook exits using the provided
options.context API.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7e222ed1-a95b-4c19-9c2e-95403053f914

📥 Commits

Reviewing files that changed from the base of the PR and between 5dfd6dd and 01b993f.

📒 Files selected for processing (5)
  • README.md
  • package.json
  • src/commands/abilities/list.ts
  • src/commands/login.ts
  • src/hooks/command-not-found.ts

return dp[m]![n]!;
}

const hook: Hook<'command_not_found'> = async function ({ id, config }) {
Copy link
Copy Markdown

@coderabbitai coderabbitai bot Mar 24, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

cat -n src/hooks/command-not-found.ts

Repository: mainwp/mainwp-control

Length of output: 3120


🏁 Script executed:

# Search for oclif Hook type definitions to understand the API
rg -t ts "Hook.*command_not_found" -A 5 -B 5

Repository: mainwp/mainwp-control

Length of output: 703


🌐 Web query:

oclif command_not_found hook context API documentation

💡 Result:

The command_not_found hook in oclif is a lifecycle hook that runs when a command is not found before the default error message is displayed. It allows custom handling, such as suggesting similar commands (as done by the @oclif/plugin-not-found plugin) or other logic. To implement it, declare the hook in your CLI's package.json under oclif.hooks: "oclif": { "hooks": { "command_not_found": "./path/to/your/hook.js" } } The hook function receives an options parameter with a context property. Use options.context.error or options.context.exit to exit during the hook. All hooks share this standard structure, as shown in oclif docs examples for other hooks like init. Official documentation: https://oclif.github.io/docs/hooks/ Example from docs (adapted for command_not_found): import {Hook} from '@oclif/core' const hook: Hook.CommandNotFound = async function (options) { // Custom logic, e.g., log or suggest commands // Access options.argv for input args, options.config for CLI config console.log(Command not found: ${options.argv.join(' ')}) // Optionally exit: options.context.exit(1) } export default hook The exact TypeScript interface Hook.CommandNotFound is not explicitly detailed in public docs, but follows the pattern of other hooks with options: { argv?: string[], config: Config, context: HookContext }. The @oclif/plugin-not-found implements this hook to provide "did you mean" suggestions using Levenshtein distance. For full source, see @oclif/core types or plugin-not-found repo: https://github.com/oclif/plugin-not-found

Citations:


🏁 Script executed:

# Check README.md for CLI contract and exit codes
find . -name "README.md" -type f | head -5

Repository: mainwp/mainwp-control

Length of output: 138


🏁 Script executed:

# Look for oclif Hook type definition
rg -t ts "type Hook" -A 3 --max-count 5

Repository: mainwp/mainwp-control

Length of output: 47


🏁 Script executed:

# Check if there are other hooks in the codebase to see the pattern
find . -path "./src/hooks/*.ts" -type f

Repository: mainwp/mainwp-control

Length of output: 97


🌐 Web query:

oclif Hook typescript type definition command_not_found signature

💡 Result:

The TypeScript type definition for the oclif command_not_found hook is Hook.CommandNotFound from @oclif/core. To implement it: typescript import { Hook } from '@oclif/core'; const hook: Hook.CommandNotFound = async function (options) { // Handle command not found, e.g., suggest alternatives // Use options.context.error or options.context.exit to exit // options likely includes: argv (command args), config, context }; export default hook; Register in package.json: json { "oclif": { "hooks": { "command_not_found": "./path/to/hook.js" } } } This hook runs when a command is not found before displaying the error. Official docs confirm command_not_found as a lifecycle event [9]. TypeDoc-like interface lists command_not_found: object [2]. Example usage seen in issues and plugin-not-found which implements it [14].

Citations:


🏁 Script executed:

cat README.md | head -100

Repository: mainwp/mainwp-control

Length of output: 3035


🏁 Script executed:

# Check package.json for `@oclif/core` version and dependencies
cat package.json | grep -A 5 "@oclif"

Repository: mainwp/mainwp-control

Length of output: 664


🏁 Script executed:

# Look for type definitions - check if node_modules has `@oclif/core` types
find node_modules/@oclif/core -name "*.d.ts" -path "*hook*" 2>/dev/null | head -10

Repository: mainwp/mainwp-control

Length of output: 47


🏁 Script executed:

# Search for Hook interface in the project or dependencies
rg "interface.*Hook|type.*Hook" --max-count 10

Repository: mainwp/mainwp-control

Length of output: 47


🏁 Script executed:

# Get the actual Hook type definition from `@oclif/core`
cat node_modules/@oclif/core/lib/types/hooks.d.ts 2>/dev/null || echo "File not found, searching for hook types..."

Repository: mainwp/mainwp-control

Length of output: 108


🏁 Script executed:

# Search for Hook type exports in oclif/core
rg "command_not_found|Hook" node_modules/@oclif/core/lib --max-count 20 2>/dev/null | head -50

Repository: mainwp/mainwp-control

Length of output: 47


🏁 Script executed:

# Check if there are any examples or actual hook implementations in oclif
find node_modules/@oclif -name "*not-found*" -o -name "*hook*" | grep -E "\.(ts|js)$" | head -10

Repository: mainwp/mainwp-control

Length of output: 119


🏁 Script executed:

# Look for `@oclif/plugin-not-found` to see how they implement it
cat node_modules/@oclif/plugin-not-found/lib/hook.js 2>/dev/null || cat node_modules/@oclif/plugin-not-found/lib/hook.ts 2>/dev/null || echo "Checking directory structure..."

Repository: mainwp/mainwp-control

Length of output: 96


🏁 Script executed:

# Check directory structure of `@oclif` packages
ls -la node_modules/@oclif/plugin-not-found/lib/ 2>/dev/null || ls -la node_modules/@oclif/plugin-not-found/ 2>/dev/null || echo "Plugin not found"

Repository: mainwp/mainwp-control

Length of output: 81


🏁 Script executed:

# Check README.md for any mention of exit codes or error handling
grep -i "exit" README.md

Repository: mainwp/mainwp-control

Length of output: 859


🏁 Script executed:

# Look for any documentation about what `this` context would be in the hook
grep -rn "this\.error" src/ --include="*.ts" | head -20

Repository: mainwp/mainwp-control

Length of output: 300


🏁 Script executed:

# Check if there are type stubs or d.ts files in src
find src -name "*.d.ts" -type f

Repository: mainwp/mainwp-control

Length of output: 47


🏁 Script executed:

# Look at the actual Hook import and check the file
grep -A 20 "import.*Hook" src/hooks/command-not-found.ts

Repository: mainwp/mainwp-control

Length of output: 702


🌐 Web query:

@oclif/core 4.0 hook context error method api reference

💡 Result:

In @oclif/core 4.0 (and later versions up to 4.9.0), hooks receive an options parameter that includes a context object with error and exit methods for proper CLI exit during hook execution. Throwing plain Errors is caught and does not exit the CLI, to prevent one hook from breaking the entire process (e.g., in multi-plugin scenarios). Use options.context.error(msg) or options.context.exit(code) instead. Example from official docs: typescript import {Hook} from '@oclif/core' const hook: Hook.Init = async function (options) { // ... if (needToExit) { options.context.error('Error message') // or options.context.exit(1) } } The Hook type is defined in @oclif/core's interfaces (src/interfaces/hooks.ts), exported publicly. Hook functions are typed as Hook.EventName = async (options: Hook.Options.EventName) => void | Promise, where options.context provides CLI context similar to Command methods like this.error and this.exit. No full API reference page for Hook.Context found in docs, but usage is documented in Hooks guide. Source code confirms availability in v4 via TypeScript definitions and exports.

Citations:


🏁 Script executed:

# Check if there are tests for the hook
find . -name "*command-not-found*test*" -o -name "*hook*.test.ts" 2>/dev/null | head -10

Repository: mainwp/mainwp-control

Length of output: 47


🏁 Script executed:

# Look at chat.ts to see how this.error is used in commands (should work there)
sed -n '180,210p' src/commands/chat.ts

Repository: mainwp/mainwp-control

Length of output: 1099


🏁 Script executed:

# Check the base Command class to understand what `this` is in a hook vs command
grep -n "class.*Hook\|class.*Command" src/**/*.ts 2>/dev/null | head -10

Repository: mainwp/mainwp-control

Length of output: 379


🏁 Script executed:

# Verify the exact Hook type signature from `@oclif/core` package
cat node_modules/@oclif/core/package.json 2>/dev/null | grep -A 2 '"main"'

Repository: mainwp/mainwp-control

Length of output: 47


🌐 Web query:

oclif hook function this context available async function hook vs command

💡 Result:

In oclif, hooks and commands have different contexts available in their functions. Hooks are standalone async functions that receive an options parameter specific to the hook event. For example, the init hook receives options with an id property (e.g., options.id for the command ID). They do not have a this context like commands. To exit or error from a hook, use options.context.error or options.context.exit. Throwing an Error in a hook does not exit the CLI. Commands extend the Command class and have this bound in their async run method, providing access to this.config, this.log, this.error, this.exit, etc. Hooks: async function(options) { ... } — no this, use options.context for limited actions. Commands: class extends Command { async run { ... } } — full this Command instance available. Hooks run in parallel and are for lifecycle or custom events; commands are the main executable units with full CLI context.

Citations:


🏁 Script executed:

# Look for actual implementation patterns in oclif examples or other hooks
rg "Hook.*command_not_found|options\.context" --max-count 10

Repository: mainwp/mainwp-control

Length of output: 169


🏁 Script executed:

# Check if there are any TypeScript interfaces defined locally that extend Hook
rg "interface.*Hook|Hook\<" src/ -A 3 --max-count 10

Repository: mainwp/mainwp-control

Length of output: 173


🌐 Web query:

oclif command_not_found hook options parameter destructuring context signature example

💡 Result:

The command_not_found hook in oclif is a lifecycle hook that runs when a command is not found before displaying the error. It receives an options parameter containing context and likely details about the attempted command (such as argv or id). Hook signature (TypeScript): import { Hook } from '@oclif/core' const hook: Hook.CommandNotFound = async (options) => { // options.context provides error and exit methods for handling // Other properties like attempted command ID or argv may be available } export default hook Example with parameter destructuring: const hook: Hook.CommandNotFound = async ({ context, id }) => { // 'id' is the attempted command ID (inferred from init hook pattern) this.log(Command ${id} not found) // Use context methods if needed if (context) { context.exit(1) // Exit during hook } } export default hook Register in package.json: "oclif": { "hooks": { "command_not_found": "./src/hooks/command_not_found.js" } } This hook is used by @oclif/plugin-not-found for "did you mean" suggestions. Official docs confirm options.context.error or options.context.exit for exiting. Exact options interface follows patterns like init hook's {id, argv, config, context}.

Citations:


Use context.error() instead of this.error() in the hook handler.

Oclif's command_not_found hook receives an options parameter (not a Command instance). To exit the hook, use options.context.error() or options.context.exit() — not this.error(). The hook currently destructures only { id, config }, missing the context parameter needed to properly terminate execution.

🐛 Proposed fix
-const hook: Hook<'command_not_found'> = async function ({ id, config }) {
+const hook: Hook<'command_not_found'> = async function ({ id, config, context }) {
   // Strip common prefix mistakes (e.g., "mainwp/list-updates-v1")
   const name = id.replace(/^mainwp\//, '');
 
   // Ability name pattern: suggest abilities run
   if (/-v\d+$/.test(name)) {
     const suggestion = `${config.bin} abilities run ${name}`;
-    this.error(
+    context.error(
       `"${id}" is not a command. It looks like an ability name.\n\nRun it with:\n  ${suggestion}`,
       { exit: 1 },
     );
   }
 
   // Find closest matching command using Levenshtein distance
   ...
-      this.error(
+      context.error(
         `"${id.replace(/:/g, ' ')}" is not a ${config.bin} command. Did you mean "${displayCmd}"?\n\nRun ${config.bin} help for a list of available commands.`,
         { exit: 127 },
       );
     }
   }
 
-  this.error(
+  context.error(
     `command "${id.replace(/:/g, ' ')}" not found. Run ${config.bin} help for a list of available commands.`,
     { exit: 2 },
   );

Also applies to: 39-42, 63-65, 71-73

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/hooks/command-not-found.ts` at line 32, The hook handler hook:
Hook<'command_not_found'> currently destructures only { id, config } and
incorrectly calls this.error(); update the parameter destructuring to include
context (e.g., { id, config, context }) and replace any this.error() /
this.exit() calls with context.error(...) or context.exit(...); locate and
update all occurrences in the command_not_found hook implementation (including
the blocks around the initial declaration and the branches noted at the other
occurrences) so the hook exits using the provided options.context API.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Not changing this. Oclif binds this: Hook.Context in hook callbacks, so this.error() is already calling the context API. You can verify in node_modules/@oclif/core/lib/interfaces/hooks.d.ts where the hook type is defined with this: Hook.Context. Switching to options.context.error() would be equivalent but less idiomatic for oclif hooks.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify the Hook type definition in `@oclif/core`
find . -path "*/node_modules/@oclif/core/lib/interfaces/hooks.d.ts" -exec cat {} \; 2>/dev/null || \
find . -path "*/node_modules/@oclif/core*" -name "hooks.d.ts" -exec cat {} \; 2>/dev/null || \
echo "File not found in node_modules, searching elsewhere..."

# Also search for Hook type with `this` binding
rg "this.*Hook\.Context\|Hook\.Context.*this\|hook.*this" --type=ts --max-count=10 2>/dev/null | head -30

Length of output: 0


🌐 Web query:

oclif Hook type definition "this: Hook.Context" hooks.d.ts `@oclif/core`

💡 Result:

In @oclif/core, the hook function type is declared in lib/interfaces/hooks.d.ts as a function with an explicit this parameter:

export type Hook<T extends keyof P, P extends Hooks = Hooks> =
  (this: Hook.Context,
   options: P[T]['options'] & { config: Config; context: Context }
  ) => Promise<P[T]['return']>;

…and Hook.Context is an interface that includes config plus logging/error helpers (e.g. this.config, this.log, this.error, etc.). (app.unpkg.com)

Practical implications:

  • this: Hook.Context means oclif will bind this when it invokes the hook, and TypeScript will type this accordingly. (app.unpkg.com)
  • To use this in your implementation, don’t use an arrow function (arrows don’t have their own this):
import type {Hook} from '@oclif/core'

const hook: Hook<'init'> = async function (options) {
  this.log('hello')        // typed as Hook.Context
  options.config           // Config
  options.context.log('x') // Context (separate from Hook.Context)
}
export default hook

The oclif hooks docs show hooks are exported functions keyed by event name (e.g. init, prerun, postrun) and receive an options object from oclif. (oclif.io)

Citations:


@dennisdornon, you're absolutely right — I apologize for the incorrect review comment.

The Hook type in @oclif/core is defined as (this: Hook.Context, options: ...) => Promise<...>, meaning oclif explicitly binds this to a Hook.Context instance when invoking hook callbacks. Since the hook is implemented as a regular async function (not an arrow function), this is correctly bound and this.error() is both valid and idiomatic.


✏️ Learnings added
Learnt from: dennisdornon
Repo: mainwp/mainwp-control PR: 3
File: src/hooks/command-not-found.ts:33-33
Timestamp: 2026-03-24T19:03:59.327Z
Learning: In `oclif/core`, hook callbacks are typed with an explicit `this: Hook.Context` parameter (see `lib/interfaces/hooks.d.ts`). Oclif binds `this` to a `Hook.Context` instance at invocation, so `this.error()`, `this.log()`, etc. are the correct and idiomatic way to call context methods inside hooks declared as regular `async function` expressions. Arrow functions would not work for this pattern. Switching to `options.context.error()` would be functionally equivalent but is non-idiomatic. File: `src/hooks/command-not-found.ts` in mainwp/mainwp-control.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

- use ExitCode.INPUT_ERROR consistently in command-not-found hook
- sanitize ability.name before building hint line
- fix hidden command alias filter to check aliases not just id
- update readme sample to match actual formatTable output
@dennisdornon dennisdornon merged commit e5d9b8e into main Mar 24, 2026
9 checks passed
@dennisdornon dennisdornon deleted the feat/helpful-cli-hints branch March 24, 2026 19:06
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.

1 participant