pico-cli 0.1.1__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.
- {pico_cli-0.1.1 → pico_cli-0.1.2}/PKG-INFO +34 -1
- {pico_cli-0.1.1 → pico_cli-0.1.2}/README.md +33 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_ai/pyproject.toml +1 -1
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_core/pyproject.toml +1 -1
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_sdk/pyproject.toml +1 -1
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_tui/pyproject.toml +1 -1
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_tui/src/pico_tui/app.py +16 -2
- {pico_cli-0.1.1 → pico_cli-0.1.2}/pyproject.toml +1 -1
- pico_cli-0.1.2/tests/test_first_run_setup.py +70 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/uv.lock +5 -5
- pico_cli-0.1.1/IMPLEMENTATION_SUMMARY.md +0 -80
- {pico_cli-0.1.1 → pico_cli-0.1.2}/.gitignore +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/.scratch/headless-agent/issues/01-unified-ai-call.md +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/.scratch/headless-agent/issues/02-tracer-bullet-headless-text-response.md +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/.scratch/headless-agent/issues/03-tools.md +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/.scratch/headless-agent/issues/04-session-fork.md +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/.scratch/headless-agent/issues/05-compaction.md +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/.scratch/headless-agent/issues/06-extension-binding.md +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/.scratch/headless-agent/issues/07-config-file.md +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/.scratch/headless-agent/spec.md +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/.scratch/pico-tui/spec.md +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/.scratch/trace-view/01-assistant-duration.md +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/.scratch/trace-view/02-row-assembly.md +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/.scratch/trace-view/03-overlay.md +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/AGENTS.md +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/CONTEXT.md +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/LICENSE +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/docs/adr/0001-monorepo-package-split.md +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/docs/adr/0002-tree-based-session.md +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/docs/adr/0003-hardcoded-core.md +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/docs/adr/0004-native-provider-adapters.md +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/docs/adr/0005-task-tool-subagents.md +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/docs/adr/0006-trace-view-durations.md +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/docs/agents/domain.md +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/docs/agents/issue-tracker.md +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/docs/agents/triage-labels.md +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_ai/README.md +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_ai/src/pico_ai/__init__.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_ai/src/pico_ai/openrouter.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_ai/src/pico_ai/provider.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_ai/src/pico_ai/providers/__init__.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_ai/src/pico_ai/providers/_compat.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_ai/src/pico_ai/providers/anthropic.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_ai/src/pico_ai/providers/deepseek.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_ai/src/pico_ai/providers/gemini.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_ai/src/pico_ai/providers/ollama.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_ai/src/pico_ai/providers/openai.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_ai/src/pico_ai/providers/spec.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_ai/src/pico_ai/py.typed +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_ai/src/pico_ai/types.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_core/README.md +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_core/src/pico_core/__init__.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_core/src/pico_core/fsm.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_core/src/pico_core/py.typed +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_core/src/pico_core/session.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_core/src/pico_core/subagents.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_core/src/pico_core/todos.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_core/src/pico_core/tools.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_core/src/pico_core/trace.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_sdk/README.md +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_sdk/src/pico_sdk/__init__.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_sdk/src/pico_sdk/__main__.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_sdk/src/pico_sdk/cli.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_sdk/src/pico_sdk/config.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_sdk/src/pico_sdk/extensions.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_sdk/src/pico_sdk/providers.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_sdk/src/pico_sdk/py.typed +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_sdk/src/pico_sdk/session.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_sdk/src/pico_sdk/skills.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_tui/README.md +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_tui/src/pico_tui/__init__.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_tui/src/pico_tui/commands.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_tui/src/pico_tui/history_picker.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_tui/src/pico_tui/modal.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_tui/src/pico_tui/model_picker.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_tui/src/pico_tui/provider_form.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_tui/src/pico_tui/provider_picker.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_tui/src/pico_tui/py.typed +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_tui/src/pico_tui/render.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_tui/src/pico_tui/skill_picker.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_tui/src/pico_tui/status_bar.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_tui/src/pico_tui/todo_panel.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/packages/pico_tui/src/pico_tui/trace_view.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/src/pico/__init__.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/tests/conftest.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/tests/test_agent_session.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/tests/test_ai_call.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/tests/test_cli.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/tests/test_config.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/tests/test_extensions.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/tests/test_first_token_timeout.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/tests/test_fsm.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/tests/test_history_picker.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/tests/test_model_persistence.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/tests/test_model_picker.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/tests/test_picker_search.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/tests/test_pointer_shape.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/tests/test_providers.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/tests/test_result_display.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/tests/test_session.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/tests/test_skill_picker.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/tests/test_status_bar.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/tests/test_stream_order.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/tests/test_subagents.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/tests/test_todos.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/tests/test_tools.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/tests/test_trace.py +0 -0
- {pico_cli-0.1.1 → pico_cli-0.1.2}/tests/test_trace_view.py +0 -0
- {pico_cli-0.1.1 → 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.
|
|
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
|
|
@@ -84,6 +84,39 @@ In the TUI, `/provider` opens a picker with ✓/✗ setup status, then a setup f
|
|
|
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
|
```
|
|
@@ -59,6 +59,39 @@ In the TUI, `/provider` opens a picker with ✓/✗ setup status, then a setup f
|
|
|
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
|
```
|
|
@@ -357,10 +357,20 @@ class PicoApp(App[None]):
|
|
|
357
357
|
("f1", "show_help", "Help"),
|
|
358
358
|
]
|
|
359
359
|
|
|
360
|
-
def __init__(
|
|
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)."""
|
|
@@ -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
|
|
|
@@ -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)
|
|
@@ -408,7 +408,7 @@ wheels = [
|
|
|
408
408
|
|
|
409
409
|
[[package]]
|
|
410
410
|
name = "pico-cli"
|
|
411
|
-
version = "0.1.
|
|
411
|
+
version = "0.1.2"
|
|
412
412
|
source = { editable = "." }
|
|
413
413
|
dependencies = [
|
|
414
414
|
{ name = "pico-cli-sdk" },
|
|
@@ -437,7 +437,7 @@ dev = [
|
|
|
437
437
|
|
|
438
438
|
[[package]]
|
|
439
439
|
name = "pico-cli-ai"
|
|
440
|
-
version = "0.1.
|
|
440
|
+
version = "0.1.2"
|
|
441
441
|
source = { editable = "packages/pico_ai" }
|
|
442
442
|
dependencies = [
|
|
443
443
|
{ name = "httpx" },
|
|
@@ -452,7 +452,7 @@ requires-dist = [
|
|
|
452
452
|
|
|
453
453
|
[[package]]
|
|
454
454
|
name = "pico-cli-core"
|
|
455
|
-
version = "0.1.
|
|
455
|
+
version = "0.1.2"
|
|
456
456
|
source = { editable = "packages/pico_core" }
|
|
457
457
|
dependencies = [
|
|
458
458
|
{ name = "httpx" },
|
|
@@ -469,7 +469,7 @@ requires-dist = [
|
|
|
469
469
|
|
|
470
470
|
[[package]]
|
|
471
471
|
name = "pico-cli-sdk"
|
|
472
|
-
version = "0.1.
|
|
472
|
+
version = "0.1.2"
|
|
473
473
|
source = { editable = "packages/pico_sdk" }
|
|
474
474
|
dependencies = [
|
|
475
475
|
{ name = "pico-cli-ai" },
|
|
@@ -486,7 +486,7 @@ requires-dist = [
|
|
|
486
486
|
|
|
487
487
|
[[package]]
|
|
488
488
|
name = "pico-cli-tui"
|
|
489
|
-
version = "0.1.
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|