pico-cli 0.1.0__tar.gz → 0.1.2__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.
Files changed (109) hide show
  1. {pico_cli-0.1.0 → pico_cli-0.1.2}/PKG-INFO +50 -17
  2. {pico_cli-0.1.0 → pico_cli-0.1.2}/README.md +48 -15
  3. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_ai/README.md +1 -1
  4. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_ai/pyproject.toml +2 -2
  5. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_core/README.md +1 -1
  6. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_core/pyproject.toml +4 -4
  7. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_sdk/README.md +1 -1
  8. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_sdk/pyproject.toml +5 -5
  9. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_sdk/src/pico_sdk/cli.py +2 -2
  10. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_tui/README.md +2 -2
  11. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_tui/pyproject.toml +3 -3
  12. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_tui/src/pico_tui/app.py +17 -3
  13. {pico_cli-0.1.0 → pico_cli-0.1.2}/pyproject.toml +5 -5
  14. {pico_cli-0.1.0 → pico_cli-0.1.2}/src/pico/__init__.py +1 -1
  15. pico_cli-0.1.2/tests/test_first_run_setup.py +70 -0
  16. {pico_cli-0.1.0 → pico_cli-0.1.2}/uv.lock +34 -34
  17. pico_cli-0.1.0/IMPLEMENTATION_SUMMARY.md +0 -80
  18. {pico_cli-0.1.0 → pico_cli-0.1.2}/.gitignore +0 -0
  19. {pico_cli-0.1.0 → pico_cli-0.1.2}/.scratch/headless-agent/issues/01-unified-ai-call.md +0 -0
  20. {pico_cli-0.1.0 → pico_cli-0.1.2}/.scratch/headless-agent/issues/02-tracer-bullet-headless-text-response.md +0 -0
  21. {pico_cli-0.1.0 → pico_cli-0.1.2}/.scratch/headless-agent/issues/03-tools.md +0 -0
  22. {pico_cli-0.1.0 → pico_cli-0.1.2}/.scratch/headless-agent/issues/04-session-fork.md +0 -0
  23. {pico_cli-0.1.0 → pico_cli-0.1.2}/.scratch/headless-agent/issues/05-compaction.md +0 -0
  24. {pico_cli-0.1.0 → pico_cli-0.1.2}/.scratch/headless-agent/issues/06-extension-binding.md +0 -0
  25. {pico_cli-0.1.0 → pico_cli-0.1.2}/.scratch/headless-agent/issues/07-config-file.md +0 -0
  26. {pico_cli-0.1.0 → pico_cli-0.1.2}/.scratch/headless-agent/spec.md +0 -0
  27. {pico_cli-0.1.0 → pico_cli-0.1.2}/.scratch/pico-tui/spec.md +0 -0
  28. {pico_cli-0.1.0 → pico_cli-0.1.2}/.scratch/trace-view/01-assistant-duration.md +0 -0
  29. {pico_cli-0.1.0 → pico_cli-0.1.2}/.scratch/trace-view/02-row-assembly.md +0 -0
  30. {pico_cli-0.1.0 → pico_cli-0.1.2}/.scratch/trace-view/03-overlay.md +0 -0
  31. {pico_cli-0.1.0 → pico_cli-0.1.2}/AGENTS.md +0 -0
  32. {pico_cli-0.1.0 → pico_cli-0.1.2}/CONTEXT.md +0 -0
  33. {pico_cli-0.1.0 → pico_cli-0.1.2}/LICENSE +0 -0
  34. {pico_cli-0.1.0 → pico_cli-0.1.2}/docs/adr/0001-monorepo-package-split.md +0 -0
  35. {pico_cli-0.1.0 → pico_cli-0.1.2}/docs/adr/0002-tree-based-session.md +0 -0
  36. {pico_cli-0.1.0 → pico_cli-0.1.2}/docs/adr/0003-hardcoded-core.md +0 -0
  37. {pico_cli-0.1.0 → pico_cli-0.1.2}/docs/adr/0004-native-provider-adapters.md +0 -0
  38. {pico_cli-0.1.0 → pico_cli-0.1.2}/docs/adr/0005-task-tool-subagents.md +0 -0
  39. {pico_cli-0.1.0 → pico_cli-0.1.2}/docs/adr/0006-trace-view-durations.md +0 -0
  40. {pico_cli-0.1.0 → pico_cli-0.1.2}/docs/agents/domain.md +0 -0
  41. {pico_cli-0.1.0 → pico_cli-0.1.2}/docs/agents/issue-tracker.md +0 -0
  42. {pico_cli-0.1.0 → pico_cli-0.1.2}/docs/agents/triage-labels.md +0 -0
  43. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_ai/src/pico_ai/__init__.py +0 -0
  44. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_ai/src/pico_ai/openrouter.py +0 -0
  45. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_ai/src/pico_ai/provider.py +0 -0
  46. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_ai/src/pico_ai/providers/__init__.py +0 -0
  47. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_ai/src/pico_ai/providers/_compat.py +0 -0
  48. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_ai/src/pico_ai/providers/anthropic.py +0 -0
  49. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_ai/src/pico_ai/providers/deepseek.py +0 -0
  50. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_ai/src/pico_ai/providers/gemini.py +0 -0
  51. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_ai/src/pico_ai/providers/ollama.py +0 -0
  52. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_ai/src/pico_ai/providers/openai.py +0 -0
  53. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_ai/src/pico_ai/providers/spec.py +0 -0
  54. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_ai/src/pico_ai/py.typed +0 -0
  55. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_ai/src/pico_ai/types.py +0 -0
  56. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_core/src/pico_core/__init__.py +0 -0
  57. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_core/src/pico_core/fsm.py +0 -0
  58. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_core/src/pico_core/py.typed +0 -0
  59. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_core/src/pico_core/session.py +0 -0
  60. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_core/src/pico_core/subagents.py +0 -0
  61. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_core/src/pico_core/todos.py +0 -0
  62. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_core/src/pico_core/tools.py +0 -0
  63. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_core/src/pico_core/trace.py +0 -0
  64. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_sdk/src/pico_sdk/__init__.py +0 -0
  65. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_sdk/src/pico_sdk/__main__.py +0 -0
  66. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_sdk/src/pico_sdk/config.py +0 -0
  67. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_sdk/src/pico_sdk/extensions.py +0 -0
  68. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_sdk/src/pico_sdk/providers.py +0 -0
  69. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_sdk/src/pico_sdk/py.typed +0 -0
  70. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_sdk/src/pico_sdk/session.py +0 -0
  71. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_sdk/src/pico_sdk/skills.py +0 -0
  72. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_tui/src/pico_tui/__init__.py +0 -0
  73. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_tui/src/pico_tui/commands.py +0 -0
  74. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_tui/src/pico_tui/history_picker.py +0 -0
  75. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_tui/src/pico_tui/modal.py +0 -0
  76. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_tui/src/pico_tui/model_picker.py +0 -0
  77. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_tui/src/pico_tui/provider_form.py +0 -0
  78. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_tui/src/pico_tui/provider_picker.py +0 -0
  79. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_tui/src/pico_tui/py.typed +0 -0
  80. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_tui/src/pico_tui/render.py +0 -0
  81. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_tui/src/pico_tui/skill_picker.py +0 -0
  82. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_tui/src/pico_tui/status_bar.py +0 -0
  83. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_tui/src/pico_tui/todo_panel.py +0 -0
  84. {pico_cli-0.1.0 → pico_cli-0.1.2}/packages/pico_tui/src/pico_tui/trace_view.py +0 -0
  85. {pico_cli-0.1.0 → pico_cli-0.1.2}/tests/conftest.py +0 -0
  86. {pico_cli-0.1.0 → pico_cli-0.1.2}/tests/test_agent_session.py +0 -0
  87. {pico_cli-0.1.0 → pico_cli-0.1.2}/tests/test_ai_call.py +0 -0
  88. {pico_cli-0.1.0 → pico_cli-0.1.2}/tests/test_cli.py +0 -0
  89. {pico_cli-0.1.0 → pico_cli-0.1.2}/tests/test_config.py +0 -0
  90. {pico_cli-0.1.0 → pico_cli-0.1.2}/tests/test_extensions.py +0 -0
  91. {pico_cli-0.1.0 → pico_cli-0.1.2}/tests/test_first_token_timeout.py +0 -0
  92. {pico_cli-0.1.0 → pico_cli-0.1.2}/tests/test_fsm.py +0 -0
  93. {pico_cli-0.1.0 → pico_cli-0.1.2}/tests/test_history_picker.py +0 -0
  94. {pico_cli-0.1.0 → pico_cli-0.1.2}/tests/test_model_persistence.py +0 -0
  95. {pico_cli-0.1.0 → pico_cli-0.1.2}/tests/test_model_picker.py +0 -0
  96. {pico_cli-0.1.0 → pico_cli-0.1.2}/tests/test_picker_search.py +0 -0
  97. {pico_cli-0.1.0 → pico_cli-0.1.2}/tests/test_pointer_shape.py +0 -0
  98. {pico_cli-0.1.0 → pico_cli-0.1.2}/tests/test_providers.py +0 -0
  99. {pico_cli-0.1.0 → pico_cli-0.1.2}/tests/test_result_display.py +0 -0
  100. {pico_cli-0.1.0 → pico_cli-0.1.2}/tests/test_session.py +0 -0
  101. {pico_cli-0.1.0 → pico_cli-0.1.2}/tests/test_skill_picker.py +0 -0
  102. {pico_cli-0.1.0 → pico_cli-0.1.2}/tests/test_status_bar.py +0 -0
  103. {pico_cli-0.1.0 → pico_cli-0.1.2}/tests/test_stream_order.py +0 -0
  104. {pico_cli-0.1.0 → pico_cli-0.1.2}/tests/test_subagents.py +0 -0
  105. {pico_cli-0.1.0 → pico_cli-0.1.2}/tests/test_todos.py +0 -0
  106. {pico_cli-0.1.0 → pico_cli-0.1.2}/tests/test_tools.py +0 -0
  107. {pico_cli-0.1.0 → pico_cli-0.1.2}/tests/test_trace.py +0 -0
  108. {pico_cli-0.1.0 → pico_cli-0.1.2}/tests/test_trace_view.py +0 -0
  109. {pico_cli-0.1.0 → pico_cli-0.1.2}/tests/test_tui.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: pico-cli
3
- Version: 0.1.0
3
+ Version: 0.1.2
4
4
  Summary: A Python CLI coding agent — autonomous, tool-using, and session-persistent.
5
5
  Project-URL: Homepage, https://github.com/Arya-Ojha/PicoCLI_Learn
6
6
  Project-URL: Repository, https://github.com/Arya-Ojha/PicoCLI_Learn
@@ -20,7 +20,7 @@ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
20
20
  Classifier: Topic :: Utilities
21
21
  Requires-Python: >=3.12
22
22
  Requires-Dist: pico-cli-sdk
23
- Requires-Dist: pico-tui
23
+ Requires-Dist: pico-cli-tui
24
24
  Description-Content-Type: text/markdown
25
25
 
26
26
  # pico
@@ -37,8 +37,8 @@ pico_ai ─► pico_core ─► pico_sdk ─► pico_tui
37
37
 
38
38
  ## Features
39
39
 
40
- - **Headless CLI** — `picoCLI run "do a task"` completes a coding task end-to-end with a single prompt.
41
- - **Interactive TUI** — `picoCLI-chat` is a full terminal UI (Textual + Rich) for back-and-forth sessions.
40
+ - **Headless CLI** — `picocli-chat run "do a task"` completes a coding task end-to-end with a single prompt.
41
+ - **Interactive TUI** — `picocli` is a full terminal UI (Textual + Rich) for back-and-forth sessions.
42
42
  - **Status bar** — the bottom bar always shows `provider | model`, a `thinking` indicator while streaming, and a color-coded context-window bar (`green < 70%`, `yellow < 90%`, `red ≥ 90%`) with the live token estimate.
43
43
  - **Nine hardcoded core tools** — `read`, `write`, `edit`, `grep`, `fetch`, `websearch`, `bash`, `todo`, and `task` (see ADR-0003, ADR-0005).
44
44
  - **Todo tracking** — the agent tracks multi-step work with a `todo` tool (add / update / list / clear); the TUI shows the in-memory list in a read-only side panel that appears once the first todo exists. A run only ends once every todo is completed — stopping early nudges the agent back in. When the run ends clean, the list is cleared for the next run (a run stopped by the stuck-model guard keeps its open todos).
@@ -80,10 +80,43 @@ Dependencies flow one way — `pico_ai` ← `pico_core` ← `pico_sdk` ← `pico
80
80
  | DeepSeek | `DEEPSEEK_API_KEY` | Chat + reasoner (reasoning streams as thinking blocks) |
81
81
  | Ollama | — | Local server (`OLLAMA_HOST`, default `http://localhost:11434`) |
82
82
 
83
- In the TUI, `/provider` opens a picker with ✓/✗ setup status, then a setup form for that provider's API key, base URL, model, and extras. Only changed values are stored (in `settings.json` — prefer env vars on shared machines); blanks fall back to env/defaults. Effective precedence: field default < environment < stored value. Switching providers resets the model to that provider's stored/default model. Headless: `picoCLI run --provider ollama "..."`.
83
+ In the TUI, `/provider` opens a picker with ✓/✗ setup status, then a setup form for that provider's API key, base URL, model, and extras. Only changed values are stored (in `settings.json` — prefer env vars on shared machines); blanks fall back to env/defaults. Effective precedence: field default < environment < stored value. Switching providers resets the model to that provider's stored/default model. Headless: `picocli-chat run --provider ollama "..."`.
84
84
 
85
85
  ## Installation
86
86
 
87
+ Requires Python **3.12+**.
88
+
89
+ ```bash
90
+ # recommended: isolated install — `picocli` + `picocli-chat` work in any
91
+ # directory, like `npm i -g`
92
+ pipx install pico-cli
93
+
94
+ # ... or via uv (same result)
95
+ uv tool install pico-cli
96
+
97
+ # plain pip also works (see the Windows PATH note below)
98
+ pip install pico-cli
99
+
100
+ # try without installing (npx-style)
101
+ uvx pico-cli --help
102
+ ```
103
+
104
+ Then open a terminal **in any directory** and run `picocli`. On first launch (no API key yet) the provider setup opens automatically — pick a provider, paste the key, done. Keys can also come from environment variables (see Configuration below).
105
+
106
+ ### Windows: `pip install` and PATH
107
+
108
+ `pip --user` installs (the default when site-packages isn't writable) drop the commands into `~/.local`-style user Scripts, which is often **not** on PATH — that's when `picocli` is "not recognized". Prefer `pipx`/`uv tool` above, or add the dir once (then open a fresh terminal):
109
+
110
+ ```powershell
111
+ $userPath = [Environment]::GetEnvironmentVariable("Path", "User")
112
+ $newDir = "$env:APPDATA\Python\Python314\Scripts" # adjust version to yours
113
+ if ($userPath -split ";" -notcontains $newDir) {
114
+ [Environment]::SetEnvironmentVariable("Path", "$userPath;$newDir", "User")
115
+ }
116
+ ```
117
+
118
+ ### From source (contributors)
119
+
87
120
  ```bash
88
121
  uv sync
89
122
  ```
@@ -128,22 +161,22 @@ Create `~/.pico/settings.json` to override defaults:
128
161
 
129
162
  ```bash
130
163
  # complete a task in one shot
131
- uv run picoCLI run "explain what this repo does"
164
+ uv run picocli-chat run "explain what this repo does"
132
165
 
133
166
  # let the agent run shell commands (bash is on by default)
134
- uv run picoCLI run "run the tests and fix failures"
167
+ uv run picocli-chat run "run the tests and fix failures"
135
168
 
136
169
  # work in another directory, pick a model
137
- uv run picoCLI run "summarize this code" --cwd D:\some\repo --model openai/gpt-4o-mini
170
+ uv run picocli-chat run "summarize this code" --cwd D:\some\repo --model openai/gpt-4o-mini
138
171
 
139
172
  # resume a previous session by id
140
- uv run picoCLI run "continue" --session <session-id>
173
+ uv run picocli-chat run "continue" --session <session-id>
141
174
 
142
175
  # compact a session headlessly (with optional steering text)
143
- uv run picoCLI run "/compact focus on the auth refactor"
176
+ uv run picocli-chat run "/compact focus on the auth refactor"
144
177
  ```
145
178
 
146
- Flags for `picoCLI run`:
179
+ Flags for `picocli-chat run`:
147
180
 
148
181
  | Flag | Purpose |
149
182
  |---|---|
@@ -159,10 +192,10 @@ Flags for `picoCLI run`:
159
192
  ### Interactive TUI
160
193
 
161
194
  ```bash
162
- uv run picoCLI-chat
195
+ uv run picocli
163
196
  ```
164
197
 
165
- `picoCLI-chat` shares the same flags. Inside the prompt you can type a message or use:
198
+ `picocli` shares the same flags. Inside the prompt you can type a message or use:
166
199
 
167
200
  | Slash command | Key | Action |
168
201
  |---|---|---|
@@ -202,7 +235,7 @@ Permission gating via `allowed_tools` in `settings.json` (`null` = all tools, `[
202
235
 
203
236
  ## Where sessions live
204
237
 
205
- Sessions are persisted as JSONL under `~/.pico/sessions/<id>.jsonl` by default (configurable via `session_dir`). Both `picoCLI run` and `picoCLI-chat` accept `--session <id>` to resume; `/history`, `/fork`, and `/undo` rewind within the tree without deleting nodes.
238
+ Sessions are persisted as JSONL under `~/.pico/sessions/<id>.jsonl` by default (configurable via `session_dir`). Both `picocli-chat run` and `picocli` accept `--session <id>` to resume; `/history`, `/fork`, and `/undo` rewind within the tree without deleting nodes.
206
239
 
207
240
  ## Development
208
241
 
@@ -215,10 +248,10 @@ uv run mypy packages/pico_ai/src packages/pico_core/src packages/pico_sdk/src pa
215
248
 
216
249
  # build all wheels into dist/ (root `pico-cli` is a meta-package: deps + entry points only)
217
250
  uv build --package pico-cli --out-dir dist
218
- uv build --package pico-ai --out-dir dist
219
- uv build --package pico-core --out-dir dist
251
+ uv build --package pico-cli-ai --out-dir dist
252
+ uv build --package pico-cli-core --out-dir dist
220
253
  uv build --package pico-cli-sdk --out-dir dist
221
- uv build --package pico-tui --out-dir dist
254
+ uv build --package pico-cli-tui --out-dir dist
222
255
  ```
223
256
 
224
257
  The test suite is network-free: it drives the whole agent loop through a scripted fake provider (`FakeProvider`) and a temporary filesystem, exercising `pico_ai`, `pico_core`, `pico_sdk`, and `pico_tui`.
@@ -12,8 +12,8 @@ pico_ai ─► pico_core ─► pico_sdk ─► pico_tui
12
12
 
13
13
  ## Features
14
14
 
15
- - **Headless CLI** — `picoCLI run "do a task"` completes a coding task end-to-end with a single prompt.
16
- - **Interactive TUI** — `picoCLI-chat` is a full terminal UI (Textual + Rich) for back-and-forth sessions.
15
+ - **Headless CLI** — `picocli-chat run "do a task"` completes a coding task end-to-end with a single prompt.
16
+ - **Interactive TUI** — `picocli` is a full terminal UI (Textual + Rich) for back-and-forth sessions.
17
17
  - **Status bar** — the bottom bar always shows `provider | model`, a `thinking` indicator while streaming, and a color-coded context-window bar (`green < 70%`, `yellow < 90%`, `red ≥ 90%`) with the live token estimate.
18
18
  - **Nine hardcoded core tools** — `read`, `write`, `edit`, `grep`, `fetch`, `websearch`, `bash`, `todo`, and `task` (see ADR-0003, ADR-0005).
19
19
  - **Todo tracking** — the agent tracks multi-step work with a `todo` tool (add / update / list / clear); the TUI shows the in-memory list in a read-only side panel that appears once the first todo exists. A run only ends once every todo is completed — stopping early nudges the agent back in. When the run ends clean, the list is cleared for the next run (a run stopped by the stuck-model guard keeps its open todos).
@@ -55,10 +55,43 @@ Dependencies flow one way — `pico_ai` ← `pico_core` ← `pico_sdk` ← `pico
55
55
  | DeepSeek | `DEEPSEEK_API_KEY` | Chat + reasoner (reasoning streams as thinking blocks) |
56
56
  | Ollama | — | Local server (`OLLAMA_HOST`, default `http://localhost:11434`) |
57
57
 
58
- In the TUI, `/provider` opens a picker with ✓/✗ setup status, then a setup form for that provider's API key, base URL, model, and extras. Only changed values are stored (in `settings.json` — prefer env vars on shared machines); blanks fall back to env/defaults. Effective precedence: field default < environment < stored value. Switching providers resets the model to that provider's stored/default model. Headless: `picoCLI run --provider ollama "..."`.
58
+ In the TUI, `/provider` opens a picker with ✓/✗ setup status, then a setup form for that provider's API key, base URL, model, and extras. Only changed values are stored (in `settings.json` — prefer env vars on shared machines); blanks fall back to env/defaults. Effective precedence: field default < environment < stored value. Switching providers resets the model to that provider's stored/default model. Headless: `picocli-chat run --provider ollama "..."`.
59
59
 
60
60
  ## Installation
61
61
 
62
+ Requires Python **3.12+**.
63
+
64
+ ```bash
65
+ # recommended: isolated install — `picocli` + `picocli-chat` work in any
66
+ # directory, like `npm i -g`
67
+ pipx install pico-cli
68
+
69
+ # ... or via uv (same result)
70
+ uv tool install pico-cli
71
+
72
+ # plain pip also works (see the Windows PATH note below)
73
+ pip install pico-cli
74
+
75
+ # try without installing (npx-style)
76
+ uvx pico-cli --help
77
+ ```
78
+
79
+ Then open a terminal **in any directory** and run `picocli`. On first launch (no API key yet) the provider setup opens automatically — pick a provider, paste the key, done. Keys can also come from environment variables (see Configuration below).
80
+
81
+ ### Windows: `pip install` and PATH
82
+
83
+ `pip --user` installs (the default when site-packages isn't writable) drop the commands into `~/.local`-style user Scripts, which is often **not** on PATH — that's when `picocli` is "not recognized". Prefer `pipx`/`uv tool` above, or add the dir once (then open a fresh terminal):
84
+
85
+ ```powershell
86
+ $userPath = [Environment]::GetEnvironmentVariable("Path", "User")
87
+ $newDir = "$env:APPDATA\Python\Python314\Scripts" # adjust version to yours
88
+ if ($userPath -split ";" -notcontains $newDir) {
89
+ [Environment]::SetEnvironmentVariable("Path", "$userPath;$newDir", "User")
90
+ }
91
+ ```
92
+
93
+ ### From source (contributors)
94
+
62
95
  ```bash
63
96
  uv sync
64
97
  ```
@@ -103,22 +136,22 @@ Create `~/.pico/settings.json` to override defaults:
103
136
 
104
137
  ```bash
105
138
  # complete a task in one shot
106
- uv run picoCLI run "explain what this repo does"
139
+ uv run picocli-chat run "explain what this repo does"
107
140
 
108
141
  # let the agent run shell commands (bash is on by default)
109
- uv run picoCLI run "run the tests and fix failures"
142
+ uv run picocli-chat run "run the tests and fix failures"
110
143
 
111
144
  # work in another directory, pick a model
112
- uv run picoCLI run "summarize this code" --cwd D:\some\repo --model openai/gpt-4o-mini
145
+ uv run picocli-chat run "summarize this code" --cwd D:\some\repo --model openai/gpt-4o-mini
113
146
 
114
147
  # resume a previous session by id
115
- uv run picoCLI run "continue" --session <session-id>
148
+ uv run picocli-chat run "continue" --session <session-id>
116
149
 
117
150
  # compact a session headlessly (with optional steering text)
118
- uv run picoCLI run "/compact focus on the auth refactor"
151
+ uv run picocli-chat run "/compact focus on the auth refactor"
119
152
  ```
120
153
 
121
- Flags for `picoCLI run`:
154
+ Flags for `picocli-chat run`:
122
155
 
123
156
  | Flag | Purpose |
124
157
  |---|---|
@@ -134,10 +167,10 @@ Flags for `picoCLI run`:
134
167
  ### Interactive TUI
135
168
 
136
169
  ```bash
137
- uv run picoCLI-chat
170
+ uv run picocli
138
171
  ```
139
172
 
140
- `picoCLI-chat` shares the same flags. Inside the prompt you can type a message or use:
173
+ `picocli` shares the same flags. Inside the prompt you can type a message or use:
141
174
 
142
175
  | Slash command | Key | Action |
143
176
  |---|---|---|
@@ -177,7 +210,7 @@ Permission gating via `allowed_tools` in `settings.json` (`null` = all tools, `[
177
210
 
178
211
  ## Where sessions live
179
212
 
180
- Sessions are persisted as JSONL under `~/.pico/sessions/<id>.jsonl` by default (configurable via `session_dir`). Both `picoCLI run` and `picoCLI-chat` accept `--session <id>` to resume; `/history`, `/fork`, and `/undo` rewind within the tree without deleting nodes.
213
+ Sessions are persisted as JSONL under `~/.pico/sessions/<id>.jsonl` by default (configurable via `session_dir`). Both `picocli-chat run` and `picocli` accept `--session <id>` to resume; `/history`, `/fork`, and `/undo` rewind within the tree without deleting nodes.
181
214
 
182
215
  ## Development
183
216
 
@@ -190,10 +223,10 @@ uv run mypy packages/pico_ai/src packages/pico_core/src packages/pico_sdk/src pa
190
223
 
191
224
  # build all wheels into dist/ (root `pico-cli` is a meta-package: deps + entry points only)
192
225
  uv build --package pico-cli --out-dir dist
193
- uv build --package pico-ai --out-dir dist
194
- uv build --package pico-core --out-dir dist
226
+ uv build --package pico-cli-ai --out-dir dist
227
+ uv build --package pico-cli-core --out-dir dist
195
228
  uv build --package pico-cli-sdk --out-dir dist
196
- uv build --package pico-tui --out-dir dist
229
+ uv build --package pico-cli-tui --out-dir dist
197
230
  ```
198
231
 
199
232
  The test suite is network-free: it drives the whole agent loop through a scripted fake provider (`FakeProvider`) and a temporary filesystem, exercising `pico_ai`, `pico_core`, `pico_sdk`, and `pico_tui`.
@@ -1,4 +1,4 @@
1
- # pico-ai
1
+ # pico-cli-ai
2
2
 
3
3
  LLM abstraction and protocol normalisation for `pico-cli`: one unified streaming "AI call" shape plus per-provider adapters (OpenRouter, OpenAI, Anthropic, Gemini, DeepSeek, local Ollama).
4
4
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
- name = "pico-ai"
3
- version = "0.1.0"
2
+ name = "pico-cli-ai"
3
+ version = "0.1.2"
4
4
  description = "LLM abstraction and protocol normalisation."
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -1,4 +1,4 @@
1
- # pico-core
1
+ # pico-cli-core
2
2
 
3
3
  The agent loop (explicit finite-state machine) and the append-only, tree-based session model for `pico-cli`: nine hardcoded core tools (`read`, `write`, `edit`, `grep`, `fetch`, `websearch`, `bash`, `todo`, `task`), todo tracking, sub-agents, and compaction.
4
4
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
- name = "pico-core"
3
- version = "0.1.0"
2
+ name = "pico-cli-core"
3
+ version = "0.1.2"
4
4
  description = "Agent loop and session tree."
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -15,7 +15,7 @@ classifiers = [
15
15
  "Programming Language :: Python :: 3.12",
16
16
  ]
17
17
  requires-python = ">=3.12"
18
- dependencies = ["pico-ai", "pydantic>=2", "httpx>=0.27"]
18
+ dependencies = ["pico-cli-ai", "pydantic>=2", "httpx>=0.27"]
19
19
 
20
20
  [project.urls]
21
21
  Homepage = "https://github.com/Arya-Ojha/PicoCLI_Learn"
@@ -30,4 +30,4 @@ build-backend = "hatchling.build"
30
30
  packages = ["src/pico_core"]
31
31
 
32
32
  [tool.uv.sources]
33
- pico-ai = { workspace = true }
33
+ pico-cli-ai = { workspace = true }
@@ -1,5 +1,5 @@
1
1
  # pico-cli-sdk
2
2
 
3
- Headless library API for `pico-cli`: `AgentSession`, curated observe-only hooks, `SKILL.md` skills, provider setup, and the `picoCLI` command-line interface.
3
+ Headless library API for `pico-cli`: `AgentSession`, curated observe-only hooks, `SKILL.md` skills, provider setup, and the `picocli-chat` command-line interface.
4
4
 
5
5
  See the [pico-cli README](https://github.com/Arya-Ojha/PicoCLI_Learn#readme) for the full picture.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "pico-cli-sdk"
3
- version = "0.1.0"
3
+ version = "0.1.2"
4
4
  description = "Headless library API and extension/plugin binding."
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -16,14 +16,14 @@ classifiers = [
16
16
  "Programming Language :: Python :: 3.12",
17
17
  ]
18
18
  requires-python = ">=3.12"
19
- dependencies = ["pico-core", "pico-ai", "pydantic>=2"]
19
+ dependencies = ["pico-cli-core", "pico-cli-ai", "pydantic>=2"]
20
20
 
21
21
  [project.urls]
22
22
  Homepage = "https://github.com/Arya-Ojha/PicoCLI_Learn"
23
23
  Repository = "https://github.com/Arya-Ojha/PicoCLI_Learn"
24
24
  Issues = "https://github.com/Arya-Ojha/PicoCLI_Learn/issues"
25
25
 
26
- # Note: the `picoCLI` entry point lives on the `pico-cli` meta-package only,
26
+ # Note: the `picocli-chat` entry point lives on the `pico-cli` meta-package only,
27
27
  # so installing the stack never ships duplicate console scripts.
28
28
  [build-system]
29
29
  requires = ["hatchling"]
@@ -33,5 +33,5 @@ build-backend = "hatchling.build"
33
33
  packages = ["src/pico_sdk"]
34
34
 
35
35
  [tool.uv.sources]
36
- pico-core = { workspace = true }
37
- pico-ai = { workspace = true }
36
+ pico-cli-core = { workspace = true }
37
+ pico-cli-ai = { workspace = true }
@@ -53,7 +53,7 @@ def apply_cli_overrides(args: argparse.Namespace, settings: Settings) -> bool:
53
53
 
54
54
 
55
55
  def build_parser() -> argparse.ArgumentParser:
56
- parser = argparse.ArgumentParser(prog="picoCLI", description="A headless coding agent.")
56
+ parser = argparse.ArgumentParser(prog="picocli-chat", description="A headless coding agent.")
57
57
  sub = parser.add_subparsers(dest="command", required=True)
58
58
 
59
59
  run = sub.add_parser("run", help="Run the agent on a prompt.")
@@ -97,7 +97,7 @@ async def run_command(args: argparse.Namespace) -> int:
97
97
  sys.stderr.write(
98
98
  f"error: provider '{settings.provider}' is missing required "
99
99
  f"config: {', '.join(missing)}.\n"
100
- f"Run `picoCLI-chat` and use /provider to configure it, or set "
100
+ f"Run `picocli` and use /provider to configure it, or set "
101
101
  f"the corresponding environment variable.\n"
102
102
  )
103
103
  return 1
@@ -1,5 +1,5 @@
1
- # pico-tui
1
+ # pico-cli-tui
2
2
 
3
- Interactive terminal UI for `pico-cli` (Textual + Rich): chat log, todo side panel, trace view, filterable pickers, provider setup forms, and the `picoCLI-chat` entry point.
3
+ Interactive terminal UI for `pico-cli` (Textual + Rich): chat log, todo side panel, trace view, filterable pickers, provider setup forms, and the `picocli` entry point.
4
4
 
5
5
  See the [pico-cli README](https://github.com/Arya-Ojha/PicoCLI_Learn#readme) for the full picture.
@@ -1,6 +1,6 @@
1
1
  [project]
2
- name = "pico-tui"
3
- version = "0.1.0"
2
+ name = "pico-cli-tui"
3
+ version = "0.1.2"
4
4
  description = "Terminal user interface view."
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -27,7 +27,7 @@ Homepage = "https://github.com/Arya-Ojha/PicoCLI_Learn"
27
27
  Repository = "https://github.com/Arya-Ojha/PicoCLI_Learn"
28
28
  Issues = "https://github.com/Arya-Ojha/PicoCLI_Learn/issues"
29
29
 
30
- # Note: the `picoCLI-chat` entry point lives on the `pico-cli`
30
+ # Note: the `picocli` entry point lives on the `pico-cli`
31
31
  # meta-package only, so installing the stack never ships duplicate
32
32
  # console scripts.
33
33
  [build-system]
@@ -357,10 +357,20 @@ class PicoApp(App[None]):
357
357
  ("f1", "show_help", "Help"),
358
358
  ]
359
359
 
360
- def __init__(self, mgr: _SessionManager, *, startup_notice: str = "") -> None:
360
+ def __init__(
361
+ self,
362
+ mgr: _SessionManager,
363
+ *,
364
+ startup_notice: str = "",
365
+ auto_setup: bool = False,
366
+ ) -> None:
361
367
  super().__init__()
362
368
  self._mgr = mgr
363
369
  self._startup_notice = startup_notice
370
+ # First-run onboarding: when True and the active provider is
371
+ # missing required config, the provider picker opens on launch
372
+ # so keys/URLs are entered in-UI instead of discovered via /help.
373
+ self._auto_setup = auto_setup
364
374
  self._streaming = False
365
375
  # Everything written to the chat log, in order. Thinking blocks are
366
376
  # stored as ThinkingSegment so they can collapse/expand on click.
@@ -399,6 +409,10 @@ class PicoApp(App[None]):
399
409
  self._write_chat(
400
410
  Panel(self._startup_notice, title="setup", border_style="yellow")
401
411
  )
412
+ if self._auto_setup:
413
+ settings = self._mgr.session.settings
414
+ if missing_required(settings.provider, settings):
415
+ self.call_after_refresh(self._show_provider_picker)
402
416
 
403
417
  def _refresh_todo_panel(self) -> None:
404
418
  """Re-render the todo side panel (auto-hides while empty)."""
@@ -878,7 +892,7 @@ class PicoApp(App[None]):
878
892
 
879
893
  def main(argv: list[str] | None = None) -> int:
880
894
  parser = argparse.ArgumentParser(
881
- prog="picoCLI-chat", description="Interactive pico session (Textual TUI)."
895
+ prog="picocli", description="Interactive pico session (Textual TUI)."
882
896
  )
883
897
  parser.add_argument(
884
898
  "--no-bash",
@@ -955,7 +969,7 @@ def main(argv: list[str] | None = None) -> int:
955
969
  f"Provider {provider_label} is missing required config: "
956
970
  f"{', '.join(missing)}. Use /provider to configure it."
957
971
  )
958
- app = PicoApp(mgr, startup_notice=startup_notice)
972
+ app = PicoApp(mgr, startup_notice=startup_notice, auto_setup=True)
959
973
  app.run()
960
974
  return 0
961
975
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "pico-cli"
3
- version = "0.1.0"
3
+ version = "0.1.2"
4
4
  description = "A Python CLI coding agent — autonomous, tool-using, and session-persistent."
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -18,7 +18,7 @@ classifiers = [
18
18
  "Topic :: Utilities",
19
19
  ]
20
20
  requires-python = ">=3.12"
21
- dependencies = ["pico-cli-sdk", "pico-tui"]
21
+ dependencies = ["pico-cli-sdk", "pico-cli-tui"]
22
22
 
23
23
  [project.urls]
24
24
  Homepage = "https://github.com/Arya-Ojha/PicoCLI_Learn"
@@ -26,8 +26,8 @@ Repository = "https://github.com/Arya-Ojha/PicoCLI_Learn"
26
26
  Issues = "https://github.com/Arya-Ojha/PicoCLI_Learn/issues"
27
27
 
28
28
  [project.scripts]
29
- picoCLI = "pico_sdk.cli:main"
30
- picoCLI-chat = "pico_tui.app:main"
29
+ picocli-chat = "pico_sdk.cli:main"
30
+ picocli = "pico_tui.app:main"
31
31
 
32
32
  # The root `pico` dist is a meta-package: the implementation lives in the
33
33
  # workspace members, so the wheel ships the stub above plus metadata
@@ -44,7 +44,7 @@ members = ["packages/*"]
44
44
 
45
45
  [tool.uv.sources]
46
46
  pico-cli-sdk = { workspace = true }
47
- pico-tui = { workspace = true }
47
+ pico-cli-tui = { workspace = true }
48
48
 
49
49
  [dependency-groups]
50
50
  dev = [
@@ -2,5 +2,5 @@
2
2
 
3
3
  ``pico_ai``, ``pico_core``, ``pico_sdk``, and ``pico_tui`` (under
4
4
  ``packages/``) provide the implementation; this dist only carries the
5
- dependency pins and the ``picoCLI`` / ``picoCLI-chat`` entry points.
5
+ dependency pins and the ``picocli`` / ``picocli-chat`` entry points.
6
6
  """
@@ -0,0 +1,70 @@
1
+ """First-run onboarding: missing provider config auto-opens setup."""
2
+
3
+ import pytest
4
+
5
+ from pico_sdk.config import Settings
6
+ from pico_sdk.providers import create_provider, missing_required
7
+ from pico_tui.app import PicoApp, _SessionManager
8
+ from pico_tui.provider_picker import ProviderPickerScreen
9
+
10
+ from conftest import FakeProvider, make_session
11
+
12
+
13
+ @pytest.fixture
14
+ def fresh_settings(monkeypatch):
15
+ """Settings as on a brand-new machine: no keys anywhere."""
16
+ for var in (
17
+ "OPENROUTER_API_KEY",
18
+ "OPENAI_API_KEY",
19
+ "ANTHROPIC_API_KEY",
20
+ "GOOGLE_API_KEY",
21
+ "DEEPSEEK_API_KEY",
22
+ ):
23
+ monkeypatch.delenv(var, raising=False)
24
+ settings = Settings()
25
+ assert missing_required(settings.provider, settings), "expected missing config"
26
+ return settings
27
+
28
+
29
+ def _app(tmp_path, settings, auto_setup=False):
30
+ session = make_session(
31
+ FakeProvider([]), tmp_path, settings=settings, load_skills=False
32
+ )
33
+ return PicoApp(_SessionManager(session), auto_setup=auto_setup)
34
+
35
+
36
+ async def test_missing_config_auto_opens_provider_picker(tmp_path, fresh_settings):
37
+ app = _app(tmp_path, fresh_settings, auto_setup=True)
38
+ async with app.run_test() as pilot:
39
+ await pilot.pause()
40
+ await pilot.pause()
41
+ assert isinstance(app.screen, ProviderPickerScreen)
42
+
43
+
44
+ async def test_auto_setup_off_by_default(tmp_path, fresh_settings):
45
+ app = _app(tmp_path, fresh_settings)
46
+ async with app.run_test() as pilot:
47
+ await pilot.pause()
48
+ assert not isinstance(app.screen, ProviderPickerScreen)
49
+
50
+
51
+ async def test_configured_never_auto_opens(tmp_path, monkeypatch):
52
+ monkeypatch.setenv("OPENROUTER_API_KEY", "test-key")
53
+ settings = Settings()
54
+ assert not missing_required(settings.provider, settings)
55
+ session = make_session(
56
+ create_provider(settings), tmp_path, settings=settings, load_skills=False
57
+ )
58
+ app = PicoApp(_SessionManager(session), auto_setup=True)
59
+ async with app.run_test() as pilot:
60
+ await pilot.pause()
61
+ await pilot.pause()
62
+ assert not isinstance(app.screen, ProviderPickerScreen)
63
+
64
+
65
+ def test_main_requests_auto_setup():
66
+ import inspect
67
+
68
+ from pico_tui.app import main
69
+
70
+ assert "auto_setup=True" in inspect.getsource(main)
@@ -8,11 +8,11 @@ resolution-markers = [
8
8
 
9
9
  [manifest]
10
10
  members = [
11
- "pico-ai",
12
11
  "pico-cli",
12
+ "pico-cli-ai",
13
+ "pico-cli-core",
13
14
  "pico-cli-sdk",
14
- "pico-core",
15
- "pico-tui",
15
+ "pico-cli-tui",
16
16
  ]
17
17
 
18
18
  [[package]]
@@ -406,28 +406,13 @@ wheels = [
406
406
  { url = "https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl", hash = "sha256:a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189", size = 57328, upload-time = "2026-04-27T01:46:07.06Z" },
407
407
  ]
408
408
 
409
- [[package]]
410
- name = "pico-ai"
411
- version = "0.1.0"
412
- source = { editable = "packages/pico_ai" }
413
- dependencies = [
414
- { name = "httpx" },
415
- { name = "pydantic" },
416
- ]
417
-
418
- [package.metadata]
419
- requires-dist = [
420
- { name = "httpx", specifier = ">=0.27" },
421
- { name = "pydantic", specifier = ">=2" },
422
- ]
423
-
424
409
  [[package]]
425
410
  name = "pico-cli"
426
- version = "0.1.0"
411
+ version = "0.1.2"
427
412
  source = { editable = "." }
428
413
  dependencies = [
429
414
  { name = "pico-cli-sdk" },
430
- { name = "pico-tui" },
415
+ { name = "pico-cli-tui" },
431
416
  ]
432
417
 
433
418
  [package.dev-dependencies]
@@ -440,7 +425,7 @@ dev = [
440
425
  [package.metadata]
441
426
  requires-dist = [
442
427
  { name = "pico-cli-sdk", editable = "packages/pico_sdk" },
443
- { name = "pico-tui", editable = "packages/pico_tui" },
428
+ { name = "pico-cli-tui", editable = "packages/pico_tui" },
444
429
  ]
445
430
 
446
431
  [package.metadata.requires-dev]
@@ -451,42 +436,57 @@ dev = [
451
436
  ]
452
437
 
453
438
  [[package]]
454
- name = "pico-cli-sdk"
455
- version = "0.1.0"
456
- source = { editable = "packages/pico_sdk" }
439
+ name = "pico-cli-ai"
440
+ version = "0.1.2"
441
+ source = { editable = "packages/pico_ai" }
457
442
  dependencies = [
458
- { name = "pico-ai" },
459
- { name = "pico-core" },
443
+ { name = "httpx" },
460
444
  { name = "pydantic" },
461
445
  ]
462
446
 
463
447
  [package.metadata]
464
448
  requires-dist = [
465
- { name = "pico-ai", editable = "packages/pico_ai" },
466
- { name = "pico-core", editable = "packages/pico_core" },
449
+ { name = "httpx", specifier = ">=0.27" },
467
450
  { name = "pydantic", specifier = ">=2" },
468
451
  ]
469
452
 
470
453
  [[package]]
471
- name = "pico-core"
472
- version = "0.1.0"
454
+ name = "pico-cli-core"
455
+ version = "0.1.2"
473
456
  source = { editable = "packages/pico_core" }
474
457
  dependencies = [
475
458
  { name = "httpx" },
476
- { name = "pico-ai" },
459
+ { name = "pico-cli-ai" },
477
460
  { name = "pydantic" },
478
461
  ]
479
462
 
480
463
  [package.metadata]
481
464
  requires-dist = [
482
465
  { name = "httpx", specifier = ">=0.27" },
483
- { name = "pico-ai", editable = "packages/pico_ai" },
466
+ { name = "pico-cli-ai", editable = "packages/pico_ai" },
484
467
  { name = "pydantic", specifier = ">=2" },
485
468
  ]
486
469
 
487
470
  [[package]]
488
- name = "pico-tui"
489
- version = "0.1.0"
471
+ name = "pico-cli-sdk"
472
+ version = "0.1.2"
473
+ source = { editable = "packages/pico_sdk" }
474
+ dependencies = [
475
+ { name = "pico-cli-ai" },
476
+ { name = "pico-cli-core" },
477
+ { name = "pydantic" },
478
+ ]
479
+
480
+ [package.metadata]
481
+ requires-dist = [
482
+ { name = "pico-cli-ai", editable = "packages/pico_ai" },
483
+ { name = "pico-cli-core", editable = "packages/pico_core" },
484
+ { name = "pydantic", specifier = ">=2" },
485
+ ]
486
+
487
+ [[package]]
488
+ name = "pico-cli-tui"
489
+ version = "0.1.2"
490
490
  source = { editable = "packages/pico_tui" }
491
491
  dependencies = [
492
492
  { name = "pico-cli-sdk" },
@@ -1,80 +0,0 @@
1
- # Context Status Bar Implementation Summary
2
-
3
- ## Overview
4
- Added a context status bar widget to the PicoCLI TUI that displays:
5
- - Provider name (e.g., "OpenRouter")
6
- - Model name (e.g., "nvidia/nemotron-3.5-lightning:free")
7
- - Thinking indicator (shown when the model is reasoning)
8
- - Context window progress bar (fills as context fills, color-coded by usage level)
9
- - Current token count (formatted with commas, e.g., "38,932")
10
-
11
- ## Files Modified
12
-
13
- ### 1. `packages/pico_core/src/pico_core/fsm.py`
14
- - Added public `estimate_tokens()` method to `AgentLoop` class
15
- - This exposes the private `_estimate_tokens()` functionality
16
-
17
- ### 2. `packages/pico_sdk/src/pico_sdk/session.py`
18
- - Added `provider_name` property to `AgentSession` class
19
- - Extracts provider name from the provider class name
20
- - Returns "OpenRouter" for OpenRouterProvider
21
- - Added `context_window` property to `AgentSession` class
22
- - Returns the context window size from the agent loop
23
- - Added `estimate_tokens()` method to `AgentSession` class
24
- - Returns current estimated token count from the agent loop
25
-
26
- ### 3. `packages/pico_tui/src/pico_tui/status_bar.py` (NEW FILE)
27
- - Created `ContextStatusBar` widget extending Textual's `Static`
28
- - Features:
29
- - Displays provider | model information
30
- - Shows "thinking" indicator in yellow italic when active
31
- - Renders a 20-character progress bar for context window usage
32
- - Color-codes the progress bar:
33
- - Green: 0-50% usage (░ character)
34
- - Yellow: 50-70% usage (▒ character)
35
- - Orange: 70-90% usage (▓ character)
36
- - Red: 90-100% usage (█ character)
37
- - Shows token count with comma formatting in cyan
38
- - Methods:
39
- - `on_mount()`: Renders initial display after widget mount
40
- - `update_info()`: Updates all status information
41
- - `set_thinking()`: Updates thinking state
42
- - `_update_display()`: Renders the status bar with Rich Text
43
-
44
- ### 4. `packages/pico_tui/src/pico_tui/app.py`
45
- - Imported `ContextStatusBar` widget
46
- - Added CSS styling for `#status-bar`:
47
- - Docked to bottom
48
- - Height: 1 line
49
- - Background: $surface color
50
- - Padding: 0 1
51
- - Added `ContextStatusBar` to `compose()` method after Input widget
52
- - Added `_update_status_bar()` method to update the status bar with current session info
53
- - Updated `on_mount()` to call `_update_status_bar()` on initialization
54
- - Updated `_run_prompt()` to call `_update_status_bar()` when streaming starts
55
- - Updated `_stream_worker()` to call `_update_status_bar()` when streaming completes
56
-
57
- ### 5. `tests/test_status_bar.py` (NEW FILE)
58
- - Added 3 tests for the ContextStatusBar widget:
59
- - `test_status_bar_initialization`: Verifies default values
60
- - `test_status_bar_stores_info`: Verifies info storage
61
- - `test_status_bar_set_thinking`: Verifies thinking state updates
62
-
63
- ## Test Results
64
- All 92 tests pass successfully, including:
65
- - 19 existing TUI tests
66
- - 3 new status bar tests
67
- - All other existing tests remain passing
68
-
69
- ## Usage
70
- The status bar automatically appears below the input bar in the TUI and updates:
71
- - On application startup (shows initial provider, model, and 0 tokens)
72
- - When a prompt is submitted (shows "thinking" indicator)
73
- - When streaming completes (updates token count and hides "thinking")
74
- - When the model changes via `/model` command
75
-
76
- The status bar provides real-time visibility into:
77
- - Which AI provider and model is being used
78
- - Whether the model is currently thinking/reasoning
79
- - How much of the context window is being used
80
- - The exact token count in the current context
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes