Skip to content

Conversation

@noameron
Copy link
Contributor

@noameron noameron commented Nov 6, 2025

Add Zsh Shell Completions

Adds tab completion support for the OpenSpec CLI with Zsh (including Oh My Zsh).

New Command

openspec completion install # Auto-installs Zsh completions
openspec completion uninstall # Removes completions
openspec completion generate # Outputs completion script

Key Files

Core Implementation

  • src/core/completions/command-registry.ts - Centralized registry of all CLI commands and flags with COMMON_FLAGS constant for reusable flag definitions
  • src/core/completions/completion-provider.ts - Discovers change/spec IDs from projects with 2s caching
  • src/core/completions/factory.ts - Factory pattern with SUPPORTED_SHELLS constant for shell support

Zsh-Specific

  • src/core/completions/generators/zsh-generator.ts - Generates Zsh completion scripts using _arguments and _describe
  • src/core/completions/installers/zsh-installer.ts - Handles installation to Oh My Zsh (/.oh-my-zsh/custom/completions/) or standard Zsh (/.zsh/completions/)

Command Interface

  • src/commands/completion.ts - CLI command implementation with shared resolveShellOrExit() logic

Features

  • Tab complete commands, flags, change IDs, and spec IDs
  • Auto-detects Oh My Zsh vs standard Zsh
  • Only activates in OpenSpec projects
  • Plugin architecture for future shells (bash, fish, PowerShell)

Summary by CodeRabbit

  • New Features

    • Adds a top-level "completion" CLI with generate/install/uninstall for Zsh; dynamic, project-aware suggestions for changes/specs (2s cache); auto shell detection; machine-readable mode; Oh My Zsh & standard Zsh install/uninstall flows.
  • Documentation

    • Adds detailed design, proposal, and spec covering architecture, UX, install/uninstall behavior, error messages, caching, testing, and roadmap for other shells.
  • Tests

    • Extensive tests for generation, installer flows, detection, caching, and edge cases.
  • Chores

    • Postinstall auto-install wiring with opt-out and a test harness.

✏️ Tip: You can customize this high-level summary in your review settings.

@noameron noameron requested a review from TabishB as a code owner November 6, 2025 18:12
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 6, 2025

Walkthrough

Adds a Zsh-first, plugin-based shell completion subsystem: new completion CLI (generate/install/uninstall), generator/installer factory, COMMAND_REGISTRY, dynamic CompletionProvider with 2s TTL, shell detection, postinstall automation, Zsh generator/installer implementations, design/spec docs, and comprehensive tests.

Changes

Cohort / File(s) Summary
Design & Specs
openspec/changes/archive/2025-11-06-add-shell-completions/design.md, .../proposal.md, .../specs/cli-completion/spec.md, openspec/specs/cli-completion/spec.md
New design, proposal, and spec documents describing architecture, Zsh-first behavior, interfaces, dynamic provider caching, install/uninstall flows, error handling, testing plan, and roadmap.
Shell Detection
src/utils/shell-detection.ts
Adds SupportedShell type and detectShell() to infer shell from environment (zsh, bash, fish, powershell).
Core Types & Registry
src/core/completions/types.ts, src/core/completions/command-registry.ts
Adds typed interfaces (FlagDefinition, CommandDefinition, CompletionGenerator) and a strongly-typed COMMAND_REGISTRY enumerating commands, flags, subcommands, and positional types.
Dynamic Provider
src/core/completions/completion-provider.ts
New CompletionProvider with per-entity caches and 2s TTL; methods: getChangeIds(), getSpecIds(), getAllIds(), clearCache(), getCacheStats().
Zsh Generator
src/core/completions/generators/zsh-generator.ts
New ZshGenerator implementing CompletionGenerator; emits Zsh completion scripts using _arguments, _describe, per-command functions, and dynamic ID helpers.
Zsh Installer
src/core/completions/installers/zsh-installer.ts
New ZshInstaller and InstallationResult; detects Oh My Zsh, writes/backups completion file, marker-based .zshrc auto-config, uninstall/cleanup, and status/info methods.
Factory & Installer Interface
src/core/completions/factory.ts
New CompletionFactory with createGenerator/createInstaller, isSupported, getSupportedShells; adds CompletionInstaller interface and re-exports InstallationResult.
CLI Command Integration
src/cli/index.ts, src/commands/completion.ts
Adds top-level completion command with generate, install, uninstall subcommands and CompletionCommand orchestration (resolve shell, generate, install/uninstall, machine-readable __complete).
Postinstall Automation
package.json, scripts/postinstall.js, scripts/test-postinstall.sh
Adds postinstall wiring in package.json, scripts/postinstall.js to auto-install completions (skippable via CI or env), and scripts/test-postinstall.sh test harness.
Item discovery helper
src/utils/item-discovery.ts
Adds getArchivedChangeIds(root?) to list archived change IDs from openspec/changes/archive.
Tests
test/utils/shell-detection.test.ts, test/core/completions/*.test.ts, test/commands/completion.test.ts
Extensive tests covering shell detection, CompletionProvider caching, ZshGenerator output, ZshInstaller filesystem/.zshrc behavior, CLI behaviors, and postinstall scenarios.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant User as CLI User
    participant Cmd as CompletionCommand
    participant Detect as detectShell()
    participant Factory as CompletionFactory
    participant Gen as ZshGenerator
    participant Registry as COMMAND_REGISTRY
    participant Provider as CompletionProvider
    participant Installer as ZshInstaller

    Note over User,Cmd: User runs "openspec completion install [shell?]"
    User->>Cmd: completion install [shell?]
    Cmd->>Detect: detectShell()
    Detect-->>Cmd: 'zsh'
    Cmd->>Factory: createGenerator('zsh')
    Factory-->>Gen: instantiate
    Cmd->>Gen: generate(COMMAND_REGISTRY)
    Gen->>Registry: read command metadata
    Gen->>Provider: fetch dynamic IDs (changes/specs)
    Provider-->>Gen: {changeIds, specIds}
    Gen-->>Cmd: zsh completion script
    Cmd->>Factory: createInstaller('zsh')
    Factory-->>Installer: instantiate
    Cmd->>Installer: install(script)
    Installer->>Installer: detect OMZ / ensure dirs / backup
    Installer->>Installer: write completion file
    Installer->>Installer: optionally modify ~/.zshrc (markers)
    Installer-->>Cmd: InstallationResult
    Cmd-->>User: success message & instructions
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Areas needing extra attention:

  • src/core/completions/generators/zsh-generator.ts — Zsh script syntax, escaping, and dynamic helper correctness.
  • src/core/completions/installers/zsh-installer.ts — filesystem operations, backups, marker-based .zshrc edits, permission/error handling.
  • src/commands/completion.ts and src/cli/index.ts — shell resolution, CLI wiring, and user-visible error flows.
  • scripts/postinstall.js — CI/opt-out detection, dynamic imports, and ensuring npm install never fails.
  • Tests manipulating filesystem and env — isolation, teardown, and cross-platform behavior.

Possibly related issues

Poem

🐇 I hopped through flags and dashed through names,
I stitched up scripts for zsh’s games.
Backups snug, markers placed just so,
Tab-completions purr — now watch me go! 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.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 'feature/oh-my-zsh-completions' accurately describes the main feature being added - Zsh shell completions with Oh My Zsh support for the OpenSpec CLI, which is clearly the primary change in this changeset.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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

🧹 Nitpick comments (2)
src/core/completions/installers/zsh-installer.ts (2)

180-227: Consider extracting marker removal to FileSystemUtils for consistency.

The configureZshrc method uses FileSystemUtils.updateFileWithMarkers (Line 145) while removeZshrcConfig implements custom removal logic. This creates potential for inconsistency if the marker handling in FileSystemUtils changes.

Additionally, the logic at lines 215-217 unconditionally removes leading empty lines, but the comment suggests this should only happen "if the markers were at the top." The code doesn't actually verify the markers were at the top before removing these lines.

Consider:

  1. Add a removeMarkerSection method to FileSystemUtils to centralize marker management
  2. Clarify the empty line removal logic - either add a condition to check if startIndex === 0, or update the comment if unconditional removal is intentional

Example for the empty line fix:

-      // Remove trailing empty lines at the start if the markers were at the top
-      while (lines.length > 0 && lines[0].trim() === '') {
-        lines.shift();
-      }
+      // Remove leading empty lines if the markers were at the top of the file
+      if (startIndex === 0) {
+        while (lines.length > 0 && lines[0].trim() === '') {
+          lines.shift();
+        }
+      }

235-278: Consider validating the completion script parameter.

The method writes completionScript directly without validating that it's non-empty or contains valid content. While the caller should provide valid input, defensive validation would prevent installing corrupt completions.

Consider adding validation before writing:

 async install(completionScript: string): Promise<InstallationResult> {
   try {
+    if (!completionScript || completionScript.trim().length === 0) {
+      return {
+        success: false,
+        isOhMyZsh: false,
+        message: 'Invalid completion script: content is empty',
+      };
+    }
+
     const { path: targetPath, isOhMyZsh } = await this.getInstallationPath();
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d32e50f and 1784ffa.

📒 Files selected for processing (22)
  • openspec/changes/archive/2025-11-06-add-shell-completions/design.md (1 hunks)
  • openspec/changes/archive/2025-11-06-add-shell-completions/proposal.md (1 hunks)
  • openspec/changes/archive/2025-11-06-add-shell-completions/specs/cli-completion/spec.md (1 hunks)
  • openspec/changes/archive/2025-11-06-add-shell-completions/tasks.md (1 hunks)
  • openspec/specs/cli-completion/spec.md (1 hunks)
  • package.json (2 hunks)
  • scripts/postinstall.js (1 hunks)
  • scripts/test-postinstall.sh (1 hunks)
  • src/cli/index.ts (2 hunks)
  • src/commands/completion.ts (1 hunks)
  • src/core/completions/command-registry.ts (1 hunks)
  • src/core/completions/completion-provider.ts (1 hunks)
  • src/core/completions/factory.ts (1 hunks)
  • src/core/completions/generators/zsh-generator.ts (1 hunks)
  • src/core/completions/installers/zsh-installer.ts (1 hunks)
  • src/core/completions/types.ts (1 hunks)
  • src/utils/shell-detection.ts (1 hunks)
  • test/commands/completion.test.ts (1 hunks)
  • test/core/completions/completion-provider.test.ts (1 hunks)
  • test/core/completions/generators/zsh-generator.test.ts (1 hunks)
  • test/core/completions/installers/zsh-installer.test.ts (1 hunks)
  • test/utils/shell-detection.test.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
openspec/changes/*/**

📄 CodeRabbit inference engine (openspec/AGENTS.md)

Choose a unique kebab-case, verb-led change-id (add-, update-, remove-, refactor-) for openspec/changes//

Files:

  • openspec/changes/archive/2025-11-06-add-shell-completions/design.md
  • openspec/changes/archive/2025-11-06-add-shell-completions/specs/cli-completion/spec.md
  • openspec/changes/archive/2025-11-06-add-shell-completions/tasks.md
  • openspec/changes/archive/2025-11-06-add-shell-completions/proposal.md
openspec/changes/archive/**

📄 CodeRabbit inference engine (openspec/AGENTS.md)

Archive completed changes under openspec/changes/archive/YYYY-MM-DD-/ and run 'openspec validate --strict' post-archive; update specs/ if capabilities changed

Files:

  • openspec/changes/archive/2025-11-06-add-shell-completions/design.md
  • openspec/changes/archive/2025-11-06-add-shell-completions/specs/cli-completion/spec.md
  • openspec/changes/archive/2025-11-06-add-shell-completions/tasks.md
  • openspec/changes/archive/2025-11-06-add-shell-completions/proposal.md
openspec/{specs/**/spec.md,changes/*/specs/**/spec.md}

📄 CodeRabbit inference engine (openspec/AGENTS.md)

openspec/{specs/**/spec.md,changes/*/specs/**/spec.md}: Write requirements using SHALL/MUST for normative wording
Every requirement must include at least one scenario, formatted exactly with a '#### Scenario: ' header (no bullets or bold)
Under ADDED, introduce new capabilities as standalone requirements rather than altering existing ones

Files:

  • openspec/specs/cli-completion/spec.md
openspec/specs/**/spec.md

📄 CodeRabbit inference engine (openspec/AGENTS.md)

Keep current, deployed specs in openspec/specs//spec.md (one focused capability per directory)

Files:

  • openspec/specs/cli-completion/spec.md
🧠 Learnings (8)
📚 Learning: 2025-10-22T06:05:06.615Z
Learnt from: CR
Repo: Fission-AI/OpenSpec PR: 0
File: openspec/AGENTS.md:0-0
Timestamp: 2025-10-22T06:05:06.615Z
Learning: Applies to openspec/{specs/**/spec.md,changes/*/specs/**/spec.md} : Under ADDED, introduce new capabilities as standalone requirements rather than altering existing ones

Applied to files:

  • openspec/changes/archive/2025-11-06-add-shell-completions/specs/cli-completion/spec.md
  • openspec/specs/cli-completion/spec.md
  • openspec/changes/archive/2025-11-06-add-shell-completions/proposal.md
📚 Learning: 2025-10-22T06:05:06.615Z
Learnt from: CR
Repo: Fission-AI/OpenSpec PR: 0
File: openspec/AGENTS.md:0-0
Timestamp: 2025-10-22T06:05:06.615Z
Learning: Applies to openspec/changes/archive/** : Archive completed changes under openspec/changes/archive/YYYY-MM-DD-<name>/ and run 'openspec validate --strict' post-archive; update specs/ if capabilities changed

Applied to files:

  • openspec/changes/archive/2025-11-06-add-shell-completions/specs/cli-completion/spec.md
📚 Learning: 2025-10-22T06:05:06.615Z
Learnt from: CR
Repo: Fission-AI/OpenSpec PR: 0
File: openspec/AGENTS.md:0-0
Timestamp: 2025-10-22T06:05:06.615Z
Learning: Applies to openspec/changes/*/{proposal.md,tasks.md,design.md,specs/**/spec.md} : Scaffold each change with proposal.md, tasks.md, optional design.md, and delta spec files under openspec/changes/<change-id>/specs/<capability>/spec.md

Applied to files:

  • openspec/changes/archive/2025-11-06-add-shell-completions/specs/cli-completion/spec.md
  • openspec/changes/archive/2025-11-06-add-shell-completions/tasks.md
  • openspec/changes/archive/2025-11-06-add-shell-completions/proposal.md
📚 Learning: 2025-10-22T06:05:06.615Z
Learnt from: CR
Repo: Fission-AI/OpenSpec PR: 0
File: openspec/AGENTS.md:0-0
Timestamp: 2025-10-22T06:05:06.615Z
Learning: Applies to openspec/specs/**/spec.md : Keep current, deployed specs in openspec/specs/<capability>/spec.md (one focused capability per directory)

Applied to files:

  • openspec/changes/archive/2025-11-06-add-shell-completions/specs/cli-completion/spec.md
📚 Learning: 2025-10-22T06:05:06.615Z
Learnt from: CR
Repo: Fission-AI/OpenSpec PR: 0
File: openspec/AGENTS.md:0-0
Timestamp: 2025-10-22T06:05:06.615Z
Learning: Applies to openspec/changes/*/specs/**/spec.md : Use ADDED, MODIFIED, REMOVED, or RENAMED sections when authoring deltas; place changed requirements under the correct operation header

Applied to files:

  • openspec/changes/archive/2025-11-06-add-shell-completions/specs/cli-completion/spec.md
📚 Learning: 2025-10-22T06:05:06.615Z
Learnt from: CR
Repo: Fission-AI/OpenSpec PR: 0
File: openspec/AGENTS.md:0-0
Timestamp: 2025-10-22T06:05:06.615Z
Learning: Applies to openspec/{specs/**/spec.md,changes/*/specs/**/spec.md} : Write requirements using SHALL/MUST for normative wording

Applied to files:

  • openspec/changes/archive/2025-11-06-add-shell-completions/specs/cli-completion/spec.md
📚 Learning: 2025-10-22T06:05:06.615Z
Learnt from: CR
Repo: Fission-AI/OpenSpec PR: 0
File: openspec/AGENTS.md:0-0
Timestamp: 2025-10-22T06:05:06.615Z
Learning: Applies to openspec/changes/*/specs/**/spec.md : For MODIFIED requirements, paste the full existing requirement block (header through scenarios) and ensure the header text matches exactly (whitespace-insensitive)

Applied to files:

  • openspec/changes/archive/2025-11-06-add-shell-completions/specs/cli-completion/spec.md
📚 Learning: 2025-10-22T06:05:06.615Z
Learnt from: CR
Repo: Fission-AI/OpenSpec PR: 0
File: openspec/AGENTS.md:0-0
Timestamp: 2025-10-22T06:05:06.615Z
Learning: Applies to openspec/changes/*/tasks.md : Track implementation steps in tasks.md and mark each completed item with '- [x]' once finished

Applied to files:

  • openspec/changes/archive/2025-11-06-add-shell-completions/tasks.md
🧬 Code graph analysis (14)
test/commands/completion.test.ts (2)
src/commands/completion.ts (1)
  • CompletionCommand (22-185)
src/core/completions/installers/zsh-installer.ts (1)
  • ZshInstaller (23-412)
test/utils/shell-detection.test.ts (1)
src/utils/shell-detection.ts (2)
  • detectShell (11-48)
  • SupportedShell (4-4)
scripts/postinstall.js (3)
src/utils/shell-detection.ts (1)
  • detectShell (11-48)
src/core/completions/factory.ts (1)
  • CompletionFactory (21-74)
src/core/completions/command-registry.ts (1)
  • COMMAND_REGISTRY (35-291)
src/core/completions/command-registry.ts (1)
src/core/completions/types.ts (2)
  • FlagDefinition (6-31)
  • CommandDefinition (36-72)
src/cli/index.ts (2)
scripts/postinstall.js (1)
  • shell (127-127)
src/commands/completion.ts (1)
  • CompletionCommand (22-185)
src/core/completions/completion-provider.ts (1)
src/utils/item-discovery.ts (1)
  • getActiveChangeIds (4-23)
src/commands/completion.ts (4)
scripts/postinstall.js (5)
  • shell (127-127)
  • generator (79-79)
  • script (80-80)
  • installer (83-83)
  • result (84-84)
src/utils/shell-detection.ts (2)
  • SupportedShell (4-4)
  • detectShell (11-48)
src/core/completions/factory.ts (1)
  • CompletionFactory (21-74)
src/core/completions/command-registry.ts (1)
  • COMMAND_REGISTRY (35-291)
src/core/completions/generators/zsh-generator.ts (2)
src/core/completions/types.ts (3)
  • CompletionGenerator (77-90)
  • CommandDefinition (36-72)
  • FlagDefinition (6-31)
scripts/postinstall.js (1)
  • script (80-80)
test/core/completions/completion-provider.test.ts (1)
src/core/completions/completion-provider.ts (1)
  • CompletionProvider (16-128)
src/core/completions/factory.ts (3)
src/core/completions/installers/zsh-installer.ts (2)
  • InstallationResult (9-17)
  • ZshInstaller (23-412)
src/utils/shell-detection.ts (1)
  • SupportedShell (4-4)
src/core/completions/types.ts (1)
  • CompletionGenerator (77-90)
test/core/completions/generators/zsh-generator.test.ts (3)
scripts/postinstall.js (2)
  • generator (79-79)
  • script (80-80)
src/core/completions/generators/zsh-generator.ts (1)
  • ZshGenerator (7-373)
src/core/completions/types.ts (1)
  • CommandDefinition (36-72)
src/core/completions/types.ts (1)
src/utils/shell-detection.ts (1)
  • SupportedShell (4-4)
test/core/completions/installers/zsh-installer.test.ts (2)
scripts/postinstall.js (3)
  • installer (83-83)
  • result (84-84)
  • stat (44-44)
src/core/completions/installers/zsh-installer.ts (2)
  • ZshInstaller (23-412)
  • isInstalled (378-386)
src/core/completions/installers/zsh-installer.ts (2)
src/core/completions/factory.ts (1)
  • InstallationResult (15-15)
src/utils/file-system.ts (1)
  • FileSystemUtils (44-187)
🔇 Additional comments (22)
openspec/changes/archive/2025-11-06-add-shell-completions/specs/cli-completion/spec.md (1)

1-301: LGTM! Well-structured specification.

The specification follows all coding guidelines:

  • Properly archived under the correct date-based path format
  • Uses SHALL/MUST normative language throughout
  • Organizes new capabilities under ADDED section
  • Scenarios follow WHEN/THEN/AND structure
  • Comprehensive coverage of requirements including native shell behavior, installation flows, error handling, and testing

The architecture patterns defined here (factory, generators, installers, command registry) align well with the implementation files in this PR.

Based on learnings

package.json (1)

48-51: LGTM! Postinstall integration follows best practices.

The postinstall hook enables automatic shell completion installation after package install. The implementation (scripts/postinstall.js) includes:

  • CI detection to skip in automated environments
  • OPENSPEC_NO_COMPLETIONS=1 opt-out mechanism
  • Graceful failure that never breaks npm install
  • Silent skips when dist/ doesn't exist (dev scenarios)

This aligns with the specification requirements for installation automation.

test/commands/completion.test.ts (3)

1-96: LGTM! Comprehensive test coverage for generate subcommand.

The test suite properly covers:

  • Explicit shell parameter
  • Auto-detection scenarios
  • Error cases (unsupported shells, detection failures)
  • Case-insensitive shell handling

Mocking strategy is appropriate with shell-detection and ZshInstaller properly isolated.


98-153: LGTM! Install subcommand tests cover key scenarios.

Tests validate:

  • Explicit and auto-detected shell installation
  • Verbose output mode
  • Error handling for detection failures
  • Unsupported shell errors
  • Installation instruction display

196-268: LGTM! Error handling and integration tests are thorough.

The tests cover:

  • Installation/uninstallation failure scenarios with appropriate error messages
  • Shell detection fallback behavior
  • Explicit shell parameter precedence over auto-detection

Good use of dynamic imports and mock re-implementation for failure scenarios.

src/cli/index.ts (1)

16-16: LGTM! CLI integration follows consistent patterns.

The completion command integration:

  • Follows the same structure as existing commands (change, spec, validate)
  • Properly passes options (shell, verbose) to CompletionCommand methods
  • Uses consistent error handling with ora and process.exit(1)
  • Subcommands align with specification requirements

Also applies to: 254-300

scripts/postinstall.js (1)

1-146: LGTM! Postinstall script follows best practices.

The implementation demonstrates excellent postinstall hygiene:

  • ✓ Never fails npm install (all errors caught, exits 0)
  • ✓ Skips silently in CI environments
  • ✓ Respects opt-out via OPENSPEC_NO_COMPLETIONS=1
  • ✓ Guards against missing dist/ (dev setup scenario)
  • ✓ Gracefully handles detection and installation failures
  • ✓ Provides helpful tips when auto-install isn't possible
  • ✓ Dynamic imports prevent crashes when modules unavailable

The success messages appropriately vary by installation type (Oh My Zsh vs. standard Zsh vs. manual configuration needed).

src/utils/shell-detection.ts (1)

1-48: LGTM! Shell detection logic handles common scenarios correctly.

The implementation:

  • Detects Unix shells (zsh, bash, fish) via $SHELL environment variable
  • Handles PowerShell detection via PSModulePath (works for WSL scenarios)
  • Returns undefined for unsupported shells (cmd.exe, tcsh, etc.)
  • Uses case-insensitive matching to handle variations

The substring matching approach (e.g., shellName.includes('zsh')) is appropriate given standard shell path conventions.

test/utils/shell-detection.test.ts (1)

1-158: LGTM! Comprehensive test coverage with proper isolation.

The test suite thoroughly validates:

  • Detection for zsh, bash, fish across multiple common paths
  • Case-insensitive detection
  • PowerShell detection via PSModulePath on both Windows and non-Windows
  • Undefined behavior for unsupported shells and missing configuration
  • Platform-specific logic (Windows vs. Unix-like)

Environment restoration (lines 10-43) ensures test isolation. The use of Object.defineProperty for mocking process.platform is appropriate.

scripts/test-postinstall.sh (1)

1-57: LGTM! Well-designed integration test harness.

The test script validates three critical postinstall scenarios:

  1. Normal installation flow
  2. CI environment skip (silent)
  3. Opt-out flag skip (silent)

Good practices:

  • set -e for strict error handling
  • Environment preservation and restoration
  • Clear output with headers and expected behavior notes
  • Tests the actual behavior rather than implementation details
src/core/completions/command-registry.ts (1)

1-291: LGTM! Well-structured command registry.

The centralized registry follows clean architecture principles and provides excellent type safety. The COMMON_FLAGS pattern effectively reduces duplication.

test/core/completions/completion-provider.test.ts (1)

1-288: Excellent test coverage!

The test suite comprehensively validates caching behavior, TTL expiration, cache invalidation, and data retrieval. The use of temporary directories with proper cleanup is good practice.

src/core/completions/types.ts (1)

1-90: LGTM! Clean and well-documented type definitions.

The interfaces provide strong typing for the completion system with clear documentation. The positionalType union ensures type safety for dynamic completions.

src/core/completions/completion-provider.ts (1)

1-128: LGTM! Solid caching implementation.

The CompletionProvider implements efficient 2-second TTL caching to balance performance with freshness during tab completion. The parallel fetching in getAllIds() using Promise.all is a good optimization.

src/core/completions/factory.ts (1)

1-74: LGTM! Clean factory pattern with good extensibility.

The factory pattern makes it straightforward to add support for additional shells in future PRs. The defensive copy in getSupportedShells() and the type guard in isSupported() follow good practices.

test/core/completions/generators/zsh-generator.test.ts (1)

1-381: Excellent test coverage!

The test suite thoroughly validates the ZshGenerator implementation with comprehensive coverage of:

  • Interface compliance
  • Script structure and syntax
  • Command, flag, and subcommand handling
  • Positional argument types
  • Special character escaping
  • Edge cases and complex nested structures
src/core/completions/installers/zsh-installer.ts (6)

1-17: LGTM! Clean interface definition.

The imports are appropriate and the InstallationResult interface is well-structured with clear optional fields for different installation scenarios.


23-36: LGTM! Good testability design.

The constructor allows dependency injection of homeDir for testing while defaulting to os.homedir(). The marker-based configuration approach is a standard pattern for managing auto-generated config sections.


43-95: LGTM! Appropriate path detection and backup strategy.

The path detection correctly distinguishes between Oh My Zsh and standard Zsh installations. The timestamped backup approach prevents overwriting existing backups and the graceful failure handling is appropriate for this use case.


128-157: LGTM! Robust configuration with appropriate safeguards.

Good defensive programming with permission checks and the OPENSPEC_NO_AUTO_CONFIG opt-out mechanism. The graceful failure approach ensures installation doesn't break if .zshrc configuration fails.


287-315: LGTM! Clear and actionable user instructions.

The instructions appropriately differ between Oh My Zsh and standard Zsh setups, providing users with exactly the steps needed to enable completions.


322-411: LGTM! Comprehensive uninstallation and status checking.

The uninstall logic correctly handles partial installations (script exists but no config, or vice versa) and provides accurate feedback. The status checking methods offer a clean API for querying installation state.

Comment on lines +31 to +35
- **WHEN** user executes `openspec completion --help`
- **THEN** display available subcommands:
- `zsh` - Generate Zsh completion script
- `install [shell]` - Install completion for Zsh (auto-detects or requires explicit shell)
- `uninstall [shell]` - Remove completion for Zsh (auto-detects or requires explicit shell)
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 | 🟠 Major

Fix the documented subcommand list.

The CLI exposes completion generate/install/uninstall, not a zsh subcommand. The requirement should match the shipped interface to keep the spec authoritative. Please update the scenario accordingly.
[suggested diff]

-  - `zsh` - Generate Zsh completion script
-  - `install [shell]` - Install completion for Zsh (auto-detects or requires explicit shell)
-  - `uninstall [shell]` - Remove completion for Zsh (auto-detects or requires explicit shell)
+  - `generate [shell]` - Output the completion script (defaults to detected shell)
+  - `install [shell]` - Install completion for Zsh (auto-detects or requires explicit shell)
+  - `uninstall [shell]` - Remove completion for Zsh (auto-detects or requires explicit shell)
🤖 Prompt for AI Agents
In openspec/specs/cli-completion/spec.md around lines 31 to 35, the scenario
lists a non-existent `zsh` subcommand; update the expected subcommand list to
reflect the actual CLI interface `completion generate/install/uninstall` (and
describe their purposes, e.g., `generate` - produce completion script, `install
[shell]` - install for a shell, `uninstall [shell]` - remove for a shell).
Ensure the wording replaces `zsh` with `generate` and updates the bullet
descriptions to match the shipped commands.

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 (1)
src/core/completions/generators/zsh-generator.ts (1)

328-343: Consider using SUPPORTED_SHELLS constant for shell completion.

Line 339 hardcodes '*:shell:(zsh)', but the PR description mentions the architecture is prepared for additional shells (bash, fish, PowerShell). Consider referencing the SUPPORTED_SHELLS constant from factory.ts to keep the completion list in sync with supported shells.

Example refactor:

import { SUPPORTED_SHELLS } from '../factory.js';

// In generatePositionalSpec:
case 'shell':
  const shells = SUPPORTED_SHELLS.join(' ');
  return `'*:shell:(${shells})'`;
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b0bb9ad and b53f12d.

📒 Files selected for processing (1)
  • src/core/completions/generators/zsh-generator.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/core/completions/generators/zsh-generator.ts (2)
src/core/completions/types.ts (3)
  • CompletionGenerator (77-90)
  • CommandDefinition (36-72)
  • FlagDefinition (6-31)
scripts/postinstall.js (1)
  • script (80-80)
🔇 Additional comments (9)
src/core/completions/generators/zsh-generator.ts (9)

1-8: LGTM!

The class correctly implements the CompletionGenerator interface, and the const assertion on the shell property provides proper type safety.


16-83: Excellent fix from previous review!

The completion script structure correctly follows Zsh conventions. The critical issue from the previous review has been properly addressed—line 79 now uses compdef _openspec openspec for registration instead of invoking _openspec "$@" during load, which prevents errors when sourcing the completion file.


94-126: LGTM!

The helper correctly generates Zsh completion functions with proper handling of single and multi-line command arrays.


131-173: LGTM!

The dynamic completion helpers correctly use command substitution with openspec list and awk to format change and spec IDs with descriptions. The Zsh parameter expansion syntax ${(f)"..."} properly splits the output into array elements.


178-257: LGTM with minor edge case.

The function correctly handles both commands with and without subcommands, properly generating Zsh completion logic. The trailing backslash removal (lines 240-242) is necessary for valid Zsh syntax.

Edge case: If a command has neither flags nor positionals, the result would be _arguments with no arguments, which is invalid Zsh syntax. However, this is unlikely in practice as commands typically have at least one flag.


262-288: LGTM!

The subcommand function generation follows the same pattern as command functions with consistent handling of flags and positionals.


293-323: LGTM!

The flag specification generation correctly implements Zsh syntax for both mutually exclusive short/long forms and value completion.


348-365: LGTM!

The escaping methods correctly handle special characters for Zsh completion syntax, with backslash properly escaped first to avoid double-escaping issues.


370-372: LGTM!

The function correctly sanitizes command names for use in Zsh function identifiers by replacing dashes with underscores.

noameron and others added 2 commits November 6, 2025 20:39
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
  - Add __complete endpoint with tab-separated output for safe parsing
  - Replace brittle awk parsing with __complete in completion helpers
  - Add uninstall confirmation prompt with --yes flag to skip
  - Prefer $ZSH env var for Oh My Zsh detection before dir check
  - Add fpath verification guidance for OMZ installations
  - Update cli-completion spec to document generate subcommand
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)
src/utils/item-discovery.ts (1)

4-65: Consider extracting common discovery logic to reduce duplication.

All three functions (getActiveChangeIds, getSpecIds, getArchivedChangeIds) share nearly identical logic—they differ only in the base path, validation file name, and filter criteria. Consider refactoring into a parameterized helper function:

async function discoverItems(
  basePath: string,
  validationFile: string,
  excludeDirs: string[] = []
): Promise<string[]> {
  try {
    const entries = await fs.readdir(basePath, { withFileTypes: true });
    const result: string[] = [];
    for (const entry of entries) {
      if (!entry.isDirectory() || entry.name.startsWith('.') || excludeDirs.includes(entry.name)) continue;
      const filePath = path.join(basePath, entry.name, validationFile);
      try {
        await fs.access(filePath);
        result.push(entry.name);
      } catch {
        // skip directories without validation file
      }
    }
    return result.sort();
  } catch {
    return [];
  }
}

export async function getActiveChangeIds(root: string = process.cwd()): Promise<string[]> {
  return discoverItems(
    path.join(root, 'openspec', 'changes'),
    'proposal.md',
    ['archive']
  );
}

export async function getSpecIds(root: string = process.cwd()): Promise<string[]> {
  return discoverItems(
    path.join(root, 'openspec', 'specs'),
    'spec.md'
  );
}

export async function getArchivedChangeIds(root: string = process.cwd()): Promise<string[]> {
  return discoverItems(
    path.join(root, 'openspec', 'changes', 'archive'),
    'proposal.md'
  );
}

This would also help consolidate similar logic found in src/commands/change.ts (getActiveChanges method).

src/core/completions/installers/zsh-installer.ts (1)

186-233: Consider using FileSystemUtils for marker removal.

The removeZshrcConfig method manually implements marker-based content removal, which duplicates some logic from FileSystemUtils.updateFileWithMarkers. If FileSystemUtils provides a method to remove marker-enclosed content (or if updateFileWithMarkers can be extended to handle removal by passing empty content), consider using it to reduce code duplication and ensure consistent marker handling.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b53f12d and e978946.

📒 Files selected for processing (7)
  • src/cli/index.ts (2 hunks)
  • src/commands/completion.ts (1 hunks)
  • src/core/completions/generators/zsh-generator.ts (1 hunks)
  • src/core/completions/installers/zsh-installer.ts (1 hunks)
  • src/utils/item-discovery.ts (1 hunks)
  • test/commands/completion.test.ts (1 hunks)
  • test/core/completions/generators/zsh-generator.test.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • test/core/completions/generators/zsh-generator.test.ts
  • src/commands/completion.ts
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-10-22T06:05:06.615Z
Learnt from: CR
Repo: Fission-AI/OpenSpec PR: 0
File: openspec/AGENTS.md:0-0
Timestamp: 2025-10-22T06:05:06.615Z
Learning: Applies to openspec/changes/archive/** : Archive completed changes under openspec/changes/archive/YYYY-MM-DD-<name>/ and run 'openspec validate --strict' post-archive; update specs/ if capabilities changed

Applied to files:

  • src/utils/item-discovery.ts
📚 Learning: 2025-10-21T03:05:07.856Z
Learnt from: CR
Repo: Fission-AI/OpenSpec PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-21T03:05:07.856Z
Learning: Always open @/openspec/AGENTS.md when the request is ambiguous and the authoritative spec is needed before coding

Applied to files:

  • src/core/completions/generators/zsh-generator.ts
🧬 Code graph analysis (5)
src/utils/item-discovery.ts (2)
src/commands/change.ts (1)
  • getActiveChanges (241-259)
src/core/view.ts (1)
  • getChangesData (71-110)
src/cli/index.ts (2)
scripts/postinstall.js (1)
  • shell (127-127)
src/commands/completion.ts (1)
  • CompletionCommand (30-254)
src/core/completions/generators/zsh-generator.ts (2)
src/core/completions/types.ts (3)
  • CompletionGenerator (77-90)
  • CommandDefinition (36-72)
  • FlagDefinition (6-31)
scripts/postinstall.js (1)
  • script (80-80)
src/core/completions/installers/zsh-installer.ts (2)
src/core/completions/factory.ts (1)
  • InstallationResult (15-15)
src/utils/file-system.ts (1)
  • FileSystemUtils (44-187)
test/commands/completion.test.ts (2)
src/commands/completion.ts (1)
  • CompletionCommand (30-254)
src/core/completions/installers/zsh-installer.ts (1)
  • ZshInstaller (23-442)
🔇 Additional comments (1)
src/utils/item-discovery.ts (1)

46-65: LGTM! Logic is correct and consistent.

The function correctly discovers archived change IDs by scanning the archive directory, validating the presence of proposal.md, and returning a sorted list. The error handling and filtering logic align perfectly with the existing getActiveChangeIds and getSpecIds functions.

@noameron
Copy link
Contributor Author

@TabishB Hi, this PR is abit big partly due to the specs used

Copy link
Contributor

@TabishB TabishB left a comment

Choose a reason for hiding this comment

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

Hey this is amazing @noameron! Nice stuff man, comments belows are mostly nits. It's mainly comments around difference in what you've said in the spec vs what was implemented.

@noameron noameron requested a review from TabishB November 20, 2025 10:11
noameron and others added 3 commits November 20, 2025 13:53
  - Return structured result from detectShell() with shell and detected name
  - Detect already-installed completions and skip reinstall
  - Add update detection with automatic backup of previous version
  - Add debug logging to silent catch blocks for diagnostics
  - Quote fpath directories to handle paths with spaces
  - Verify Oh My Zsh fpath configuration and add to .zshrc if needed
  - Show helpful error for detected but unsupported shells
  - Update all tests for new detection API
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 (6)
test/core/completions/installers/zsh-installer.test.ts (1)

177-194: Consider using beforeEach/afterEach for environment variable management.

The manual save/restore pattern for OPENSPEC_NO_AUTO_CONFIG works but is error-prone if an assertion fails before restoration. Consider extracting this to a helper or using nested describe blocks with dedicated setup/teardown for tests that modify environment variables.

+  describe('with OPENSPEC_NO_AUTO_CONFIG=1', () => {
+    let originalEnv: string | undefined;
+
+    beforeEach(() => {
+      originalEnv = process.env.OPENSPEC_NO_AUTO_CONFIG;
+      process.env.OPENSPEC_NO_AUTO_CONFIG = '1';
+    });
+
+    afterEach(() => {
+      if (originalEnv === undefined) {
+        delete process.env.OPENSPEC_NO_AUTO_CONFIG;
+      } else {
+        process.env.OPENSPEC_NO_AUTO_CONFIG = originalEnv;
+      }
+    });
+
+    it('should include fpath instructions for standard Zsh when auto-config is disabled', async () => {
+      const result = await installer.install(testScript);
+
+      expect(result.instructions).toBeDefined();
+      expect(result.instructions!.join('\n')).toContain('fpath');
+      expect(result.instructions!.join('\n')).toContain('.zshrc');
+      expect(result.instructions!.join('\n')).toContain('compinit');
+    });
+  });
test/utils/shell-detection.test.ts (2)

40-42: Add configurable: true to platform property descriptor.

Without configurable: true, subsequent Object.defineProperty calls on process.platform may fail in some Node.js versions. This affects both the restore in afterEach and any later tests that mock the platform.

     Object.defineProperty(process, 'platform', {
       value: originalPlatform,
+      configurable: true,
     });

Apply the same change to all other Object.defineProperty calls for process.platform (lines 137-139, 154-156, 163-165).


179-184: Limited value in type test.

This test only verifies array length, which doesn't test the TypeScript type constraint at runtime. Consider removing this test or adding a compile-time type assertion test using expectTypeOf from vitest if available.

   describe('SupportedShell type', () => {
-    it('should accept valid shell types', () => {
-      const shells: SupportedShell[] = ['zsh', 'bash', 'fish', 'powershell'];
-      expect(shells).toHaveLength(4);
-    });
+    it('should accept valid shell types', () => {
+      // Type-level test: this will fail at compile time if types don't match
+      const shells: SupportedShell[] = ['zsh', 'bash', 'fish', 'powershell'];
+      expect(shells).toEqual(['zsh', 'bash', 'fish', 'powershell']);
+    });
   });
scripts/postinstall.js (2)

24-36: Consider extending CI detection.

The current CI detection checks only CI=true and CI=1. Many CI systems set CI to other truthy values or use different environment variables.

 function shouldSkipInstallation() {
   // Skip in CI environments
-  if (process.env.CI === 'true' || process.env.CI === '1') {
+  if (process.env.CI) {
     return { skip: true, reason: 'CI environment detected' };
   }

This matches common practice where any non-empty CI value indicates a CI environment.


89-99: Hardcoded Zsh-specific messages may be misleading for future shells.

The success messages (lines 91-98) are hardcoded for Zsh (exec zsh, ~/.zsh/completions/, ~/.zshrc). When support for other shells is added, these messages will be incorrect. Consider using the result object's data or the shell parameter to generate appropriate messages.

     if (result.success) {
       // Show success message based on installation type
       if (result.isOhMyZsh) {
         console.log(`✓ Shell completions installed`);
-        console.log(`  Restart shell: exec zsh`);
+        console.log(`  Restart shell: exec ${shell}`);
       } else if (result.zshrcConfigured) {
         console.log(`✓ Shell completions installed and configured`);
-        console.log(`  Restart shell: exec zsh`);
+        console.log(`  Restart shell: exec ${shell}`);
       } else {
-        console.log(`✓ Shell completions installed to ~/.zsh/completions/`);
-        console.log(`  Add to ~/.zshrc: fpath=(~/.zsh/completions $fpath)`);
-        console.log(`  Then: exec zsh`);
+        console.log(`✓ Shell completions installed to ${result.installedPath}`);
+        if (result.instructions) {
+          result.instructions.forEach(i => console.log(`  ${i}`));
+        }
       }
src/commands/completion.ts (1)

181-186: Hardcoded Zsh reference in confirmation prompt.

The confirmation message mentions ~/.zshrc specifically, which won't be accurate when other shells are supported.

     if (!skipConfirmation) {
       const confirmed = await confirm({
-        message: 'Remove OpenSpec configuration from ~/.zshrc?',
+        message: `Remove OpenSpec ${shell} completion configuration?`,
         default: false,
       });
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e3a2556 and 932d1e5.

📒 Files selected for processing (7)
  • scripts/postinstall.js (1 hunks)
  • src/commands/completion.ts (1 hunks)
  • src/core/completions/installers/zsh-installer.ts (1 hunks)
  • src/utils/shell-detection.ts (1 hunks)
  • test/commands/completion.test.ts (1 hunks)
  • test/core/completions/installers/zsh-installer.test.ts (1 hunks)
  • test/utils/shell-detection.test.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • test/commands/completion.test.ts
  • src/core/completions/installers/zsh-installer.ts
🧰 Additional context used
🧬 Code graph analysis (4)
test/utils/shell-detection.test.ts (1)
src/utils/shell-detection.ts (2)
  • detectShell (21-62)
  • SupportedShell (4-4)
scripts/postinstall.js (3)
src/utils/shell-detection.ts (1)
  • detectShell (21-62)
src/core/completions/factory.ts (1)
  • CompletionFactory (21-74)
src/core/completions/command-registry.ts (1)
  • COMMAND_REGISTRY (35-291)
src/commands/completion.ts (4)
src/core/completions/completion-provider.ts (1)
  • CompletionProvider (16-128)
src/utils/shell-detection.ts (2)
  • SupportedShell (4-4)
  • detectShell (21-62)
src/core/completions/command-registry.ts (1)
  • COMMAND_REGISTRY (35-291)
src/utils/item-discovery.ts (1)
  • getArchivedChangeIds (46-65)
test/core/completions/installers/zsh-installer.test.ts (1)
src/core/completions/installers/zsh-installer.ts (2)
  • ZshInstaller (23-507)
  • isInstalled (473-481)
🔇 Additional comments (16)
test/core/completions/installers/zsh-installer.test.ts (6)

1-22: Good test setup with isolated temp directories.

The beforeEach/afterEach pattern properly creates and cleans up isolated test directories using randomUUID(), preventing test pollution.


196-204: LGTM for error handling test.

Testing with an inaccessible path to verify graceful failure is appropriate. The implementation correctly returns { success: false } without throwing.


246-269: Good coverage for paths with spaces.

This test properly validates that paths containing spaces are quoted correctly in .zshrc configuration, which is important for shell compatibility.


272-313: Comprehensive uninstall test coverage.

Tests properly verify both successful removal and failure cases, including Oh My Zsh-specific path handling.


389-512: Thorough .zshrc configuration tests.

Good coverage of marker-based configuration management, including creation, updates, and preservation of user content outside markers.


585-594: Good defensive test for invalid marker placement.

Testing the case where END marker appears before START marker ensures the implementation handles corrupted configurations gracefully.

test/utils/shell-detection.test.ts (3)

10-43: Good environment isolation pattern.

The beforeEach/afterEach pattern properly saves and restores all relevant environment variables and process.platform, preventing test pollution.


53-67: Good coverage of shell path variations.

Testing multiple common installation paths for each shell ensures the detection works across different system configurations.


129-144: PowerShell detection coverage looks good.

Tests properly verify both PSModulePath presence and Windows platform scenarios.

scripts/postinstall.js (1)

143-147: Appropriate fail-safe pattern for postinstall.

Using main().catch(() => process.exit(0)) ensures the npm install never fails due to completion installation issues, which is the correct behavior for an optional enhancement.

src/utils/shell-detection.ts (3)

1-14: Clean type definitions.

The SupportedShell type and ShellDetectionResult interface provide good type safety for shell detection consumers.


25-36: Shell detection using includes() is pragmatic.

The substring matching approach works for common shell paths. Edge cases like /usr/bin/zsh-5.8 (versioned binaries) will correctly match. The approach is reasonable for the expected use cases.


45-59: Windows detection logic is sound.

Using PSModulePath as the primary PowerShell indicator is reliable. The fallback to COMSPEC for cmd.exe detection properly handles the unsupported case.

src/commands/completion.ts (3)

43-75: Past review feedback addressed.

The resolveShellOrExit method now properly distinguishes between:

  1. Detected but unsupported shell (lines 54-58): Shows "Shell '' is not supported yet"
  2. Could not detect shell (lines 60-65): Shows "Could not auto-detect shell"

This addresses the previous reviewer's feedback about providing better messaging for detected-but-unsupported shells.


219-254: Clean machine-readable output for shell completions.

The complete() method properly outputs tab-separated data and silently fails with exit code 1 for invalid types, which is appropriate for shell completion scripts that shouldn't produce error messages.


125-172: Well-structured installation flow with good UX.

The installation method provides clear feedback via spinner, supports verbose output for debugging, and handles success/failure cases appropriately with actionable instructions.

Copy link
Contributor

@TabishB TabishB left a comment

Choose a reason for hiding this comment

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

Thanks @noameron for the contribution 🚀

@TabishB TabishB merged commit 1adf3ce into Fission-AI:main Dec 12, 2025
7 checks passed
@noameron noameron deleted the feature/oh-my-zsh-completions branch December 15, 2025 12:20
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.

2 participants