moss-cli 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- moss_cli-0.1.0/LICENSE +6 -0
- moss_cli-0.1.0/PKG-INFO +229 -0
- moss_cli-0.1.0/README.md +199 -0
- moss_cli-0.1.0/pyproject.toml +65 -0
- moss_cli-0.1.0/setup.cfg +4 -0
- moss_cli-0.1.0/src/moss_cli/__init__.py +3 -0
- moss_cli-0.1.0/src/moss_cli/commands/__init__.py +0 -0
- moss_cli-0.1.0/src/moss_cli/commands/doc.py +101 -0
- moss_cli-0.1.0/src/moss_cli/commands/index.py +92 -0
- moss_cli-0.1.0/src/moss_cli/commands/init_cmd.py +52 -0
- moss_cli-0.1.0/src/moss_cli/commands/job.py +42 -0
- moss_cli-0.1.0/src/moss_cli/commands/search.py +74 -0
- moss_cli-0.1.0/src/moss_cli/commands/version.py +24 -0
- moss_cli-0.1.0/src/moss_cli/config.py +57 -0
- moss_cli-0.1.0/src/moss_cli/documents.py +116 -0
- moss_cli-0.1.0/src/moss_cli/job_waiter.py +71 -0
- moss_cli-0.1.0/src/moss_cli/main.py +77 -0
- moss_cli-0.1.0/src/moss_cli/output.py +221 -0
- moss_cli-0.1.0/src/moss_cli.egg-info/PKG-INFO +229 -0
- moss_cli-0.1.0/src/moss_cli.egg-info/SOURCES.txt +22 -0
- moss_cli-0.1.0/src/moss_cli.egg-info/dependency_links.txt +1 -0
- moss_cli-0.1.0/src/moss_cli.egg-info/entry_points.txt +2 -0
- moss_cli-0.1.0/src/moss_cli.egg-info/requires.txt +12 -0
- moss_cli-0.1.0/src/moss_cli.egg-info/top_level.txt +1 -0
moss_cli-0.1.0/LICENSE
ADDED
moss_cli-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: moss-cli
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Command-line interface for Moss semantic search
|
|
5
|
+
Author-email: "InferEdge Inc." <contact@usemoss.dev>
|
|
6
|
+
Keywords: search,semantic,cli,moss
|
|
7
|
+
Classifier: Development Status :: 3 - Alpha
|
|
8
|
+
Classifier: Intended Audience :: Developers
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
15
|
+
Requires-Python: >=3.10
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: moss>=1.0.0
|
|
19
|
+
Requires-Dist: typer>=0.9.0
|
|
20
|
+
Requires-Dist: rich>=13.0.0
|
|
21
|
+
Provides-Extra: dev
|
|
22
|
+
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
23
|
+
Requires-Dist: black>=24.0.0; extra == "dev"
|
|
24
|
+
Requires-Dist: isort>=5.0.0; extra == "dev"
|
|
25
|
+
Requires-Dist: flake8>=7.0.0; extra == "dev"
|
|
26
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
27
|
+
Requires-Dist: build>=1.0.0; extra == "dev"
|
|
28
|
+
Requires-Dist: twine>=5.0.0; extra == "dev"
|
|
29
|
+
Dynamic: license-file
|
|
30
|
+
|
|
31
|
+
# Moss CLI
|
|
32
|
+
|
|
33
|
+
**Command-line interface for Moss semantic search** — manage indexes, documents, and queries directly from your terminal.
|
|
34
|
+
|
|
35
|
+
Moss CLI wraps the [Moss Python SDK](https://docs.usemoss.dev/) so you can build and query semantic search indexes without writing any code. Ideal for quick prototyping, scripting, CI/CD pipelines, and data workflows.
|
|
36
|
+
|
|
37
|
+
## Features
|
|
38
|
+
|
|
39
|
+
- ⚡ **Full SDK coverage** — every SDK operation available as a CLI command
|
|
40
|
+
- 🔍 **Semantic search** — query indexes with configurable hybrid search (semantic + keyword)
|
|
41
|
+
- 📦 **Index management** — create, list, inspect, and delete indexes
|
|
42
|
+
- 📄 **Document management** — add, update, retrieve, and delete documents
|
|
43
|
+
- 🚀 **Local by default** — downloads indexes for on-device queries, `--cloud` to skip
|
|
44
|
+
- 🔧 **Flexible auth** — CLI flags, environment variables, or config file
|
|
45
|
+
- 📊 **Multiple output formats** — rich tables for humans, `--json` for scripts
|
|
46
|
+
- ⏳ **Job tracking** — poll background jobs with live progress display
|
|
47
|
+
- 🔗 **Pipe-friendly** — stdin/stdout support for composing with other tools
|
|
48
|
+
|
|
49
|
+
## Installation
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
pip install moss-cli
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Quick Start
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
# 1. Save your credentials
|
|
59
|
+
moss init
|
|
60
|
+
|
|
61
|
+
# 2. List your indexes
|
|
62
|
+
moss index list
|
|
63
|
+
|
|
64
|
+
# 3. Create an index from a JSON file
|
|
65
|
+
moss index create my-index -f docs.json --wait
|
|
66
|
+
|
|
67
|
+
# 4. Search it
|
|
68
|
+
moss query my-index "what is machine learning"
|
|
69
|
+
|
|
70
|
+
# 5. Search via cloud API (skips local download)
|
|
71
|
+
moss query my-index "neural networks" --cloud
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Authentication
|
|
75
|
+
|
|
76
|
+
Credentials are resolved in this order:
|
|
77
|
+
|
|
78
|
+
1. **CLI flags**: `--project-id` and `--project-key`
|
|
79
|
+
2. **Environment variables**: `MOSS_PROJECT_ID` and `MOSS_PROJECT_KEY`
|
|
80
|
+
3. **Config file**: `~/.moss/config.json` (created by `moss init`)
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
# Option 1: Interactive setup (recommended)
|
|
84
|
+
moss init
|
|
85
|
+
|
|
86
|
+
# Option 2: Environment variables
|
|
87
|
+
export MOSS_PROJECT_ID="your-project-id"
|
|
88
|
+
export MOSS_PROJECT_KEY="your-project-key"
|
|
89
|
+
|
|
90
|
+
# Option 3: Inline flags
|
|
91
|
+
moss index list --project-id "..." --project-key "..."
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Commands
|
|
95
|
+
|
|
96
|
+
### Index Management
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
# Create an index with documents from a JSON file
|
|
100
|
+
moss index create my-index -f documents.json --model moss-minilm
|
|
101
|
+
|
|
102
|
+
# Create and wait for completion
|
|
103
|
+
moss index create my-index -f documents.json --wait
|
|
104
|
+
|
|
105
|
+
# List all indexes
|
|
106
|
+
moss index list
|
|
107
|
+
|
|
108
|
+
# Get index details
|
|
109
|
+
moss index get my-index
|
|
110
|
+
|
|
111
|
+
# Delete an index
|
|
112
|
+
moss index delete my-index
|
|
113
|
+
moss index delete my-index --confirm # skip prompt
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Document Management
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
# Add documents to an existing index
|
|
120
|
+
moss doc add my-index -f new-docs.json
|
|
121
|
+
|
|
122
|
+
# Add with upsert (update existing, insert new)
|
|
123
|
+
moss doc add my-index -f docs.json --upsert --wait
|
|
124
|
+
|
|
125
|
+
# Get all documents
|
|
126
|
+
moss doc get my-index
|
|
127
|
+
|
|
128
|
+
# Get specific documents
|
|
129
|
+
moss doc get my-index --ids doc1,doc2,doc3
|
|
130
|
+
|
|
131
|
+
# Delete documents
|
|
132
|
+
moss doc delete my-index --ids doc1,doc2
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Query
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
# Search (downloads index and queries on-device by default)
|
|
139
|
+
moss query my-index "what is deep learning"
|
|
140
|
+
|
|
141
|
+
# Tune results: more results, keyword-heavy
|
|
142
|
+
moss query my-index "neural networks" --top-k 20 --alpha 0.3
|
|
143
|
+
|
|
144
|
+
# Cloud mode (skip download, query via cloud API)
|
|
145
|
+
moss query my-index "transformers" --cloud
|
|
146
|
+
|
|
147
|
+
# With metadata filter (local only)
|
|
148
|
+
moss query my-index "shoes" --filter '{"field": "category", "condition": {"$eq": "footwear"}}'
|
|
149
|
+
|
|
150
|
+
# Pipe query from stdin
|
|
151
|
+
echo "what is AI" | moss query my-index
|
|
152
|
+
|
|
153
|
+
# JSON output for scripting
|
|
154
|
+
moss query my-index "query" --json | jq '.docs[0].text'
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Job Tracking
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
# Check job status
|
|
161
|
+
moss job status <job-id>
|
|
162
|
+
|
|
163
|
+
# Wait for job to finish (with live progress)
|
|
164
|
+
moss job status <job-id> --wait
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Other
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
# Print version info
|
|
171
|
+
moss version
|
|
172
|
+
|
|
173
|
+
# Global JSON output
|
|
174
|
+
moss index list --json
|
|
175
|
+
moss doc get my-index --json
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Document File Format
|
|
179
|
+
|
|
180
|
+
### JSON (recommended)
|
|
181
|
+
|
|
182
|
+
```json
|
|
183
|
+
[
|
|
184
|
+
{"id": "doc1", "text": "Machine learning fundamentals", "metadata": {"topic": "ml"}},
|
|
185
|
+
{"id": "doc2", "text": "Deep learning with neural networks"},
|
|
186
|
+
{"id": "doc3", "text": "Natural language processing", "metadata": {"topic": "nlp"}}
|
|
187
|
+
]
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Also supports a wrapper format: `{"documents": [...]}`.
|
|
191
|
+
|
|
192
|
+
### CSV
|
|
193
|
+
|
|
194
|
+
```csv
|
|
195
|
+
id,text,metadata
|
|
196
|
+
doc1,Machine learning fundamentals,"{""topic"": ""ml""}"
|
|
197
|
+
doc2,Deep learning with neural networks,
|
|
198
|
+
doc3,Natural language processing,"{""topic"": ""nlp""}"
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### stdin
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
cat docs.json | moss index create my-index -f -
|
|
205
|
+
cat docs.json | moss doc add my-index -f -
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Global Options
|
|
209
|
+
|
|
210
|
+
| Flag | Short | Description |
|
|
211
|
+
|---|---|---|
|
|
212
|
+
| `--project-id` | `-p` | Project ID (overrides env/config) |
|
|
213
|
+
| `--project-key` | | Project key (overrides env/config) |
|
|
214
|
+
| `--json` | | Machine-readable JSON output |
|
|
215
|
+
| `--verbose` | `-v` | Enable debug logging |
|
|
216
|
+
|
|
217
|
+
## Available Models
|
|
218
|
+
|
|
219
|
+
| Model | Description |
|
|
220
|
+
|---|---|
|
|
221
|
+
| `moss-minilm` | Lightweight, optimized for speed (default) |
|
|
222
|
+
| `moss-mediumlm` | Balanced accuracy and performance |
|
|
223
|
+
| `custom` | Used automatically when documents include embeddings |
|
|
224
|
+
|
|
225
|
+
## License
|
|
226
|
+
|
|
227
|
+
Copyright (c) 2026 InferEdge Inc. — PolyForm Shield License 1.0.0.
|
|
228
|
+
|
|
229
|
+
See [LICENSE](LICENSE) for full terms. For commercial licensing, contact contact@usemoss.dev.
|
moss_cli-0.1.0/README.md
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# Moss CLI
|
|
2
|
+
|
|
3
|
+
**Command-line interface for Moss semantic search** — manage indexes, documents, and queries directly from your terminal.
|
|
4
|
+
|
|
5
|
+
Moss CLI wraps the [Moss Python SDK](https://docs.usemoss.dev/) so you can build and query semantic search indexes without writing any code. Ideal for quick prototyping, scripting, CI/CD pipelines, and data workflows.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- ⚡ **Full SDK coverage** — every SDK operation available as a CLI command
|
|
10
|
+
- 🔍 **Semantic search** — query indexes with configurable hybrid search (semantic + keyword)
|
|
11
|
+
- 📦 **Index management** — create, list, inspect, and delete indexes
|
|
12
|
+
- 📄 **Document management** — add, update, retrieve, and delete documents
|
|
13
|
+
- 🚀 **Local by default** — downloads indexes for on-device queries, `--cloud` to skip
|
|
14
|
+
- 🔧 **Flexible auth** — CLI flags, environment variables, or config file
|
|
15
|
+
- 📊 **Multiple output formats** — rich tables for humans, `--json` for scripts
|
|
16
|
+
- ⏳ **Job tracking** — poll background jobs with live progress display
|
|
17
|
+
- 🔗 **Pipe-friendly** — stdin/stdout support for composing with other tools
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pip install moss-cli
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Quick Start
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# 1. Save your credentials
|
|
29
|
+
moss init
|
|
30
|
+
|
|
31
|
+
# 2. List your indexes
|
|
32
|
+
moss index list
|
|
33
|
+
|
|
34
|
+
# 3. Create an index from a JSON file
|
|
35
|
+
moss index create my-index -f docs.json --wait
|
|
36
|
+
|
|
37
|
+
# 4. Search it
|
|
38
|
+
moss query my-index "what is machine learning"
|
|
39
|
+
|
|
40
|
+
# 5. Search via cloud API (skips local download)
|
|
41
|
+
moss query my-index "neural networks" --cloud
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Authentication
|
|
45
|
+
|
|
46
|
+
Credentials are resolved in this order:
|
|
47
|
+
|
|
48
|
+
1. **CLI flags**: `--project-id` and `--project-key`
|
|
49
|
+
2. **Environment variables**: `MOSS_PROJECT_ID` and `MOSS_PROJECT_KEY`
|
|
50
|
+
3. **Config file**: `~/.moss/config.json` (created by `moss init`)
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
# Option 1: Interactive setup (recommended)
|
|
54
|
+
moss init
|
|
55
|
+
|
|
56
|
+
# Option 2: Environment variables
|
|
57
|
+
export MOSS_PROJECT_ID="your-project-id"
|
|
58
|
+
export MOSS_PROJECT_KEY="your-project-key"
|
|
59
|
+
|
|
60
|
+
# Option 3: Inline flags
|
|
61
|
+
moss index list --project-id "..." --project-key "..."
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Commands
|
|
65
|
+
|
|
66
|
+
### Index Management
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
# Create an index with documents from a JSON file
|
|
70
|
+
moss index create my-index -f documents.json --model moss-minilm
|
|
71
|
+
|
|
72
|
+
# Create and wait for completion
|
|
73
|
+
moss index create my-index -f documents.json --wait
|
|
74
|
+
|
|
75
|
+
# List all indexes
|
|
76
|
+
moss index list
|
|
77
|
+
|
|
78
|
+
# Get index details
|
|
79
|
+
moss index get my-index
|
|
80
|
+
|
|
81
|
+
# Delete an index
|
|
82
|
+
moss index delete my-index
|
|
83
|
+
moss index delete my-index --confirm # skip prompt
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Document Management
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
# Add documents to an existing index
|
|
90
|
+
moss doc add my-index -f new-docs.json
|
|
91
|
+
|
|
92
|
+
# Add with upsert (update existing, insert new)
|
|
93
|
+
moss doc add my-index -f docs.json --upsert --wait
|
|
94
|
+
|
|
95
|
+
# Get all documents
|
|
96
|
+
moss doc get my-index
|
|
97
|
+
|
|
98
|
+
# Get specific documents
|
|
99
|
+
moss doc get my-index --ids doc1,doc2,doc3
|
|
100
|
+
|
|
101
|
+
# Delete documents
|
|
102
|
+
moss doc delete my-index --ids doc1,doc2
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Query
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
# Search (downloads index and queries on-device by default)
|
|
109
|
+
moss query my-index "what is deep learning"
|
|
110
|
+
|
|
111
|
+
# Tune results: more results, keyword-heavy
|
|
112
|
+
moss query my-index "neural networks" --top-k 20 --alpha 0.3
|
|
113
|
+
|
|
114
|
+
# Cloud mode (skip download, query via cloud API)
|
|
115
|
+
moss query my-index "transformers" --cloud
|
|
116
|
+
|
|
117
|
+
# With metadata filter (local only)
|
|
118
|
+
moss query my-index "shoes" --filter '{"field": "category", "condition": {"$eq": "footwear"}}'
|
|
119
|
+
|
|
120
|
+
# Pipe query from stdin
|
|
121
|
+
echo "what is AI" | moss query my-index
|
|
122
|
+
|
|
123
|
+
# JSON output for scripting
|
|
124
|
+
moss query my-index "query" --json | jq '.docs[0].text'
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Job Tracking
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
# Check job status
|
|
131
|
+
moss job status <job-id>
|
|
132
|
+
|
|
133
|
+
# Wait for job to finish (with live progress)
|
|
134
|
+
moss job status <job-id> --wait
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Other
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
# Print version info
|
|
141
|
+
moss version
|
|
142
|
+
|
|
143
|
+
# Global JSON output
|
|
144
|
+
moss index list --json
|
|
145
|
+
moss doc get my-index --json
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Document File Format
|
|
149
|
+
|
|
150
|
+
### JSON (recommended)
|
|
151
|
+
|
|
152
|
+
```json
|
|
153
|
+
[
|
|
154
|
+
{"id": "doc1", "text": "Machine learning fundamentals", "metadata": {"topic": "ml"}},
|
|
155
|
+
{"id": "doc2", "text": "Deep learning with neural networks"},
|
|
156
|
+
{"id": "doc3", "text": "Natural language processing", "metadata": {"topic": "nlp"}}
|
|
157
|
+
]
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Also supports a wrapper format: `{"documents": [...]}`.
|
|
161
|
+
|
|
162
|
+
### CSV
|
|
163
|
+
|
|
164
|
+
```csv
|
|
165
|
+
id,text,metadata
|
|
166
|
+
doc1,Machine learning fundamentals,"{""topic"": ""ml""}"
|
|
167
|
+
doc2,Deep learning with neural networks,
|
|
168
|
+
doc3,Natural language processing,"{""topic"": ""nlp""}"
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### stdin
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
cat docs.json | moss index create my-index -f -
|
|
175
|
+
cat docs.json | moss doc add my-index -f -
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Global Options
|
|
179
|
+
|
|
180
|
+
| Flag | Short | Description |
|
|
181
|
+
|---|---|---|
|
|
182
|
+
| `--project-id` | `-p` | Project ID (overrides env/config) |
|
|
183
|
+
| `--project-key` | | Project key (overrides env/config) |
|
|
184
|
+
| `--json` | | Machine-readable JSON output |
|
|
185
|
+
| `--verbose` | `-v` | Enable debug logging |
|
|
186
|
+
|
|
187
|
+
## Available Models
|
|
188
|
+
|
|
189
|
+
| Model | Description |
|
|
190
|
+
|---|---|
|
|
191
|
+
| `moss-minilm` | Lightweight, optimized for speed (default) |
|
|
192
|
+
| `moss-mediumlm` | Balanced accuracy and performance |
|
|
193
|
+
| `custom` | Used automatically when documents include embeddings |
|
|
194
|
+
|
|
195
|
+
## License
|
|
196
|
+
|
|
197
|
+
Copyright (c) 2026 InferEdge Inc. — PolyForm Shield License 1.0.0.
|
|
198
|
+
|
|
199
|
+
See [LICENSE](LICENSE) for full terms. For commercial licensing, contact contact@usemoss.dev.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "moss-cli"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Command-line interface for Moss semantic search"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license-files = ["LICENSE"]
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "InferEdge Inc.", email = "contact@usemoss.dev" }
|
|
14
|
+
]
|
|
15
|
+
keywords = ["search", "semantic", "cli", "moss"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 3 - Alpha",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"Programming Language :: Python :: 3",
|
|
20
|
+
"Programming Language :: Python :: 3.10",
|
|
21
|
+
"Programming Language :: Python :: 3.11",
|
|
22
|
+
"Programming Language :: Python :: 3.12",
|
|
23
|
+
"Programming Language :: Python :: 3.13",
|
|
24
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
25
|
+
]
|
|
26
|
+
dependencies = [
|
|
27
|
+
"moss>=1.0.0",
|
|
28
|
+
"typer>=0.9.0",
|
|
29
|
+
"rich>=13.0.0",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[project.optional-dependencies]
|
|
33
|
+
dev = [
|
|
34
|
+
"pytest>=8.0.0",
|
|
35
|
+
"black>=24.0.0",
|
|
36
|
+
"isort>=5.0.0",
|
|
37
|
+
"flake8>=7.0.0",
|
|
38
|
+
"mypy>=1.0.0",
|
|
39
|
+
"build>=1.0.0",
|
|
40
|
+
"twine>=5.0.0",
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
[project.scripts]
|
|
44
|
+
moss = "moss_cli.main:run"
|
|
45
|
+
|
|
46
|
+
[tool.setuptools.packages.find]
|
|
47
|
+
where = ["src"]
|
|
48
|
+
|
|
49
|
+
[tool.setuptools.package-dir]
|
|
50
|
+
"" = "src"
|
|
51
|
+
|
|
52
|
+
[tool.black]
|
|
53
|
+
line-length = 88
|
|
54
|
+
target-version = ['py310']
|
|
55
|
+
|
|
56
|
+
[tool.isort]
|
|
57
|
+
profile = "black"
|
|
58
|
+
line_length = 88
|
|
59
|
+
|
|
60
|
+
[tool.mypy]
|
|
61
|
+
python_version = "3.10"
|
|
62
|
+
warn_return_any = false
|
|
63
|
+
warn_unused_configs = true
|
|
64
|
+
disallow_untyped_defs = true
|
|
65
|
+
ignore_missing_imports = true
|
moss_cli-0.1.0/setup.cfg
ADDED
|
File without changes
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"""moss doc {add, delete, get} commands."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
from typing import Optional
|
|
7
|
+
|
|
8
|
+
import typer
|
|
9
|
+
from rich.console import Console
|
|
10
|
+
|
|
11
|
+
from moss import MossClient, GetDocumentsOptions, MutationOptions
|
|
12
|
+
|
|
13
|
+
from .. import output
|
|
14
|
+
from ..config import resolve_credentials
|
|
15
|
+
from ..documents import load_documents
|
|
16
|
+
from ..job_waiter import wait_for_job
|
|
17
|
+
|
|
18
|
+
console = Console()
|
|
19
|
+
doc_app = typer.Typer(name="doc", help="Manage documents in an index")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _client(ctx: typer.Context) -> MossClient:
|
|
23
|
+
pid, pkey = resolve_credentials(
|
|
24
|
+
ctx.obj.get("project_id"), ctx.obj.get("project_key")
|
|
25
|
+
)
|
|
26
|
+
return MossClient(pid, pkey)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@doc_app.command(name="add")
|
|
30
|
+
def add(
|
|
31
|
+
ctx: typer.Context,
|
|
32
|
+
index_name: str = typer.Argument(..., help="Index name"),
|
|
33
|
+
file: str = typer.Option(..., "--file", "-f", help="Path to JSON/CSV document file, or '-' for stdin"),
|
|
34
|
+
upsert: bool = typer.Option(False, "--upsert", "-u", help="Update existing documents"),
|
|
35
|
+
wait: bool = typer.Option(False, "--wait", "-w", help="Wait for job to complete"),
|
|
36
|
+
poll_interval: float = typer.Option(2.0, "--poll-interval", help="Seconds between status checks"),
|
|
37
|
+
) -> None:
|
|
38
|
+
"""Add documents to an index."""
|
|
39
|
+
json_mode = ctx.obj.get("json_output", False)
|
|
40
|
+
client = _client(ctx)
|
|
41
|
+
docs = load_documents(file)
|
|
42
|
+
|
|
43
|
+
options = MutationOptions(upsert=True) if upsert else None
|
|
44
|
+
|
|
45
|
+
if not json_mode:
|
|
46
|
+
console.print(
|
|
47
|
+
f"Adding {len(docs)} document(s) to [cyan]{index_name}[/cyan]"
|
|
48
|
+
f"{' (upsert)' if upsert else ''}..."
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
result = asyncio.run(client.add_docs(index_name, docs, options))
|
|
52
|
+
output.print_mutation_result(result, json_mode=json_mode)
|
|
53
|
+
|
|
54
|
+
if wait:
|
|
55
|
+
asyncio.run(wait_for_job(client, result.job_id, poll_interval, json_mode))
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@doc_app.command(name="delete")
|
|
59
|
+
def delete(
|
|
60
|
+
ctx: typer.Context,
|
|
61
|
+
index_name: str = typer.Argument(..., help="Index name"),
|
|
62
|
+
ids: str = typer.Option(..., "--ids", "-i", help="Comma-separated document IDs"),
|
|
63
|
+
wait: bool = typer.Option(False, "--wait", "-w", help="Wait for job to complete"),
|
|
64
|
+
poll_interval: float = typer.Option(2.0, "--poll-interval", help="Seconds between status checks"),
|
|
65
|
+
) -> None:
|
|
66
|
+
"""Delete documents from an index by ID."""
|
|
67
|
+
json_mode = ctx.obj.get("json_output", False)
|
|
68
|
+
client = _client(ctx)
|
|
69
|
+
doc_ids = [i.strip() for i in ids.split(",") if i.strip()]
|
|
70
|
+
|
|
71
|
+
if not doc_ids:
|
|
72
|
+
output.print_error("No document IDs provided.", json_mode=json_mode)
|
|
73
|
+
raise typer.Exit(1)
|
|
74
|
+
|
|
75
|
+
if not json_mode:
|
|
76
|
+
console.print(f"Deleting {len(doc_ids)} document(s) from [cyan]{index_name}[/cyan]...")
|
|
77
|
+
|
|
78
|
+
result = asyncio.run(client.delete_docs(index_name, doc_ids))
|
|
79
|
+
output.print_mutation_result(result, json_mode=json_mode)
|
|
80
|
+
|
|
81
|
+
if wait:
|
|
82
|
+
asyncio.run(wait_for_job(client, result.job_id, poll_interval, json_mode))
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
@doc_app.command(name="get")
|
|
86
|
+
def get(
|
|
87
|
+
ctx: typer.Context,
|
|
88
|
+
index_name: str = typer.Argument(..., help="Index name"),
|
|
89
|
+
ids: Optional[str] = typer.Option(None, "--ids", "-i", help="Comma-separated document IDs (omit for all)"),
|
|
90
|
+
) -> None:
|
|
91
|
+
"""Retrieve documents from an index."""
|
|
92
|
+
json_mode = ctx.obj.get("json_output", False)
|
|
93
|
+
client = _client(ctx)
|
|
94
|
+
|
|
95
|
+
options = None
|
|
96
|
+
if ids:
|
|
97
|
+
doc_ids = [i.strip() for i in ids.split(",") if i.strip()]
|
|
98
|
+
options = GetDocumentsOptions(doc_ids=doc_ids)
|
|
99
|
+
|
|
100
|
+
docs = asyncio.run(client.get_docs(index_name, options))
|
|
101
|
+
output.print_doc_table(docs, json_mode=json_mode)
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""moss index {create, list, get, delete} commands."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
from typing import Optional
|
|
7
|
+
|
|
8
|
+
import typer
|
|
9
|
+
from rich.console import Console
|
|
10
|
+
|
|
11
|
+
from moss import MossClient
|
|
12
|
+
|
|
13
|
+
from .. import output
|
|
14
|
+
from ..config import resolve_credentials
|
|
15
|
+
from ..documents import load_documents
|
|
16
|
+
from ..job_waiter import wait_for_job
|
|
17
|
+
|
|
18
|
+
console = Console()
|
|
19
|
+
index_app = typer.Typer(name="index", help="Manage indexes")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _client(ctx: typer.Context) -> MossClient:
|
|
23
|
+
pid, pkey = resolve_credentials(
|
|
24
|
+
ctx.obj.get("project_id"), ctx.obj.get("project_key")
|
|
25
|
+
)
|
|
26
|
+
return MossClient(pid, pkey)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@index_app.command(name="create")
|
|
30
|
+
def create(
|
|
31
|
+
ctx: typer.Context,
|
|
32
|
+
name: str = typer.Argument(..., help="Index name"),
|
|
33
|
+
file: str = typer.Option(..., "--file", "-f", help="Path to JSON/CSV document file, or '-' for stdin"),
|
|
34
|
+
model: Optional[str] = typer.Option(None, "--model", "-m", help="Model ID (default: moss-minilm)"),
|
|
35
|
+
wait: bool = typer.Option(False, "--wait", "-w", help="Wait for job to complete"),
|
|
36
|
+
poll_interval: float = typer.Option(2.0, "--poll-interval", help="Seconds between status checks"),
|
|
37
|
+
) -> None:
|
|
38
|
+
"""Create a new index with documents."""
|
|
39
|
+
json_mode = ctx.obj.get("json_output", False)
|
|
40
|
+
client = _client(ctx)
|
|
41
|
+
docs = load_documents(file)
|
|
42
|
+
|
|
43
|
+
if not json_mode:
|
|
44
|
+
console.print(f"Creating index [cyan]{name}[/cyan] with {len(docs)} document(s)...")
|
|
45
|
+
|
|
46
|
+
result = asyncio.run(client.create_index(name, docs, model))
|
|
47
|
+
output.print_mutation_result(result, json_mode=json_mode)
|
|
48
|
+
|
|
49
|
+
if wait:
|
|
50
|
+
asyncio.run(wait_for_job(client, result.job_id, poll_interval, json_mode))
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@index_app.command(name="list")
|
|
54
|
+
def list_indexes(ctx: typer.Context) -> None:
|
|
55
|
+
"""List all indexes."""
|
|
56
|
+
json_mode = ctx.obj.get("json_output", False)
|
|
57
|
+
client = _client(ctx)
|
|
58
|
+
indexes = asyncio.run(client.list_indexes())
|
|
59
|
+
output.print_index_table(indexes, json_mode=json_mode)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@index_app.command(name="get")
|
|
63
|
+
def get(
|
|
64
|
+
ctx: typer.Context,
|
|
65
|
+
name: str = typer.Argument(..., help="Index name"),
|
|
66
|
+
) -> None:
|
|
67
|
+
"""Get details of an index."""
|
|
68
|
+
json_mode = ctx.obj.get("json_output", False)
|
|
69
|
+
client = _client(ctx)
|
|
70
|
+
info = asyncio.run(client.get_index(name))
|
|
71
|
+
output.print_index_detail(info, json_mode=json_mode)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@index_app.command(name="delete")
|
|
75
|
+
def delete(
|
|
76
|
+
ctx: typer.Context,
|
|
77
|
+
name: str = typer.Argument(..., help="Index name"),
|
|
78
|
+
confirm: bool = typer.Option(False, "--confirm", "-y", help="Skip confirmation"),
|
|
79
|
+
) -> None:
|
|
80
|
+
"""Delete an index."""
|
|
81
|
+
json_mode = ctx.obj.get("json_output", False)
|
|
82
|
+
if not confirm and not json_mode:
|
|
83
|
+
typer.confirm(f"Delete index '{name}'?", abort=True)
|
|
84
|
+
|
|
85
|
+
client = _client(ctx)
|
|
86
|
+
result = asyncio.run(client.delete_index(name))
|
|
87
|
+
|
|
88
|
+
if result:
|
|
89
|
+
output.print_success(f"Index '{name}' deleted.", json_mode=json_mode)
|
|
90
|
+
else:
|
|
91
|
+
output.print_error(f"Failed to delete index '{name}'.", json_mode=json_mode)
|
|
92
|
+
raise typer.Exit(1)
|