codicent-cli 0.7.1__tar.gz → 0.8.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.
- {codicent_cli-0.7.1 → codicent_cli-0.8.0}/PKG-INFO +122 -1
- {codicent_cli-0.7.1 → codicent_cli-0.8.0}/README.md +120 -0
- {codicent_cli-0.7.1 → codicent_cli-0.8.0}/app.py +167 -18
- {codicent_cli-0.7.1 → codicent_cli-0.8.0}/auth.py +64 -42
- {codicent_cli-0.7.1 → codicent_cli-0.8.0}/codicent_cli.egg-info/PKG-INFO +122 -1
- {codicent_cli-0.7.1 → codicent_cli-0.8.0}/codicent_cli.egg-info/SOURCES.txt +2 -0
- {codicent_cli-0.7.1 → codicent_cli-0.8.0}/codicent_cli.egg-info/requires.txt +1 -0
- {codicent_cli-0.7.1 → codicent_cli-0.8.0}/codicent_cli.egg-info/top_level.txt +1 -0
- {codicent_cli-0.7.1 → codicent_cli-0.8.0}/setup.py +4 -3
- codicent_cli-0.8.0/templates/default.json +47 -0
- codicent_cli-0.8.0/templates/document-processing.json +57 -0
- codicent_cli-0.8.0/templates/koi-studio.json +62 -0
- codicent_cli-0.8.0/wrap.py +425 -0
- codicent_cli-0.7.1/templates/default.json +0 -22
- codicent_cli-0.7.1/templates/koi-studio.json +0 -34
- {codicent_cli-0.7.1 → codicent_cli-0.8.0}/LICENSE +0 -0
- {codicent_cli-0.7.1 → codicent_cli-0.8.0}/codicent_cli.egg-info/dependency_links.txt +0 -0
- {codicent_cli-0.7.1 → codicent_cli-0.8.0}/codicent_cli.egg-info/entry_points.txt +0 -0
- {codicent_cli-0.7.1 → codicent_cli-0.8.0}/setup.cfg +0 -0
- {codicent_cli-0.7.1 → codicent_cli-0.8.0}/templates/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codicent-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.0
|
|
4
4
|
Summary: Command-line interface for the Codicent API
|
|
5
5
|
Home-page: https://github.com/izaxon/codicent-cli
|
|
6
6
|
Author: Johan Isaksson
|
|
@@ -27,6 +27,7 @@ Requires-Dist: rich
|
|
|
27
27
|
Requires-Dist: codicent-py
|
|
28
28
|
Requires-Dist: prompt_toolkit
|
|
29
29
|
Requires-Dist: requests
|
|
30
|
+
Requires-Dist: pyyaml
|
|
30
31
|
Dynamic: author
|
|
31
32
|
Dynamic: author-email
|
|
32
33
|
Dynamic: classifier
|
|
@@ -104,6 +105,28 @@ pip install git+https://github.com/izaxon/codicent-cli.git@v0.4.8
|
|
|
104
105
|
export CODICENT_TOKEN="YOUR_API_TOKEN"
|
|
105
106
|
```
|
|
106
107
|
|
|
108
|
+
Or use the built-in device-flow authentication:
|
|
109
|
+
```bash
|
|
110
|
+
codicent auth # stores token globally in ~/.codicent_token
|
|
111
|
+
codicent auth --local # stores token in .codicent_token in the current directory
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Per-folder Projects
|
|
115
|
+
|
|
116
|
+
You can have a different Codicent project per directory by storing a local token:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
cd ~/work/projectA
|
|
120
|
+
codicent auth --local # authenticates and saves token to ~/work/projectA/.codicent_token
|
|
121
|
+
|
|
122
|
+
cd ~/work/projectB
|
|
123
|
+
codicent auth --local # authenticates and saves token to ~/work/projectB/.codicent_token
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
The CLI always checks the current directory first, then falls back to the global `~/.codicent_token`, and finally to the `CODICENT_TOKEN` environment variable.
|
|
127
|
+
|
|
128
|
+
> **Tip**: Add `.codicent_token` to your `.gitignore` to avoid accidentally committing tokens.
|
|
129
|
+
|
|
107
130
|
### Command Options
|
|
108
131
|
|
|
109
132
|
```
|
|
@@ -211,6 +234,102 @@ The CLI provides helpful error messages for common issues:
|
|
|
211
234
|
- **Input validation**: Prevents empty or overly long inputs
|
|
212
235
|
- **Keyboard interrupts**: Clean exit handling
|
|
213
236
|
|
|
237
|
+
## Project Init
|
|
238
|
+
|
|
239
|
+
Use `codicent init` to instantly set up a new project from a template. Each template posts a ready-to-use set of AI instructions, configuration, automation rules, and sample data.
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
codicent init --list # list templates
|
|
243
|
+
codicent init # use default template
|
|
244
|
+
codicent init --template koi-studio # CRM pipeline
|
|
245
|
+
codicent init --template document-processing # document intake
|
|
246
|
+
codicent init --template koi-studio --dry-run # preview without posting
|
|
247
|
+
codicent init --force # re-init even if already set up
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Available templates
|
|
251
|
+
|
|
252
|
+
| Template | Description |
|
|
253
|
+
|---|---|
|
|
254
|
+
| `default` | General-purpose: task workflow, auto-summarize notes via `#transform` |
|
|
255
|
+
| `koi-studio` | CRM: automatic lead extraction from raw text, follow-up email drafting |
|
|
256
|
+
| `document-processing` | Document intake: extract text, structure key fields with AI, review workflow |
|
|
257
|
+
|
|
258
|
+
### How it works
|
|
259
|
+
|
|
260
|
+
Templates are JSON files in `templates/`. Each defines:
|
|
261
|
+
- **`variables`** — prompted at init time (e.g. company name). Values with defaults are applied silently; values without defaults require manual entry.
|
|
262
|
+
- **`messages`** — posted in order. Each has an optional `label` shown in progress output.
|
|
263
|
+
|
|
264
|
+
Key message types posted by templates:
|
|
265
|
+
- `#instructions` — sets the AI assistant's persona and focus
|
|
266
|
+
- `#appconfig #data` — configures AI model, temperature, and token limit
|
|
267
|
+
- `#process #data` — defines pipeline stages (shown as kanban columns in the UI)
|
|
268
|
+
- `#transform #data` — automation rule: when a message with tag X arrives, run AI and produce a message with tag Y
|
|
269
|
+
- sample `#data` messages — so lists aren't empty on first login
|
|
270
|
+
|
|
271
|
+
### `--dry-run` mode
|
|
272
|
+
|
|
273
|
+
Prints every message that *would* be posted, with its label and a content preview, without any API calls or auth required. Useful for reviewing a template before committing.
|
|
274
|
+
|
|
275
|
+
## Wrap — AI CLI Remote Chat Bridge
|
|
276
|
+
|
|
277
|
+
Use `codicent wrap` to bridge a local AI CLI tool (`claude`, `codex`, `opencode`, etc.) to your codicent project chat. Remote users and the Codicent AI can interact with the locally running tool in real time through the existing codicent web UI.
|
|
278
|
+
|
|
279
|
+
```bash
|
|
280
|
+
codicent wrap claude # wrap Claude Code
|
|
281
|
+
codicent wrap opencode # wrap OpenCode
|
|
282
|
+
codicent wrap --label "Refactor sprint" codex # named session
|
|
283
|
+
codicent wrap --poll-interval 5 claude # slower polling
|
|
284
|
+
codicent wrap --binary /opt/ai/claude claude # explicit binary path
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### How it works
|
|
288
|
+
|
|
289
|
+
1. Starts the specified tool as a local subprocess with full stdin/stdout control.
|
|
290
|
+
2. Opens a **session** tagged `#wrap #wrap_<id>` in your codicent project.
|
|
291
|
+
3. **Output** from the tool is captured and posted to codicent tagged `#wrap #wrap_<id> #output`.
|
|
292
|
+
4. **Input** is received by polling for messages tagged `#wrap #wrap_<id> #input` — any message posted remotely with those tags is forwarded to the tool's stdin.
|
|
293
|
+
|
|
294
|
+
The session ID is printed on startup. To send text to the running tool from the codicent web UI, post a message with `#wrap_<id> #input` in the content.
|
|
295
|
+
|
|
296
|
+
### Startup output
|
|
297
|
+
|
|
298
|
+
```
|
|
299
|
+
🔗 Wrap session starting…
|
|
300
|
+
Session ID: wrap_a3f7c1b2
|
|
301
|
+
Project: myproject
|
|
302
|
+
Tool: claude (/usr/local/bin/claude)
|
|
303
|
+
Remote tag: #wrap_a3f7c1b2
|
|
304
|
+
Post messages tagged #wrap_a3f7c1b2 #input to send text to the tool.
|
|
305
|
+
Press Ctrl+C to stop the session.
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### Configuration (`~/.codicent/wrap-config.yaml`)
|
|
309
|
+
|
|
310
|
+
```yaml
|
|
311
|
+
poll_interval: 2 # seconds between input polls
|
|
312
|
+
output_batch_ms: 500 # ms to batch output before posting
|
|
313
|
+
|
|
314
|
+
tools:
|
|
315
|
+
claude:
|
|
316
|
+
binary: claude # binary name or full path
|
|
317
|
+
codex:
|
|
318
|
+
binary: codex
|
|
319
|
+
opencode:
|
|
320
|
+
binary: opencode
|
|
321
|
+
|
|
322
|
+
auto_responses:
|
|
323
|
+
- pattern: "Do you want to continue"
|
|
324
|
+
reply: "y"
|
|
325
|
+
- pattern: "\\(y/n\\)"
|
|
326
|
+
reply: "y"
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
Auto-response rules are matched against subprocess output using regex. When matched, the configured reply is written to stdin automatically (and posted to codicent for visibility).
|
|
330
|
+
|
|
331
|
+
If no config file exists, defaults are used: tools are resolved by name on `$PATH`, poll interval is 2 seconds.
|
|
332
|
+
|
|
214
333
|
## Development
|
|
215
334
|
|
|
216
335
|
### Running Tests
|
|
@@ -222,6 +341,7 @@ python -m pytest test_app.py -v
|
|
|
222
341
|
### Project Structure
|
|
223
342
|
|
|
224
343
|
- `app.py` - Main application logic (single-file architecture)
|
|
344
|
+
- `wrap.py` - Wrap command: AI CLI remote chat bridge
|
|
225
345
|
- `test_app.py` - Comprehensive test suite
|
|
226
346
|
- `setup.py` - Package configuration
|
|
227
347
|
- `requirements.txt` - Dependencies (now uses PyPI packages)
|
|
@@ -230,6 +350,7 @@ python -m pytest test_app.py -v
|
|
|
230
350
|
|
|
231
351
|
- **codicent-py**: Core API client for Codicent services (now available on PyPI)
|
|
232
352
|
- **rich**: Terminal formatting, markdown rendering, and animations
|
|
353
|
+
- **pyyaml**: YAML config file parsing for the wrap command
|
|
233
354
|
|
|
234
355
|
## Troubleshooting
|
|
235
356
|
|
|
@@ -62,6 +62,28 @@ pip install git+https://github.com/izaxon/codicent-cli.git@v0.4.8
|
|
|
62
62
|
export CODICENT_TOKEN="YOUR_API_TOKEN"
|
|
63
63
|
```
|
|
64
64
|
|
|
65
|
+
Or use the built-in device-flow authentication:
|
|
66
|
+
```bash
|
|
67
|
+
codicent auth # stores token globally in ~/.codicent_token
|
|
68
|
+
codicent auth --local # stores token in .codicent_token in the current directory
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Per-folder Projects
|
|
72
|
+
|
|
73
|
+
You can have a different Codicent project per directory by storing a local token:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
cd ~/work/projectA
|
|
77
|
+
codicent auth --local # authenticates and saves token to ~/work/projectA/.codicent_token
|
|
78
|
+
|
|
79
|
+
cd ~/work/projectB
|
|
80
|
+
codicent auth --local # authenticates and saves token to ~/work/projectB/.codicent_token
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
The CLI always checks the current directory first, then falls back to the global `~/.codicent_token`, and finally to the `CODICENT_TOKEN` environment variable.
|
|
84
|
+
|
|
85
|
+
> **Tip**: Add `.codicent_token` to your `.gitignore` to avoid accidentally committing tokens.
|
|
86
|
+
|
|
65
87
|
### Command Options
|
|
66
88
|
|
|
67
89
|
```
|
|
@@ -169,6 +191,102 @@ The CLI provides helpful error messages for common issues:
|
|
|
169
191
|
- **Input validation**: Prevents empty or overly long inputs
|
|
170
192
|
- **Keyboard interrupts**: Clean exit handling
|
|
171
193
|
|
|
194
|
+
## Project Init
|
|
195
|
+
|
|
196
|
+
Use `codicent init` to instantly set up a new project from a template. Each template posts a ready-to-use set of AI instructions, configuration, automation rules, and sample data.
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
codicent init --list # list templates
|
|
200
|
+
codicent init # use default template
|
|
201
|
+
codicent init --template koi-studio # CRM pipeline
|
|
202
|
+
codicent init --template document-processing # document intake
|
|
203
|
+
codicent init --template koi-studio --dry-run # preview without posting
|
|
204
|
+
codicent init --force # re-init even if already set up
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Available templates
|
|
208
|
+
|
|
209
|
+
| Template | Description |
|
|
210
|
+
|---|---|
|
|
211
|
+
| `default` | General-purpose: task workflow, auto-summarize notes via `#transform` |
|
|
212
|
+
| `koi-studio` | CRM: automatic lead extraction from raw text, follow-up email drafting |
|
|
213
|
+
| `document-processing` | Document intake: extract text, structure key fields with AI, review workflow |
|
|
214
|
+
|
|
215
|
+
### How it works
|
|
216
|
+
|
|
217
|
+
Templates are JSON files in `templates/`. Each defines:
|
|
218
|
+
- **`variables`** — prompted at init time (e.g. company name). Values with defaults are applied silently; values without defaults require manual entry.
|
|
219
|
+
- **`messages`** — posted in order. Each has an optional `label` shown in progress output.
|
|
220
|
+
|
|
221
|
+
Key message types posted by templates:
|
|
222
|
+
- `#instructions` — sets the AI assistant's persona and focus
|
|
223
|
+
- `#appconfig #data` — configures AI model, temperature, and token limit
|
|
224
|
+
- `#process #data` — defines pipeline stages (shown as kanban columns in the UI)
|
|
225
|
+
- `#transform #data` — automation rule: when a message with tag X arrives, run AI and produce a message with tag Y
|
|
226
|
+
- sample `#data` messages — so lists aren't empty on first login
|
|
227
|
+
|
|
228
|
+
### `--dry-run` mode
|
|
229
|
+
|
|
230
|
+
Prints every message that *would* be posted, with its label and a content preview, without any API calls or auth required. Useful for reviewing a template before committing.
|
|
231
|
+
|
|
232
|
+
## Wrap — AI CLI Remote Chat Bridge
|
|
233
|
+
|
|
234
|
+
Use `codicent wrap` to bridge a local AI CLI tool (`claude`, `codex`, `opencode`, etc.) to your codicent project chat. Remote users and the Codicent AI can interact with the locally running tool in real time through the existing codicent web UI.
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
codicent wrap claude # wrap Claude Code
|
|
238
|
+
codicent wrap opencode # wrap OpenCode
|
|
239
|
+
codicent wrap --label "Refactor sprint" codex # named session
|
|
240
|
+
codicent wrap --poll-interval 5 claude # slower polling
|
|
241
|
+
codicent wrap --binary /opt/ai/claude claude # explicit binary path
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### How it works
|
|
245
|
+
|
|
246
|
+
1. Starts the specified tool as a local subprocess with full stdin/stdout control.
|
|
247
|
+
2. Opens a **session** tagged `#wrap #wrap_<id>` in your codicent project.
|
|
248
|
+
3. **Output** from the tool is captured and posted to codicent tagged `#wrap #wrap_<id> #output`.
|
|
249
|
+
4. **Input** is received by polling for messages tagged `#wrap #wrap_<id> #input` — any message posted remotely with those tags is forwarded to the tool's stdin.
|
|
250
|
+
|
|
251
|
+
The session ID is printed on startup. To send text to the running tool from the codicent web UI, post a message with `#wrap_<id> #input` in the content.
|
|
252
|
+
|
|
253
|
+
### Startup output
|
|
254
|
+
|
|
255
|
+
```
|
|
256
|
+
🔗 Wrap session starting…
|
|
257
|
+
Session ID: wrap_a3f7c1b2
|
|
258
|
+
Project: myproject
|
|
259
|
+
Tool: claude (/usr/local/bin/claude)
|
|
260
|
+
Remote tag: #wrap_a3f7c1b2
|
|
261
|
+
Post messages tagged #wrap_a3f7c1b2 #input to send text to the tool.
|
|
262
|
+
Press Ctrl+C to stop the session.
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### Configuration (`~/.codicent/wrap-config.yaml`)
|
|
266
|
+
|
|
267
|
+
```yaml
|
|
268
|
+
poll_interval: 2 # seconds between input polls
|
|
269
|
+
output_batch_ms: 500 # ms to batch output before posting
|
|
270
|
+
|
|
271
|
+
tools:
|
|
272
|
+
claude:
|
|
273
|
+
binary: claude # binary name or full path
|
|
274
|
+
codex:
|
|
275
|
+
binary: codex
|
|
276
|
+
opencode:
|
|
277
|
+
binary: opencode
|
|
278
|
+
|
|
279
|
+
auto_responses:
|
|
280
|
+
- pattern: "Do you want to continue"
|
|
281
|
+
reply: "y"
|
|
282
|
+
- pattern: "\\(y/n\\)"
|
|
283
|
+
reply: "y"
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
Auto-response rules are matched against subprocess output using regex. When matched, the configured reply is written to stdin automatically (and posted to codicent for visibility).
|
|
287
|
+
|
|
288
|
+
If no config file exists, defaults are used: tools are resolved by name on `$PATH`, poll interval is 2 seconds.
|
|
289
|
+
|
|
172
290
|
## Development
|
|
173
291
|
|
|
174
292
|
### Running Tests
|
|
@@ -180,6 +298,7 @@ python -m pytest test_app.py -v
|
|
|
180
298
|
### Project Structure
|
|
181
299
|
|
|
182
300
|
- `app.py` - Main application logic (single-file architecture)
|
|
301
|
+
- `wrap.py` - Wrap command: AI CLI remote chat bridge
|
|
183
302
|
- `test_app.py` - Comprehensive test suite
|
|
184
303
|
- `setup.py` - Package configuration
|
|
185
304
|
- `requirements.txt` - Dependencies (now uses PyPI packages)
|
|
@@ -188,6 +307,7 @@ python -m pytest test_app.py -v
|
|
|
188
307
|
|
|
189
308
|
- **codicent-py**: Core API client for Codicent services (now available on PyPI)
|
|
190
309
|
- **rich**: Terminal formatting, markdown rendering, and animations
|
|
310
|
+
- **pyyaml**: YAML config file parsing for the wrap command
|
|
191
311
|
|
|
192
312
|
## Troubleshooting
|
|
193
313
|
|
|
@@ -40,8 +40,10 @@ OPTIONS:
|
|
|
40
40
|
|
|
41
41
|
AUTHENTICATION:
|
|
42
42
|
auth Authenticate using device flow (project selected during web auth)
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
auth --local Authenticate and store token in the current directory (.codicent_token)
|
|
44
|
+
logout Clear stored global authentication
|
|
45
|
+
logout --local Clear only the local (.codicent_token) token in the current directory
|
|
46
|
+
status Check authentication status (shows whether local or global token is used)
|
|
45
47
|
|
|
46
48
|
FILE UPLOAD:
|
|
47
49
|
upload Upload files and post messages with tags
|
|
@@ -55,13 +57,54 @@ FILE UPLOAD:
|
|
|
55
57
|
PROJECT INIT:
|
|
56
58
|
init Initialize current project with a template
|
|
57
59
|
|
|
58
|
-
--list List available templates
|
|
60
|
+
--list List available templates with descriptions
|
|
59
61
|
--template NAME Use a specific template (default: 'default')
|
|
62
|
+
--dry-run Preview messages without posting (no auth needed)
|
|
63
|
+
--force Re-initialize even if project already has #instructions
|
|
64
|
+
|
|
65
|
+
Templates:
|
|
66
|
+
default General-purpose: task workflow + auto-summarize notes
|
|
67
|
+
koi-studio CRM: lead extraction + follow-up email drafting pipeline
|
|
68
|
+
document-processing Document intake: extract, structure, and review documents
|
|
60
69
|
|
|
61
70
|
Examples:
|
|
62
71
|
codicent init
|
|
63
72
|
codicent init --template koi-studio
|
|
73
|
+
codicent init --template document-processing --dry-run
|
|
64
74
|
codicent init --list
|
|
75
|
+
codicent init --force
|
|
76
|
+
|
|
77
|
+
WRAP (AI CLI Remote Bridge):
|
|
78
|
+
wrap Bridge a local AI CLI tool to a remote codicent chat session.
|
|
79
|
+
Remote users and AI can interact with the locally running tool.
|
|
80
|
+
|
|
81
|
+
<tool> Tool to wrap: claude, codex, opencode, or any CLI tool
|
|
82
|
+
[tool-args...] Arguments passed through to the wrapped tool
|
|
83
|
+
--label TEXT Session label shown in codicent UI (default: "<tool> session")
|
|
84
|
+
--binary PATH Explicit path to the tool binary
|
|
85
|
+
--poll-interval N Seconds between input polls (default: 2)
|
|
86
|
+
|
|
87
|
+
How it works:
|
|
88
|
+
1. Starts the tool as a local subprocess
|
|
89
|
+
2. Posts tool output to codicent tagged #wrap #wrap_<id> #output
|
|
90
|
+
3. Polls for messages tagged #wrap #wrap_<id> #input and writes them to stdin
|
|
91
|
+
4. Remote users tag messages with #wrap_<id> #input to send text to the tool
|
|
92
|
+
|
|
93
|
+
Config file (~/.codicent/wrap-config.yaml):
|
|
94
|
+
poll_interval: 2
|
|
95
|
+
output_batch_ms: 500
|
|
96
|
+
tools:
|
|
97
|
+
claude:
|
|
98
|
+
binary: claude
|
|
99
|
+
auto_responses:
|
|
100
|
+
- pattern: "Do you want to continue"
|
|
101
|
+
reply: "y"
|
|
102
|
+
|
|
103
|
+
Examples:
|
|
104
|
+
codicent wrap claude
|
|
105
|
+
codicent wrap --label "Refactor session" opencode
|
|
106
|
+
codicent wrap --poll-interval 5 codex
|
|
107
|
+
codicent wrap --binary /usr/local/bin/claude claude --model claude-opus-4-5
|
|
65
108
|
|
|
66
109
|
EXAMPLES:
|
|
67
110
|
codicent auth
|
|
@@ -70,6 +113,7 @@ EXAMPLES:
|
|
|
70
113
|
codicent "@mention Hello there"
|
|
71
114
|
codicent upload document.txt *.log
|
|
72
115
|
codicent init --template koi-studio
|
|
116
|
+
codicent wrap claude
|
|
73
117
|
echo "Help me debug this" | codicent
|
|
74
118
|
|
|
75
119
|
ENVIRONMENT:
|
|
@@ -81,7 +125,7 @@ For more information, visit: https://github.com/izaxon/codicent-cli
|
|
|
81
125
|
|
|
82
126
|
def show_version():
|
|
83
127
|
"""Display version information."""
|
|
84
|
-
print("Codicent CLI v0.
|
|
128
|
+
print("Codicent CLI v0.8.0")
|
|
85
129
|
|
|
86
130
|
def validate_input(question):
|
|
87
131
|
"""Validate user input."""
|
|
@@ -115,6 +159,11 @@ def main():
|
|
|
115
159
|
logging.getLogger().setLevel(logging.ERROR)
|
|
116
160
|
sys.argv.remove("--quiet")
|
|
117
161
|
|
|
162
|
+
# Parse --local flag (store/remove token in current working directory)
|
|
163
|
+
use_local = "--local" in sys.argv
|
|
164
|
+
if use_local:
|
|
165
|
+
sys.argv.remove("--local")
|
|
166
|
+
|
|
118
167
|
# Initialize auth handler
|
|
119
168
|
auth = CodicentAuth()
|
|
120
169
|
|
|
@@ -123,8 +172,7 @@ def main():
|
|
|
123
172
|
command = sys.argv[1]
|
|
124
173
|
|
|
125
174
|
if command == "auth":
|
|
126
|
-
|
|
127
|
-
token = auth.get_token(force_reauth=True)
|
|
175
|
+
token = auth.get_token(force_reauth=True, local=use_local)
|
|
128
176
|
if token:
|
|
129
177
|
console.print("[green]✅ Authentication successful![/green]")
|
|
130
178
|
return 0
|
|
@@ -133,13 +181,13 @@ def main():
|
|
|
133
181
|
return 1
|
|
134
182
|
|
|
135
183
|
elif command == "logout":
|
|
136
|
-
auth.logout()
|
|
184
|
+
auth.logout(local=use_local)
|
|
137
185
|
return 0
|
|
138
186
|
|
|
139
187
|
elif command == "status":
|
|
140
|
-
|
|
141
|
-
if
|
|
142
|
-
console.print("[green]✅ Authenticated (
|
|
188
|
+
source = auth.get_token_source()
|
|
189
|
+
if source:
|
|
190
|
+
console.print(f"[green]✅ Authenticated[/green] [dim]({source})[/dim]")
|
|
143
191
|
return 0
|
|
144
192
|
else:
|
|
145
193
|
env_token = os.getenv("CODICENT_TOKEN")
|
|
@@ -270,6 +318,9 @@ def main():
|
|
|
270
318
|
if len(sys.argv) > 1 and sys.argv[1] == "init":
|
|
271
319
|
templates_dir = os.path.join(os.path.dirname(__file__), "templates")
|
|
272
320
|
|
|
321
|
+
dry_run = "--dry-run" in sys.argv
|
|
322
|
+
force = "--force" in sys.argv
|
|
323
|
+
|
|
273
324
|
# --list: show available templates
|
|
274
325
|
if "--list" in sys.argv:
|
|
275
326
|
try:
|
|
@@ -279,7 +330,10 @@ def main():
|
|
|
279
330
|
template_path = os.path.join(templates_dir, f"{name}.json")
|
|
280
331
|
with open(template_path, encoding="utf-8") as fh:
|
|
281
332
|
meta = json.load(fh)
|
|
282
|
-
|
|
333
|
+
vars_info = ""
|
|
334
|
+
if meta.get("variables"):
|
|
335
|
+
vars_info = f" [dim]({len(meta['variables'])} variable(s))[/dim]"
|
|
336
|
+
console.print(f" [bold bright_cyan]{name}[/bold bright_cyan]{vars_info} — {meta.get('description', '')}")
|
|
283
337
|
except Exception as e:
|
|
284
338
|
console.print(f"[red]❌ Error listing templates: {e}[/red]")
|
|
285
339
|
return 0
|
|
@@ -299,6 +353,51 @@ def main():
|
|
|
299
353
|
console.print(f"[red]❌ Template '{template_name}' not found. Use 'codicent init --list' to see options.[/red]")
|
|
300
354
|
return 1
|
|
301
355
|
|
|
356
|
+
with open(template_path, encoding="utf-8") as fh:
|
|
357
|
+
template = json.load(fh)
|
|
358
|
+
|
|
359
|
+
# Resolve variables: prompt for any without defaults
|
|
360
|
+
variable_values = {}
|
|
361
|
+
template_variables = template.get("variables", {})
|
|
362
|
+
for var_name, var_meta in template_variables.items():
|
|
363
|
+
default = var_meta.get("default", "")
|
|
364
|
+
description = var_meta.get("description", var_name)
|
|
365
|
+
if dry_run:
|
|
366
|
+
# In dry-run, use defaults without prompting
|
|
367
|
+
variable_values[var_name] = default or f"{{{var_name}}}"
|
|
368
|
+
elif default:
|
|
369
|
+
variable_values[var_name] = default
|
|
370
|
+
console.print(f"[dim] {var_name}: {default} (default)[/dim]")
|
|
371
|
+
else:
|
|
372
|
+
value = input(f" {description}: ").strip()
|
|
373
|
+
if not value:
|
|
374
|
+
console.print(f"[red]❌ Variable '{var_name}' is required.[/red]")
|
|
375
|
+
return 1
|
|
376
|
+
variable_values[var_name] = value
|
|
377
|
+
|
|
378
|
+
def apply_variables(text, project):
|
|
379
|
+
result = text.replace("{project}", project)
|
|
380
|
+
for var_name, var_value in variable_values.items():
|
|
381
|
+
result = result.replace("{" + var_name + "}", var_value)
|
|
382
|
+
return result
|
|
383
|
+
|
|
384
|
+
# --- Dry-run mode: print plan without calling API ---
|
|
385
|
+
if dry_run:
|
|
386
|
+
messages = template.get("messages", [])
|
|
387
|
+
console.print(f"\n[bold]Dry run — template [bright_cyan]{template_name}[/bright_cyan] ({len(messages)} messages)[/bold]")
|
|
388
|
+
console.print(f"[dim]No messages will be posted. Remove --dry-run to execute.[/dim]\n")
|
|
389
|
+
for i, entry in enumerate(messages, 1):
|
|
390
|
+
label = entry.get("label", f"Message {i}")
|
|
391
|
+
content = apply_variables(entry["content"], "{project}")
|
|
392
|
+
# Show first 120 chars of content
|
|
393
|
+
preview = content.replace("\n", " ↵ ")
|
|
394
|
+
if len(preview) > 120:
|
|
395
|
+
preview = preview[:117] + "..."
|
|
396
|
+
console.print(f" [bold]{i}.[/bold] [bright_cyan]{label}[/bright_cyan]")
|
|
397
|
+
console.print(f" [dim]{preview}[/dim]")
|
|
398
|
+
console.print()
|
|
399
|
+
return 0
|
|
400
|
+
|
|
302
401
|
# Get authentication token
|
|
303
402
|
token = auth.get_cached_token()
|
|
304
403
|
if not token:
|
|
@@ -325,23 +424,41 @@ def main():
|
|
|
325
424
|
console.print(f"[red]❌ Failed to initialize Codicent API client: {e}[/red]")
|
|
326
425
|
return 1
|
|
327
426
|
|
|
328
|
-
|
|
329
|
-
|
|
427
|
+
# Idempotency check: warn if #instructions already exists in this project
|
|
428
|
+
if not force:
|
|
429
|
+
try:
|
|
430
|
+
headers = {"Authorization": f"Bearer {token}"}
|
|
431
|
+
check_url = f"{codicent.base_url}api/GetMessages"
|
|
432
|
+
resp = requests.get(
|
|
433
|
+
check_url,
|
|
434
|
+
params={"mention": project, "tags": "instructions", "length": "1"},
|
|
435
|
+
headers=headers,
|
|
436
|
+
verify=codicent.verify_https,
|
|
437
|
+
timeout=10,
|
|
438
|
+
)
|
|
439
|
+
if resp.ok and resp.json():
|
|
440
|
+
console.print(f"[yellow]⚠ Project [bold]{project}[/bold] already has #instructions — it may have been initialized before.[/yellow]")
|
|
441
|
+
console.print("[dim]Pass --force to initialize anyway, or --dry-run to preview what would be posted.[/dim]")
|
|
442
|
+
return 1
|
|
443
|
+
except Exception:
|
|
444
|
+
logger.debug("Idempotency check failed (skipping)")
|
|
330
445
|
|
|
331
446
|
messages = template.get("messages", [])
|
|
332
447
|
console.print(f"Initializing [bold]{project}[/bold] with template [bold bright_cyan]{template_name}[/bold bright_cyan] ({len(messages)} messages)...")
|
|
333
448
|
|
|
334
449
|
posted = 0
|
|
335
450
|
failed = 0
|
|
336
|
-
for entry in messages:
|
|
337
|
-
|
|
451
|
+
for i, entry in enumerate(messages, 1):
|
|
452
|
+
label = entry.get("label", f"Message {i}")
|
|
453
|
+
content = apply_variables(entry["content"], project)
|
|
338
454
|
msg_type = entry.get("type", "info")
|
|
339
455
|
try:
|
|
340
|
-
with console.status(f"[dim]
|
|
456
|
+
with console.status(f"[dim]({i}/{len(messages)}) {label}...[/dim]", spinner="dots"):
|
|
341
457
|
codicent.post_message(content, type=msg_type)
|
|
458
|
+
console.print(f" [green]✓[/green] [dim]{label}[/dim]")
|
|
342
459
|
posted += 1
|
|
343
460
|
except Exception as e:
|
|
344
|
-
console.print(f"[red]
|
|
461
|
+
console.print(f" [red]✗ {label}: {e}[/red]")
|
|
345
462
|
failed += 1
|
|
346
463
|
|
|
347
464
|
console.print()
|
|
@@ -350,6 +467,38 @@ def main():
|
|
|
350
467
|
console.print(f"[red]❌ {failed} message(s) failed.[/red]")
|
|
351
468
|
return 0 if failed == 0 else 1
|
|
352
469
|
|
|
470
|
+
# Handle wrap command
|
|
471
|
+
if len(sys.argv) > 1 and sys.argv[1] == "wrap":
|
|
472
|
+
from wrap import run_wrap_command
|
|
473
|
+
|
|
474
|
+
wrap_token = auth.get_cached_token()
|
|
475
|
+
if not wrap_token:
|
|
476
|
+
wrap_token = os.getenv("CODICENT_TOKEN")
|
|
477
|
+
if not wrap_token:
|
|
478
|
+
console.print("[red]❌ No authentication found.[/red]")
|
|
479
|
+
console.print("[dim]Run 'codicent auth' to authenticate, or set CODICENT_TOKEN environment variable[/dim]")
|
|
480
|
+
return 1
|
|
481
|
+
|
|
482
|
+
# Extract project and base_url from JWT token
|
|
483
|
+
try:
|
|
484
|
+
wrap_payload = wrap_token.split(".")[1]
|
|
485
|
+
wrap_payload += '=' * (-len(wrap_payload) % 4)
|
|
486
|
+
wrap_jwt = json.loads(base64.urlsafe_b64decode(wrap_payload).decode('utf-8'))
|
|
487
|
+
wrap_project = wrap_jwt["project"]
|
|
488
|
+
wrap_base_url = wrap_jwt.get("baseUrl", "https://codicent.com/")
|
|
489
|
+
except Exception as e:
|
|
490
|
+
console.print(f"[red]❌ Failed to extract project from token: {e}[/red]")
|
|
491
|
+
return 1
|
|
492
|
+
|
|
493
|
+
# Pass everything after "wrap" as args
|
|
494
|
+
wrap_args = sys.argv[2:]
|
|
495
|
+
return run_wrap_command(
|
|
496
|
+
args=wrap_args,
|
|
497
|
+
token=wrap_token,
|
|
498
|
+
base_url=wrap_base_url,
|
|
499
|
+
project=wrap_project,
|
|
500
|
+
)
|
|
501
|
+
|
|
353
502
|
# Get authentication token
|
|
354
503
|
token = auth.get_cached_token()
|
|
355
504
|
if not token:
|
|
@@ -578,7 +727,7 @@ def main():
|
|
|
578
727
|
|
|
579
728
|
header = Text()
|
|
580
729
|
header.append("Codicent CLI", style="bold bright_cyan")
|
|
581
|
-
header.append(" v0.
|
|
730
|
+
header.append(" v0.8.0\n", style="bright_cyan")
|
|
582
731
|
header.append("Type your questions or use Ctrl+C to exit.\n", style="dim")
|
|
583
732
|
header.append("\n")
|
|
584
733
|
header.append("Tip: ", style="bold dim")
|