Skip to content

feat(cli): add profile switching, bulk-import with column mapping, and fix shell completions - #404

Open
ImBIOS wants to merge 2 commits into
usemoss:mainfrom
ImBIOS:feat/cli-improvements-profile-and-bulk-import
Open

feat(cli): add profile switching, bulk-import with column mapping, and fix shell completions#404
ImBIOS wants to merge 2 commits into
usemoss:mainfrom
ImBIOS:feat/cli-improvements-profile-and-bulk-import

Conversation

@ImBIOS

@ImBIOS ImBIOS commented Jul 16, 2026

Copy link
Copy Markdown

Description

This PR introduces three major, high-impact improvements to the Moss CLI to enhance developer experience, streamline multi-project workflows, and fix a critical bug in the shell completions command.


1. 🐛 Fix Shell Completions Fall-through Bug

While running the CLI tests, I discovered that the command was failing with:
Shell completion is unavailable in this Typer installation.

Upon inspection of packages/moss-cli/src/moss_cli/commands/completions.py, I identified a fall-through bug in the exception handling block:

    except Exception:  # pragma: no cover
        try:
            from typer._completion_shared import get_completion_script  # type: ignore
        except Exception:  # pragma: no cover - depends on Typer installation
            output.print_error(
                "Shell completion is unavailable in this Typer installation.",
                json_mode,
            )
            raise typer.Exit(1)
        output.print_error(
            "Shell completion is unavailable in this Typer installation.",
            json_mode,
        )
        raise typer.Exit(1)

Even when the inner import from typer._completion_shared succeeded, the code fell through to print the error and exit non-zero.

  • Fix: Removed the duplicate error print/raise block at the end of the outer except block so that successful imports correctly proceed to script generation.
  • Result: All shell completion tests are now 100% green!

2. 📁 Profile Switching Commands (Closes #176, Closes #126)

Added subcommands to make switching between named credential profiles seamless and explicit without manually editing configuration files or relying on environment variables:

  • moss profile use <profile-name> (or moss profile set-default <profile-name>): Sets the active/default profile in the config.
  • moss profile current: Displays the currently selected profile (taking into account CLI flags and env vars).

3. 📥 Bulk-Import with Column Mapping (Closes #379)

Added a powerful bulk-loading command to import documents from arbitrary CSV, JSON, or JSONL files without writing code:

  • moss doc import <index_name> -f <file_path>
  • Supports column mapping via --id-column / -i and --text-column / -t to map arbitrary column/key names to document ID and text.
  • Automatically maps all other columns/keys to the document's metadata dictionary (satisfying the Dict[str, str] constraint of DocumentInfo by converting values to strings and serializing complex objects/lists to JSON strings).
  • Supports explicit metadata filtering selection via --metadata-columns / -m and toggling with --include-all-metadata / --no-include-all-metadata.

4. 🧪 Comprehensive Test Coverage

Added robust unit and integration tests in tests/test_profiles.py covering:

  • set_active_profile success and failure paths.
  • moss profile use, set-default, and current CLI commands.
  • CSV, JSON, and JSONL document parsers with arbitrary column mapping.
  • End-to-end integration test of moss doc import with mocked API client responses.

All 42 CLI tests are now fully passing!

ImBIOS added 2 commits July 16, 2026 11:11
Upgrades esbuild, pydantic-settings, nltk, cryptography, and aiohttp to keep the build healthy and up to date.

Closes usemoss#377

Closes usemoss#366

Closes usemoss#364

Closes usemoss#363

Closes usemoss#357
Copilot AI review requested due to automatic review settings July 16, 2026 04:21

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR enhances the Moss CLI’s usability for multi-project workflows by adding explicit profile switching, introducing a bulk document import command with column/key mapping, and fixing a shell completions fall-through bug. It also updates several JS/Python lockfiles and overrides (notably esbuild, plus some Python deps in uv.lock snapshots).

Changes:

  • Add moss profile use|set-default|current commands and config support for setting the active profile.
  • Add moss doc import for CSV/JSON/JSONL bulk imports with ID/text/metadata column mapping.
  • Fix moss completions so it doesn’t incorrectly error/exit after a successful fallback import.

Reviewed changes

Copilot reviewed 10 out of 39 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
packages/vitepress-plugin-moss/demo-site/package.json Bump esbuild override for the demo site.
packages/moss-md-indexer/pnpm-lock.yaml Lockfile updates reflecting esbuild override bump.
packages/moss-md-indexer/package.json Bump esbuild overrides.
packages/moss-md-indexer/example/package.json Bump esbuild override in example.
packages/moss-data-connector/moss-connector-supabase/uv.lock Update Python lock snapshot (deps + revision metadata).
packages/moss-data-connector/moss-connector-sqlite/uv.lock Update Python lock snapshot (deps + revision metadata).
packages/moss-data-connector/moss-connector-mongodb/uv.lock Update Python lock snapshot (deps + revision metadata).
packages/moss-cli/tests/test_profiles.py Add tests for profile switching and document import mapping.
packages/moss-cli/src/moss_cli/documents.py Add CSV/JSON/JSONL import helpers with mapping + metadata handling.
packages/moss-cli/src/moss_cli/config.py Add set_active_profile() to persist active profile selection.
packages/moss-cli/src/moss_cli/commands/profile.py Add profile use, set-default, and current commands.
packages/moss-cli/src/moss_cli/commands/doc.py Add doc import command wiring to new import helpers.
packages/moss-cli/src/moss_cli/commands/completions.py Remove erroneous fall-through error/exit in completion script generation.
packages/agora-moss/uv.lock Update Python lock snapshot (deps + revision metadata).
package.json Bump root esbuild override.
package-lock.json Update npm lockfile for esbuild patch bump.
moss-live-labs/python/uv.lock Update experimental Python lock snapshot (deps + revision metadata).
moss-live-labs/examples/voice-agent/uv.lock Update experimental Python lock snapshot (deps + revision metadata).
moss-live-labs/examples/semantic-cache/uv.lock Update experimental Python lock snapshot (revision metadata).
moss-live-labs/examples/image-search/setup-py/uv.lock Update experimental Python lock snapshot (deps + revision metadata).
moss-live-labs/examples/image-search/backend-py/uv.lock Update experimental Python lock snapshot (revision metadata).
examples/voice-agents/insurance-adjuster/uv.lock Update example Python lock snapshot (revision metadata).
examples/cookbook/smolagents/uv.lock Update cookbook Python lock snapshot (revision metadata).
examples/cookbook/sim/uv.lock Update cookbook Python lock snapshot (revision metadata).
apps/vapi-moss/uv.lock Update app Python lock snapshot (revision metadata).
apps/elevenlabs-moss/uv.lock Update app Python lock snapshot (deps + revision metadata).
apps/agora-moss/uv.lock Update app Python lock snapshot (deps + revision metadata).
Files not reviewed (2)
  • packages/moss-md-indexer/example/pnpm-lock.yaml: Generated file
  • packages/moss-md-indexer/pnpm-lock.yaml: Generated file

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

metadata_columns: Optional[List[str]] = None,
include_all_metadata: bool = True,
) -> List[DocumentInfo]:
reader = csv.DictReader(content.splitlines())
content: str,
id_column: str = "id",
text_column: str = "text",
metadata_columns: Optional[List[str]] = None,
source: str = "input",
id_column: str = "id",
text_column: str = "text",
metadata_columns: Optional[List[str]] = None,
source: str = "input",
id_column: str = "id",
text_column: str = "text",
metadata_columns: Optional[List[str]] = None,
index: int,
id_column: str = "id",
text_column: str = "text",
metadata_columns: Optional[List[str]] = None,
file_path: str,
id_column: str = "id",
text_column: str = "text",
metadata_columns: Optional[List[str]] = None,
raise typer.BadParameter(f"File not found: {file_path}")

suffix = path.suffix.lower()
content = path.read_text()
def import_command(
ctx: typer.Context,
index_name: str = typer.Argument(..., help="Index name", autocompletion=complete_index_name),
file: str = typer.Option(..., "--file", "-f", help="Path to JSON/CSV document file, or '-' for stdin"),
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

3 participants