Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions python/vectorless/cli/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"""Vectorless CLI — command-line interface for document intelligence."""

from vectorless.cli.main import app

__all__ = ["app"]
25 changes: 25 additions & 0 deletions python/vectorless/cli/commands/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"""CLI command modules."""

from vectorless.cli.commands.init import init_cmd
from vectorless.cli.commands.add import add_cmd
from vectorless.cli.commands.list_cmd import list_cmd
from vectorless.cli.commands.info import info_cmd
from vectorless.cli.commands.remove import remove_cmd
from vectorless.cli.commands.query import query_cmd
from vectorless.cli.commands.ask import ask_cmd
from vectorless.cli.commands.tree import tree_cmd
from vectorless.cli.commands.stats import stats_cmd
from vectorless.cli.commands.config_cmd import config_cmd

__all__ = [
"init_cmd",
"add_cmd",
"list_cmd",
"info_cmd",
"remove_cmd",
"query_cmd",
"ask_cmd",
"tree_cmd",
"stats_cmd",
"config_cmd",
]
32 changes: 32 additions & 0 deletions python/vectorless/cli/commands/add.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"""add command — index documents (maps to engine.index)."""

from typing import Optional

import click


def add_cmd(
path: str,
*,
recursive: bool = False,
fmt: Optional[str] = None,
force: bool = False,
jobs: int = 1,
verbose: bool = False,
) -> None:
"""Index a document or directory.

Args:
path: File or directory path.
recursive: Index directory recursively.
fmt: Force format ("markdown" | "pdf" | None for auto-detect).
force: Force re-index existing documents.
jobs: Number of parallel indexing jobs.
verbose: Show detailed progress.

Uses:
Engine.index(IndexContext)
IndexContext.from_path / from_paths / from_dir
IndexOptions(mode="force" if force else "default")
"""
raise NotImplementedError
46 changes: 46 additions & 0 deletions python/vectorless/cli/commands/ask.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
"""ask command — interactive REPL for multi-turn queries."""

from typing import Optional

import click


def ask_cmd(*, doc_id: Optional[str] = None, verbose: bool = False) -> None:
"""Start an interactive query REPL.

Args:
doc_id: Limit to a specific document.
verbose: Show Agent navigation steps.

Uses:
Engine.query() in a loop with user input.
Maintains conversation context across turns.

Built-in commands (prefixed with .):
.help Show available commands
.tree Display current document tree
.stats Show session statistics (LLM calls, tokens, cost)
.nav-log Show navigation log for current conversation
.doc <id> Switch query target document
.doc Show current target document
.verbose Toggle verbose mode
.quit Exit REPL
"""
raise NotImplementedError


def _handle_repl_command(line: str) -> bool:
"""Handle a built-in REPL command (prefixed with .).

Args:
line: Raw input line.

Returns:
True if the command was handled, False if it's a query.
"""
raise NotImplementedError


def _print_welcome() -> None:
"""Print REPL welcome message with available commands."""
raise NotImplementedError
63 changes: 63 additions & 0 deletions python/vectorless/cli/commands/config_cmd.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"""config command — view and modify configuration."""

from typing import Optional

import click


def config_cmd(
key: Optional[str] = None,
value: Optional[str] = None,
*,
init_config: bool = False,
) -> None:
"""View or modify workspace configuration.

Args:
key: Config key (dot-separated, e.g. "llm.model").
value: New value to set. If None, prints current value.
init_config: Reset config to defaults.

Usage:
vectorless-cli config # show all
vectorless-cli config llm.model # show one key
vectorless-cli config llm.model gpt-4o # set value
vectorless-cli config --init # reset defaults

Config keys (in .vectorless/config.toml):
llm.model LLM model name
llm.api_key API key (or env VECTORLESS_API_KEY)
llm.endpoint API endpoint
retrieval.strategy agent | pipeline
retrieval.max_rounds navigation budget
index.summary full | selective | lazy | navigation
index.compact_mode true | false
"""
raise NotImplementedError


def _load_config(workspace: str) -> dict:
"""Load config.toml from workspace.

Args:
workspace: Path to .vectorless/ directory.

Returns:
Parsed config dict.
"""
raise NotImplementedError


def _save_config(workspace: str, config: dict) -> None:
"""Save config dict to config.toml.

Args:
workspace: Path to .vectorless/ directory.
config: Config dict to serialize.
"""
raise NotImplementedError


def _default_config() -> dict:
"""Return default configuration values."""
raise NotImplementedError
30 changes: 30 additions & 0 deletions python/vectorless/cli/commands/info.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
"""info command — show document index details."""

import click


def info_cmd(doc_id: str) -> None:
"""Show detailed information about an indexed document.

Args:
doc_id: Document identifier.

Uses:
Engine.list() -> filter by doc_id
Display: title, source, format, node count, depth, leaf count,
total tokens, routing keywords, top-level sections,
indexed timestamp.

Example output:
Document: API Guide (a1b2c3)
Source: ./docs/api-guide.md
Format: Markdown
Tree: 45 nodes, depth 4, 12 leaves
Total tokens: 8,234
Routing keywords: api, authentication, endpoints, rate-limit
Top-level sections:
1. Overview (12 leaves)
2. Authentication (8 leaves)
3. Endpoints (18 leaves)
"""
raise NotImplementedError
18 changes: 18 additions & 0 deletions python/vectorless/cli/commands/init.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"""init command — initialize .vectorless/ workspace."""

import click


def init_cmd(workspace: str) -> None:
"""Create .vectorless/ directory structure with default config.

Creates:
.vectorless/
├── config.toml # LLM key/model/endpoint, retrieval strategy
├── data/ # Index data (DocumentTree, ReasoningIndex)
└── cache/ # Memo cache

Args:
workspace: Parent directory to create .vectorless/ in.
"""
raise NotImplementedError
18 changes: 18 additions & 0 deletions python/vectorless/cli/commands/list_cmd.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"""list command — list indexed documents."""

import click


def list_cmd(*, fmt: str = "table") -> None:
"""List all indexed documents in the workspace.

Args:
fmt: Output format — "table" or "json".

Uses:
Engine.list() -> List[DocumentInfo]

Table output:
Doc ID | Title | Format | Nodes | Pages | Indexed At
"""
raise NotImplementedError
40 changes: 40 additions & 0 deletions python/vectorless/cli/commands/query.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
"""query command — single query (maps to engine.query)."""

from typing import Optional

import click


def query_cmd(
question: str,
*,
doc_ids: tuple[str, ...] = (),
workspace_scope: bool = False,
fmt: str = "text",
verbose: bool = False,
max_tokens: Optional[int] = None,
) -> None:
"""Execute a single query against indexed documents.

Args:
question: Natural-language question.
doc_ids: Limit to specific document IDs.
workspace_scope: Query across all documents.
fmt: Output format — "text" or "json".
verbose: Show Agent navigation steps.
max_tokens: Max result tokens.

Uses:
Engine.query(QueryContext(question)
.with_doc_ids([...]) or .with_workspace()
.with_max_tokens(n))
-> QueryResult

Verbose mode prints Agent navigation:
[1/8] Bird's-eye: 3 top-level branches
[2/8] Descend → payment-configuration
[3/8] GetContent → doc 29139b
[4/8] Evaluate → sufficient
→ Answer: ...
"""
raise NotImplementedError
15 changes: 15 additions & 0 deletions python/vectorless/cli/commands/remove.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
"""remove command — remove document index."""

import click


def remove_cmd(doc_id: str) -> None:
"""Remove a document from the index.

Args:
doc_id: Document identifier to remove.

Uses:
Engine.remove(doc_id)
"""
raise NotImplementedError
22 changes: 22 additions & 0 deletions python/vectorless/cli/commands/stats.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"""stats command — workspace statistics."""

import click


def stats_cmd() -> None:
"""Show workspace statistics.

Displays:
- Workspace path
- Number of indexed documents
- Total nodes / leaves / tokens
- Index size on disk
- DocumentGraph info (edges, connected components)
- Last indexed timestamp

Uses:
Engine.list() -> count documents
Engine.metrics_report()
Filesystem scan for size info
"""
raise NotImplementedError
32 changes: 32 additions & 0 deletions python/vectorless/cli/commands/tree.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"""tree command — visualize document tree structure."""

from typing import Optional

import click


def tree_cmd(
doc_id: str,
*,
depth: Optional[int] = None,
show_summary: bool = False,
show_keywords: bool = False,
) -> None:
"""Visualize the hierarchical tree structure of an indexed document.

Args:
doc_id: Document identifier.
depth: Max depth to display (None = full tree).
show_summary: Include node summaries in output.
show_keywords: Include routing keywords in output.

Example output:
API Guide (a1b2c3) — 45 nodes, 12 leaves
1. Overview [routing: api-overview] (12 leaves)
├── 1.1 Introduction
├── 1.2 Authentication [keywords: auth, token, api-key]
│ ├── 1.2.1 API Key Setup
│ └── 1.2.2 OAuth Flow
└── 1.3 Endpoints (18 leaves)
"""
raise NotImplementedError
Loading
Loading