pcli-agent 0.1.0__py3-none-any.whl

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 (130) hide show
  1. pcli/__init__.py +1 -0
  2. pcli/__main__.py +4 -0
  3. pcli/agent/__init__.py +0 -0
  4. pcli/agent/activity.py +116 -0
  5. pcli/agent/compaction.py +205 -0
  6. pcli/agent/context_pruning.py +88 -0
  7. pcli/agent/headless.py +209 -0
  8. pcli/agent/loop.py +442 -0
  9. pcli/agent/prompt.py +371 -0
  10. pcli/agent/runtime.py +240 -0
  11. pcli/browser/__init__.py +0 -0
  12. pcli/browser/session.py +135 -0
  13. pcli/cli.py +757 -0
  14. pcli/config/__init__.py +0 -0
  15. pcli/config/paths.py +95 -0
  16. pcli/config/settings.py +435 -0
  17. pcli/cost/__init__.py +0 -0
  18. pcli/cost/context.py +275 -0
  19. pcli/cost/context_detect.py +183 -0
  20. pcli/cost/pricing_table.py +141 -0
  21. pcli/cost/tracker.py +126 -0
  22. pcli/llm/__init__.py +0 -0
  23. pcli/llm/client.py +285 -0
  24. pcli/llm/errors.py +37 -0
  25. pcli/llm/models.py +100 -0
  26. pcli/llm/streaming.py +108 -0
  27. pcli/memory/__init__.py +0 -0
  28. pcli/memory/extraction.py +106 -0
  29. pcli/memory/models.py +103 -0
  30. pcli/memory/store.py +88 -0
  31. pcli/permissions/__init__.py +0 -0
  32. pcli/permissions/guardrails.py +219 -0
  33. pcli/permissions/manager.py +215 -0
  34. pcli/permissions/policy.py +70 -0
  35. pcli/sandbox/__init__.py +0 -0
  36. pcli/sandbox/base.py +50 -0
  37. pcli/sandbox/docker_backend.py +107 -0
  38. pcli/sandbox/limits.py +63 -0
  39. pcli/sandbox/null_backend.py +92 -0
  40. pcli/sandbox/selector.py +75 -0
  41. pcli/sandbox/subprocess_backend.py +376 -0
  42. pcli/scheduler/__init__.py +0 -0
  43. pcli/scheduler/daemon.py +194 -0
  44. pcli/scheduler/models.py +97 -0
  45. pcli/scheduler/runner.py +84 -0
  46. pcli/scheduler/store.py +75 -0
  47. pcli/scheduler/triggers.py +84 -0
  48. pcli/session/__init__.py +0 -0
  49. pcli/session/audit.py +122 -0
  50. pcli/session/directory_check.py +28 -0
  51. pcli/session/export.py +57 -0
  52. pcli/session/importer.py +92 -0
  53. pcli/session/models.py +168 -0
  54. pcli/session/store.py +127 -0
  55. pcli/telegram/__init__.py +0 -0
  56. pcli/telegram/bot.py +266 -0
  57. pcli/telegram/daemon.py +1197 -0
  58. pcli/telegram/permissions.py +131 -0
  59. pcli/telegram/sender.py +58 -0
  60. pcli/tools/__init__.py +0 -0
  61. pcli/tools/_nested_agent.py +204 -0
  62. pcli/tools/agent_tools.py +264 -0
  63. pcli/tools/agent_tools_store.py +69 -0
  64. pcli/tools/artifacts.py +47 -0
  65. pcli/tools/base.py +185 -0
  66. pcli/tools/builtin/__init__.py +0 -0
  67. pcli/tools/builtin/agent_tool_register_tool.py +100 -0
  68. pcli/tools/builtin/artifact_tool.py +212 -0
  69. pcli/tools/builtin/ask_tool.py +77 -0
  70. pcli/tools/builtin/browser_tool.py +253 -0
  71. pcli/tools/builtin/decision_tool.py +73 -0
  72. pcli/tools/builtin/describe_tool.py +389 -0
  73. pcli/tools/builtin/diff_tools.py +225 -0
  74. pcli/tools/builtin/fs_tools.py +371 -0
  75. pcli/tools/builtin/grep_tool.py +88 -0
  76. pcli/tools/builtin/memory_tool.py +108 -0
  77. pcli/tools/builtin/network_tools.py +107 -0
  78. pcli/tools/builtin/pip_tool.py +106 -0
  79. pcli/tools/builtin/shell_tool.py +240 -0
  80. pcli/tools/builtin/subagent_tool.py +146 -0
  81. pcli/tools/builtin/todo_tool.py +122 -0
  82. pcli/tools/builtin/toolbox_register_tool.py +76 -0
  83. pcli/tools/builtin/web_tools.py +322 -0
  84. pcli/tools/pydiscovery/__init__.py +0 -0
  85. pcli/tools/pydiscovery/cache.py +51 -0
  86. pcli/tools/pydiscovery/index.py +48 -0
  87. pcli/tools/pydiscovery/invoke.py +181 -0
  88. pcli/tools/pydiscovery/search.py +117 -0
  89. pcli/tools/registry.py +138 -0
  90. pcli/tools/toolbox/__init__.py +0 -0
  91. pcli/tools/toolbox/introspect.py +48 -0
  92. pcli/tools/toolbox/manager.py +336 -0
  93. pcli/tools/toolbox/plugin_base.py +51 -0
  94. pcli/tools/toolbox/plugins/__init__.py +6 -0
  95. pcli/tools/toolbox/plugins/httpd.py +99 -0
  96. pcli/tools/toolbox/plugins/kafka.py +162 -0
  97. pcli/tools/toolbox/plugins/kubectl.py +211 -0
  98. pcli/tools/toolbox/plugins/sge.py +146 -0
  99. pcli/tools/toolbox/store.py +65 -0
  100. pcli/tools/toolbox/synthesize.py +100 -0
  101. pcli/tui/__init__.py +0 -0
  102. pcli/tui/app.py +37 -0
  103. pcli/tui/screens/__init__.py +0 -0
  104. pcli/tui/screens/ask_question_modal.py +54 -0
  105. pcli/tui/screens/chat.py +2070 -0
  106. pcli/tui/screens/confirm_modal.py +39 -0
  107. pcli/tui/screens/models.py +43 -0
  108. pcli/tui/screens/permission_modal.py +71 -0
  109. pcli/tui/screens/sessions.py +162 -0
  110. pcli/tui/screens/subagent_activity_modal.py +71 -0
  111. pcli/tui/shell_passthrough.py +56 -0
  112. pcli/tui/styles/pcli.tcss +241 -0
  113. pcli/tui/themes.py +84 -0
  114. pcli/tui/widgets/__init__.py +0 -0
  115. pcli/tui/widgets/chat_input.py +240 -0
  116. pcli/tui/widgets/command_suggestions.py +33 -0
  117. pcli/tui/widgets/message_view.py +328 -0
  118. pcli/tui/widgets/paste_input.py +99 -0
  119. pcli/tui/widgets/paste_marker.py +69 -0
  120. pcli/tui/widgets/status_bar.py +133 -0
  121. pcli/tui/widgets/status_pane.py +58 -0
  122. pcli/util/__init__.py +0 -0
  123. pcli/util/ids.py +15 -0
  124. pcli/util/logging.py +18 -0
  125. pcli/util/text.py +10 -0
  126. pcli_agent-0.1.0.dist-info/METADATA +259 -0
  127. pcli_agent-0.1.0.dist-info/RECORD +130 -0
  128. pcli_agent-0.1.0.dist-info/WHEEL +4 -0
  129. pcli_agent-0.1.0.dist-info/entry_points.txt +2 -0
  130. pcli_agent-0.1.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,58 @@
1
+ """Scrollable pane showing the live todo list. Lives above the message
2
+ history (not part of it) so it doesn't scroll away with the conversation.
3
+ 4 lines of todos visible by default (#status-pane's height in pcli.tcss is
4
+ 5 — 4 content rows plus the 1-row border-bottom) but genuinely scrollable
5
+ when there are more todos than that — and auto-scrolls to keep whichever
6
+ task is 'in_progress' visible whenever the list changes. Collapses to
7
+ nothing when there are no todos. (Subagent progress lives in StatusBar's
8
+ second line, not here.)"""
9
+
10
+ from __future__ import annotations
11
+
12
+ from rich.text import Text
13
+ from textual.containers import VerticalScroll
14
+ from textual.reactive import reactive
15
+ from textual.widgets import Static
16
+
17
+ from pcli.session.models import TodoItem
18
+ from pcli.tui.widgets.status_bar import truncate
19
+
20
+ _STATUS_ICONS = {"pending": "○", "in_progress": "▶", "completed": "✓"}
21
+ _STATUS_STYLES = {"pending": "", "in_progress": "bold", "completed": "dim"}
22
+
23
+
24
+ class StatusPane(VerticalScroll):
25
+ todos: reactive[list[TodoItem]] = reactive(list)
26
+
27
+ def on_mount(self) -> None:
28
+ self._sync_visibility()
29
+
30
+ async def watch_todos(self, todos: list[TodoItem]) -> None:
31
+ await self.remove_children()
32
+ in_progress_widget: Static | None = None
33
+ for todo in todos:
34
+ widget = Static(
35
+ Text(
36
+ f"{_STATUS_ICONS.get(todo.status, '?')} {truncate(todo.content, 76)}",
37
+ style=_STATUS_STYLES.get(todo.status, ""),
38
+ ),
39
+ classes="status-pane-todo",
40
+ )
41
+ # Static.render() returns an internal RichVisual wrapper, not the
42
+ # raw Text — stash the source item directly for testability
43
+ # rather than fighting that (same workaround MessageView uses).
44
+ widget.todo = todo
45
+ await self.mount(widget)
46
+ if todo.status == "in_progress":
47
+ in_progress_widget = widget
48
+
49
+ self._sync_visibility()
50
+ # Deferred to after layout has settled, same pattern Textual's own
51
+ # Collapsible uses for its post-toggle auto-scroll.
52
+ if in_progress_widget is not None:
53
+ self.call_after_refresh(in_progress_widget.scroll_visible, animate=False)
54
+ else:
55
+ self.call_after_refresh(self.scroll_home, animate=False)
56
+
57
+ def _sync_visibility(self) -> None:
58
+ self.styles.display = "block" if self.todos else "none"
pcli/util/__init__.py ADDED
File without changes
pcli/util/ids.py ADDED
@@ -0,0 +1,15 @@
1
+ """Sortable id generation, without pulling in a ULID dependency.
2
+
3
+ Ids are `<13 hex digits of epoch-millis><10 hex digits of randomness>` so that
4
+ lexicographic sort order matches creation order at millisecond resolution.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import secrets
10
+ import time
11
+
12
+
13
+ def new_id(prefix: str = "") -> str:
14
+ millis = int(time.time() * 1000)
15
+ return f"{prefix}{millis:013x}{secrets.token_hex(5)}"
pcli/util/logging.py ADDED
@@ -0,0 +1,18 @@
1
+ """Logging setup. File-based only — stdout/stderr are owned by the Textual TUI."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import logging
6
+ from pathlib import Path
7
+
8
+ from pcli.config.paths import data_dir
9
+
10
+
11
+ def configure_logging(*, verbose: bool = False) -> Path:
12
+ log_path = data_dir() / "pcli.log"
13
+ logging.basicConfig(
14
+ filename=str(log_path),
15
+ level=logging.DEBUG if verbose else logging.INFO,
16
+ format="%(asctime)s %(levelname)s %(name)s: %(message)s",
17
+ )
18
+ return log_path
pcli/util/text.py ADDED
@@ -0,0 +1,10 @@
1
+ """Small, dependency-free text helpers shared across layers (TUI widgets,
2
+ agent/activity tracking, ...) that shouldn't have to import from each other
3
+ just to reuse a one-line string helper."""
4
+
5
+ from __future__ import annotations
6
+
7
+
8
+ def truncate(text: str, limit: int) -> str:
9
+ text = text.replace("\n", " ").strip()
10
+ return text if len(text) <= limit else text[: limit - 1].rstrip() + "…"
@@ -0,0 +1,259 @@
1
+ Metadata-Version: 2.5
2
+ Name: pcli-agent
3
+ Version: 0.1.0
4
+ Summary: An opencode-style AI coding agent CLI/TUI for Python, with a Python discovery tool and an OS/software toolbox.
5
+ Project-URL: Homepage, https://github.com/vikasna/pcli
6
+ Project-URL: Repository, https://github.com/vikasna/pcli
7
+ Project-URL: Issues, https://github.com/vikasna/pcli/issues
8
+ Author-email: Vikas NV <vikas.nv@gmail.com>
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: agent,ai,cli,coding-assistant,llm,tui
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Software Development
22
+ Requires-Python: >=3.11
23
+ Requires-Dist: httpx>=0.27
24
+ Requires-Dist: jsonschema>=4.21
25
+ Requires-Dist: platformdirs>=4.2
26
+ Requires-Dist: psutil>=5.9
27
+ Requires-Dist: pydantic-settings>=2.2
28
+ Requires-Dist: pydantic>=2.7
29
+ Requires-Dist: pyperclip>=1.8
30
+ Requires-Dist: tenacity>=8.2
31
+ Requires-Dist: textual>=0.58
32
+ Requires-Dist: typer>=0.12
33
+ Provides-Extra: browser
34
+ Requires-Dist: playwright>=1.40; extra == 'browser'
35
+ Provides-Extra: dev
36
+ Requires-Dist: mypy>=1.10; extra == 'dev'
37
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
38
+ Requires-Dist: pytest>=8.0; extra == 'dev'
39
+ Requires-Dist: respx>=0.21; extra == 'dev'
40
+ Requires-Dist: ruff>=0.4; extra == 'dev'
41
+ Requires-Dist: types-croniter>=2; extra == 'dev'
42
+ Requires-Dist: types-jsonschema>=4.21; extra == 'dev'
43
+ Requires-Dist: types-pyperclip>=1.8; extra == 'dev'
44
+ Provides-Extra: docker
45
+ Provides-Extra: schedule
46
+ Requires-Dist: croniter>=2; extra == 'schedule'
47
+ Provides-Extra: telegram
48
+ Requires-Dist: python-telegram-bot>=21; extra == 'telegram'
49
+ Provides-Extra: win
50
+ Requires-Dist: pywin32>=306; (sys_platform == 'win32') and extra == 'win'
51
+ Description-Content-Type: text/markdown
52
+
53
+ <picture>
54
+ <source media="(prefers-color-scheme: dark)" srcset="assets/logo-dark.svg">
55
+ <img src="assets/logo.svg" alt="pcli logo" width="72" height="72">
56
+ </picture>
57
+
58
+ # pcli
59
+
60
+ **An opencode-style AI coding agent, as a Python TUI, that talks to any OpenAI-compatible gateway.**
61
+
62
+ pcli is a terminal coding agent: a tool-calling agent loop with real filesystem/shell/browser access, running against your working directory, rendered in a Textual TUI. It connects to any OpenAI-compatible chat-completions endpoint — a hosted API, an aggregator, or a model running entirely on your own machine — rather than being locked to one vendor. Beyond the usual session management, cost tracking, and permission/guardrail system you'd expect from a coding agent, it adds a few things built specifically because no other agent CLI does them well: a hard, enforced per-session cost budget; a scheduler that can react to file changes and git commits, not just cron time; and an opt-in tamper-evident audit log for unattended runs in regulated environments.
63
+
64
+ See [`docs/README.md`](docs/README.md) for the full architecture reference and every per-topic doc.
65
+
66
+ ## What sets pcli apart
67
+
68
+ ### Hard session cost-budget enforcement
69
+
70
+ Most agent CLIs only *report* what a session cost after the fact. pcli can actually stop itself once a configured budget is hit — it doesn't just log an overrun, it refuses to keep spending.
71
+
72
+ The check (`cost_budget_reason`) runs at the start of **every internal LLM round-trip** inside a turn, not once per user-visible turn — so a single tool-call-heavy turn can't blow through the cap across many internal iterations before control ever returns to you. It's wired into all four places that drive an agent loop: the main TUI session, headless/scheduled runs, subagents, and memory extraction, since subagent and compaction spend fold into the same session total.
73
+
74
+ - `/budget [amount|off]` — view or set the cap live in the TUI
75
+ - `PCLI_MAX_SESSION_COST_USD` / `max_session_cost_usd` in `config.toml` — the persisted cap (unset by default: no limit)
76
+ - `pcli run --max-cost <amount>` / `pcli schedule add --max-cost <amount>` — a per-invocation override that never touches the persisted setting
77
+
78
+ ### Event-triggered scheduling
79
+
80
+ `pcli schedule` is pcli's own recurring-task daemon, and it isn't limited to cron timing. Besides `--cron "*/15 * * * *"`, a job can be told to fire on an *event*:
81
+
82
+ - `--on-file-change <path>` — fires when a watched file or directory (hashed recursively by path/mtime/size, no contents read) changes
83
+ - `--on-git-commit [--git-repo PATH] [--git-branch NAME]` — fires when a new commit lands on a watched branch
84
+
85
+ Both still run through the same poll loop as a cron job (`pcli schedule run --poll-interval`, default 30s) — there's no OS-level file-watching integration or git hook, just a cheap check on every tick, so no new dependency was needed. The detail worth knowing before you rely on it: **self-trigger-loop prevention**. After an event job fires, the daemon doesn't reuse the signature/SHA that triggered the run as its new baseline — it re-checks *after* the job's own run finishes and stores that as the baseline instead. So a task that edits its own watched file, or commits to its own watched branch (a very plausible "auto-commit the output" pattern), does not see its own output as one more change and fire again in a loop.
86
+
87
+ ### Tamper-evident, hash-chained audit log
88
+
89
+ Opt-in (`audit_mode_enabled`, off by default — real per-tool-call overhead most users don't need). When it's on, pcli keeps a second, independent record of what a run actually did: every tool call and every permission/guardrail decision is appended as an `AuditEntry` to `Session.audit_log`, each entry's hash computed over its own fields plus the previous entry's hash — the same tamper-evidence primitive a git commit chain uses. Edit, reorder, or delete an old entry and the chain breaks from that point forward; the break can't be silently repaired without re-deriving every hash after it.
90
+
91
+ `pcli sessions verify <id>` recomputes the chain and tells you whether it's intact or exactly where it broke:
92
+
93
+ ```
94
+ $ pcli sessions verify sess_a1b2c3d4
95
+ 12 audit entries, chain valid.
96
+
97
+ $ pcli sessions verify sess_tampered
98
+ Chain broken at entry 3: entry_hash does not match the recomputed hash - this entry's content was modified after it was recorded.
99
+ ```
100
+
101
+ This is aimed at regulated-industry use — finance, healthcare, government — where someone needs to prove, after the fact, what an unattended agent did, and that the record wasn't quietly edited afterward. Turn it on for a single invocation without touching the persisted setting via `pcli run --audit` or `pcli schedule add --audit`.
102
+
103
+ ## Also notable
104
+
105
+ - **`pcli tools list`** — a static CLI listing of all 43 built-in tools, each with an audited read-only-vs-mutating classification, `needs_permission`, `plan_mode_safe`, and a one-line description. No gateway, session, or config needed to run it.
106
+ - **Toolbox plugins** — `pcli toolbox discover <name>` turns an installed OS/software CLI (kubectl, Sun Grid Engine, Kafka, Apache httpd, or anything with a `--help`) into LLM-callable tools automatically — curated plugins for the common ones, LLM-synthesized tool schemas (cached, validated) for anything else.
107
+ - **`--local-api` mode** — uncaps tool-iteration and rate-limit guardrails and forces cost to `$0` for a given local gateway, paired to that specific gateway URL rather than a global switch. Local models get first-class treatment, not an afterthought.
108
+ - **Global cross-session memory** — a small, durable profile of what pcli has learned about you (nature of work, preferences, recurring task patterns), injected into every new session's system prompt, extended automatically on compaction.
109
+ - **Real browser automation** — seven `browser_*` tools drive an actual Chromium via Playwright (click, type, wait, read, screenshot), watchable live and headed in the TUI, or headless under `pcli run`/`pcli schedule`.
110
+ - **Telegram bot front end** — `pcli telegram` runs pcli as a two-way bot with inline-button permission approval, so you can approve or deny a tool call from your phone.
111
+
112
+ ## Install
113
+
114
+ ```
115
+ pip install -e ".[dev,docker,win,browser,telegram,schedule]"
116
+ ```
117
+
118
+ Pick the extras you actually need — none of them are required for the core TUI/CLI to run:
119
+
120
+ | Extra | What it's for |
121
+ |---|---|
122
+ | `dev` | pytest, ruff, mypy — only needed for working on pcli itself. |
123
+ | `docker` | Intentionally empty — the Docker sandbox backend shells out to the `docker` CLI directly, no Python SDK needed. Just makes `pip install -e ".[docker]"` valid; requires `docker` on `PATH` at runtime. |
124
+ | `win` | `pywin32`, for Windows-specific functionality. |
125
+ | `browser` | `playwright`, for the `browser_*` tools (see below — needs a one-time extra step). |
126
+ | `telegram` | `python-telegram-bot`, for `pcli telegram`. Self-sufficient — no separate download. |
127
+ | `schedule` | `croniter`, for `pcli schedule`'s cron expression parsing. Self-sufficient — no separate download. |
128
+
129
+ If you installed the `browser` extra, Chromium itself is a separate ~300MB download, fetched once:
130
+
131
+ ```
132
+ playwright install chromium
133
+ ```
134
+
135
+ ## Quickstart
136
+
137
+ The fastest way to see pcli working needs no API key or signup at all: point it at a local model server.
138
+
139
+ With [LM Studio](https://lmstudio.ai/) (load a model, start its local server from the Developer tab — it defaults to `http://localhost:1234/v1`):
140
+
141
+ ```
142
+ pcli --gateway-url http://localhost:1234/v1 --model <model-id-from-lm-studio>
143
+ ```
144
+
145
+ With [Ollama](https://ollama.com/) (serves an OpenAI-compatible endpoint under `/v1`):
146
+
147
+ ```
148
+ pcli --gateway-url http://localhost:11434/v1 --model llama3
149
+ ```
150
+
151
+ Either way, the gateway URL and model are saved to `config.toml` on first use, so a bare `pcli` afterward reconnects without repeating the flags. Not sure of the exact model id your server expects? Launch pcli and run `/models` — it lists whatever the server reports and lets you pick one interactively.
152
+
153
+ Add `--local-api` to lift the default tool-iteration/rate-limit guardrails (sized for paid, rate-limited gateways) and force cost tracking to `$0` for that gateway:
154
+
155
+ ```
156
+ pcli --gateway-url http://localhost:1234/v1 --model <model-id> --local-api
157
+ ```
158
+
159
+ ## Connecting to a provider
160
+
161
+ **pcli's gateway client speaks the OpenAI chat-completions wire format only** — `POST {base_url}/chat/completions`, `GET {base_url}/models`. There is no native Anthropic Messages API client and no native Google Gemini API client in this codebase. This genuinely covers a lot of ground, but it's worth being precise about what it does and doesn't mean:
162
+
163
+ - **Direct, native support**: OpenAI itself, plus any server or provider that exposes an OpenAI-compatible `/v1/chat/completions` endpoint — which includes most of the ecosystem. Local servers: LM Studio, Ollama, vLLM, text-generation-webui, llama.cpp server. Hosted APIs: Groq, Mistral, DeepSeek, Together AI, Fireworks AI, and OpenRouter.
164
+ - **Not natively supported**: Anthropic's own Messages API and Google's own Gemini API use different request/response shapes than OpenAI's chat-completions format, so pcli cannot talk to `api.anthropic.com` or Google's native Gemini endpoint directly. The honest way to reach a Claude or Gemini model *through* pcli is via an OpenAI-compatible proxy or aggregator — **OpenRouter** is the simplest one, and it fronts both model families behind one OpenAI-compatible endpoint.
165
+ - **Azure OpenAI is not currently supported.** Its deployment-based URL carries a mandatory `api-version` query parameter, and pcli's gateway client always appends `/chat/completions` as a literal path segment onto `gateway_base_url` — the two don't compose into a URL Azure will accept. See the "Azure OpenAI" section below for details.
166
+
167
+ ### OpenAI
168
+
169
+ ```
170
+ # PowerShell
171
+ $env:PCLI_GATEWAY_URL = "https://api.openai.com/v1"
172
+ $env:PCLI_GATEWAY_API_KEY = "sk-..."
173
+ pcli --model gpt-4o
174
+ ```
175
+
176
+ ### LM Studio / Ollama (local)
177
+
178
+ See [Quickstart](#quickstart) above — no API key needed.
179
+
180
+ ### OpenRouter (the path to Claude, Gemini, and others)
181
+
182
+ ```
183
+ $env:PCLI_GATEWAY_URL = "https://openrouter.ai/api/v1"
184
+ $env:PCLI_GATEWAY_API_KEY = "sk-or-..."
185
+ pcli --model anthropic/claude-sonnet-4.5
186
+ ```
187
+
188
+ OpenRouter exposes one OpenAI-compatible endpoint in front of dozens of providers' models, including Anthropic's and Google's — swap `--model` for `google/gemini-2.5-pro` or any other model it hosts, and the same gateway URL/key keep working.
189
+
190
+ ### Also just works, same pattern
191
+
192
+ Groq, Mistral, DeepSeek, Together AI, and Fireworks AI all expose an OpenAI-compatible `/chat/completions` endpoint — point `gateway_base_url`/`PCLI_GATEWAY_URL` at theirs, set the matching API key, and pick one of their model ids. No special-casing needed.
193
+
194
+ ### Azure OpenAI
195
+
196
+ **Not supported.** `GatewayClient` builds an `httpx.AsyncClient` from `gateway_base_url` and then issues every request against a relative path — `POST /chat/completions`, `GET /models` — which httpx appends as a literal path segment onto whatever `gateway_base_url` is. Azure's deployment URL already ends in a mandatory `api-version` query string (e.g. `.../deployments/<deployment>?api-version=2024-02-01`), and httpx's URL-joining doesn't relocate that query string when a path is appended — it just concatenates, producing `.../deployments/<deployment>?api-version=2024-02-01/chat/completions`. That's not a valid request: `/chat/completions` ends up folded into the `api-version` value instead of becoming a real path segment, so there's no URL shape you can put in `gateway_base_url` that works. Reaching Azure-hosted models through pcli would need dedicated client-side support (a special case for the Azure URL shape); until then, use OpenAI directly or an aggregator such as OpenRouter.
197
+
198
+ ## Configuration
199
+
200
+ Settings come from environment variables, CLI flags, or `config.toml`. Precedence, highest to lowest: **CLI flags > environment variables > `config.toml` > built-in defaults**. `config.toml` lives at `<config_dir>/config.toml` (e.g. `%APPDATA%\pcli\config.toml` on Windows, `~/.config/pcli/config.toml` on Linux) — created on first access if missing.
201
+
202
+ | Setting | Env var | CLI flag | config.toml key | Default |
203
+ |---|---|---|---|---|
204
+ | Gateway base URL | `PCLI_GATEWAY_URL` | `--gateway-url` | `gateway_base_url` | `""` |
205
+ | Gateway API key | `PCLI_GATEWAY_API_KEY` | `--api-key` | `gateway_api_key` | `""` |
206
+ | Default model | `PCLI_MODEL` | `--model` | `default_model` | `""` |
207
+ | Artifact threshold (chars) | `PCLI_ARTIFACT_THRESHOLD_CHARS` | `--artifact-threshold` | `artifact_threshold_chars` | `4000` |
208
+ | Local-API gateways | `PCLI_LOCAL_API_GATEWAYS` | `--local-api` | `local_api_gateways` | `[]` |
209
+ | Hard session cost cap (USD) | `PCLI_MAX_SESSION_COST_USD` | *(none — see `pcli run --max-cost`)* | `max_session_cost_usd` | unset (no cap) |
210
+ | Tamper-evident audit log | `PCLI_AUDIT_MODE_ENABLED` | *(none — see `pcli run --audit`)* | `audit_mode_enabled` | `false` |
211
+ | Sandbox backend | `PCLI_SANDBOX_BACKEND` | *(none)* | `sandbox_backend` | `"auto"` (`auto`\|`docker`\|`subprocess`\|`none`) |
212
+ | Request timeout (s) | `PCLI_REQUEST_TIMEOUT_S` | *(none)* | `request_timeout_s` | `120.0` |
213
+ | Max tool-call iterations/turn | `PCLI_MAX_TOOL_ITERATIONS` | *(none)* | `max_tool_iterations` | `25` |
214
+
215
+ The API key is deliberately never auto-persisted to `config.toml` — pass `--api-key` or set `PCLI_GATEWAY_API_KEY` each time if your gateway needs one. The gateway URL, model, and artifact threshold *are* auto-persisted when passed as a flag, so a bare `pcli` afterward picks them up. See [`docs/configuration.md`](docs/configuration.md) for the complete settings table — this covers only the ones you're most likely to touch.
216
+
217
+ Example `config.toml`:
218
+
219
+ ```toml
220
+ gateway_base_url = "http://localhost:1234/v1"
221
+ default_model = "qwen2.5-coder-32b-instruct"
222
+ max_session_cost_usd = 5.0
223
+ sandbox_backend = "subprocess"
224
+ audit_mode_enabled = false
225
+ ```
226
+
227
+ ## FAQ
228
+
229
+ **Does my code or data ever leave my machine?**
230
+ Only to whatever gateway you've configured. Point `gateway_base_url` at a local server (LM Studio, Ollama, vLLM, ...) and nothing leaves your machine at all — pcli's own cost/pricing tables and sandbox execution are entirely local regardless of gateway. Point it at a hosted API and your conversation (including file contents the model reads) goes wherever that API sends it, same as any coding agent.
231
+
232
+ **How is this different from other AI coding agent CLIs?**
233
+ Three things specifically: a cost budget that's actually *enforced* mid-turn rather than just reported after the fact, a scheduler that can react to file changes or git commits instead of cron time alone, and an opt-in hash-chained audit log for proving what an unattended run did. See [What sets pcli apart](#what-sets-pcli-apart) above. It's also provider-agnostic by construction — any OpenAI-compatible gateway, local or hosted — rather than built around one vendor's API.
234
+
235
+ **Can I run this unattended, in CI, or on a schedule?**
236
+ Yes — `pcli run --task "..."` is a one-shot, non-interactive invocation with a proper exit code (0 on success, 1 on a hit iteration/cost cap or a usage error), suitable for cron/Task Scheduler. `pcli schedule` is pcli's own recurring-task daemon on top of the same machinery, with cron or event triggers. Both support `--max-cost` and `--audit` as safety nets for an unattended run, since there's no one present to approve a permission prompt (a tool call with no standing "Always Allow" grant is simply denied, not paused to ask).
237
+
238
+ **What stops the model from running something destructive?**
239
+ Two independent layers. Guardrails (`guardrails.toml`) are hard, non-negotiable denials — a shell command denylist, filesystem allow/deny roots, a Python module denylist — checked before any permission prompt and never bypassable by asking. On top of that, the permission system gates every tool call that isn't explicitly read-only, either against a remembered grant or an interactive prompt (fails closed with no UI, e.g. in a headless run). Underneath both, a sandbox backend (Docker, a restricted subprocess, or — only if you explicitly opt out — none) bounds what an allowed command can actually touch. See [`docs/sandbox-and-permissions.md`](docs/sandbox-and-permissions.md).
240
+
241
+ **Does it work fully offline?**
242
+ Yes, with a local gateway (LM Studio, Ollama, vLLM, ...) — no network call leaves your machine except whatever the model server itself does. `web_search`/`web_fetch`/`browser_*` are the only tools that reach the internet, and the model only calls them if it decides to.
243
+
244
+ **Does it work on Windows?**
245
+ Yes. pcli's system prompt tells the model up front that it's running on Windows and that `run_shell` executes via `cmd.exe`, not bash — no heredoc syntax, no `$VAR` expansion, chain with `&&` not `;` — rather than letting the model default to Unix assumptions and discover it's wrong by trial and error. The `win` extra (`pywin32`) covers Windows-specific functionality beyond that.
246
+
247
+ **What does it cost to run?**
248
+ Entirely up to the gateway and model you point it at — pcli has no pricing of its own, it tracks whatever a model actually costs against a best-effort pricing table you can edit. Point it at a local model with `--local-api` and it's `$0`, enforced (cost is literally zeroed, not just expected to be low, since a locally-served model's name can coincidentally match a paid builtin pricing pattern otherwise).
249
+
250
+ **Is this an editor plugin? Does it replace my IDE?**
251
+ No. pcli is a standalone terminal TUI you run alongside your editor, not a plugin inside one — it complements an IDE rather than replacing it.
252
+
253
+ ## Learn more
254
+
255
+ [`docs/README.md`](docs/README.md) is the full reference: architecture, every setting, every built-in tool, the TUI guide, sandboxing/permissions, sessions/cost, memory, headless/scheduled runs, browser automation, the Telegram bot, and the toolbox plugin system.
256
+
257
+ ## License
258
+
259
+ MIT — see [`LICENSE`](LICENSE).
@@ -0,0 +1,130 @@
1
+ pcli/__init__.py,sha256=kUR5RAFc7HCeiqdlX36dZOHkUI5wI6V_43RpEcD8b-0,22
2
+ pcli/__main__.py,sha256=isDJl60WzgfWhkwxevDbZexiMJGssXxVgk_OZ8lObOY,65
3
+ pcli/cli.py,sha256=25taOVIp12S2sBlVBp88puTuILhxG7gxBP2laz4zIE4,30176
4
+ pcli/agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ pcli/agent/activity.py,sha256=IeG3_4mNlfQfho9LlbFxzT50XimzzeFHmebWa08Vrek,4611
6
+ pcli/agent/compaction.py,sha256=q318FhQtbw62-BKJQ-hWRHPJFxWLRA7uhA2zWuWppmk,9992
7
+ pcli/agent/context_pruning.py,sha256=hhDronfQwPNg__HE1R5z5_2qfMlrrUOXku_XySAnVxc,3829
8
+ pcli/agent/headless.py,sha256=2cntupKMk97Qku3H2nPJ89Qd4eNBjBHSwn_dSwkSuCU,8972
9
+ pcli/agent/loop.py,sha256=6BrkN_ZH_y7gKzZck0K94bgwMbxnQ_6AQluzNlTfJc0,21104
10
+ pcli/agent/prompt.py,sha256=rxBltyPD-slw3Qq8WM8UP8_587JbA45NtaYz80YNT_s,26730
11
+ pcli/agent/runtime.py,sha256=Ktyqv37JdNEl-V7BvSv-bVvtiEtL8zzviYH8Pvn0un4,11332
12
+ pcli/browser/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
+ pcli/browser/session.py,sha256=-_yyC7sXPD7NRBW6lZ3OMku6-lbR-SSALtJJD8a0Dvo,5529
14
+ pcli/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
+ pcli/config/paths.py,sha256=W5KlIhm9PinBimV2xMZaCZctN8OFOIlwHFp9RQ0p_3U,2470
16
+ pcli/config/settings.py,sha256=G4wbGxeDkIHE3hdpLEWnuVhoNvHVIccmSqALfnO6JXY,21369
17
+ pcli/cost/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
+ pcli/cost/context.py,sha256=Sf5zIoxIH_rhHnH_5cc4LjUueJ0rMQmGbKSjl3XbPJo,12565
19
+ pcli/cost/context_detect.py,sha256=gibxNTY8oeW9jhqawy54xxrzKehyqjzWn3_Jb6T5__c,8181
20
+ pcli/cost/pricing_table.py,sha256=nvjkM0mGyBXals6lBC2ef58ABiuhLPDBduAl9nR0gBs,5699
21
+ pcli/cost/tracker.py,sha256=JoH6oJPIklDyz9TKAmCpdtttkBsi6AnoLUJ8RD7lme0,4706
22
+ pcli/llm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
+ pcli/llm/client.py,sha256=G5pUADuYbjHxs4usC9uk9iU3bPSrck0tXDtOSBh0Fqc,13039
24
+ pcli/llm/errors.py,sha256=C0isJtXJohdAPFBJCfZ1uR04J7BtY2bV-xRPbT1AwTw,1551
25
+ pcli/llm/models.py,sha256=31i27dJ_R_CspRqS_o6ZTZvVedkMMs-ZnGl_eqrd1Cs,2669
26
+ pcli/llm/streaming.py,sha256=tRpLLHELT4CDUIqWJOCYCeseEJdTSaQgJjtEDLDj2KE,3801
27
+ pcli/memory/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
+ pcli/memory/extraction.py,sha256=TDjzOmFh4nS0rsHza2bUVGTCGniz_IkI6VxGEE-H8mk,5603
29
+ pcli/memory/models.py,sha256=pyfSbCpsGQcevgAloOvWKwIWSyt_3fkOtJdUcDZPRSk,4415
30
+ pcli/memory/store.py,sha256=yazTnYVdNtguDwC3x4c8qtJXjjnfDs14SVTGyMsq7Xw,3233
31
+ pcli/permissions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
32
+ pcli/permissions/guardrails.py,sha256=JPESjDTvABrBQfn9ypeTvhVsyW-KmJDIYf03AVhWZ2c,8658
33
+ pcli/permissions/manager.py,sha256=xRRvB5ldsXnBkeZ8BrXcRex1JBC3NxPh2SdMwj9iDC8,8785
34
+ pcli/permissions/policy.py,sha256=THrmwzASsmcK5QIPRIW8lsmjkC-Z3A__YrHtFlNsfsQ,2379
35
+ pcli/sandbox/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
+ pcli/sandbox/base.py,sha256=JX-mfVjDuNzv9crmyMoD3i35eYQwfCdsmQ1lMZ6e85A,1233
37
+ pcli/sandbox/docker_backend.py,sha256=nK9QWca4NFQsd_D7BN2oQ9j5OhrYX08NwloUTf4qcjc,3725
38
+ pcli/sandbox/limits.py,sha256=46fi0msolGAeyZIgk3i6nXfULxopd5o1uUFy_Be4pVo,2011
39
+ pcli/sandbox/null_backend.py,sha256=qPVVqkZkw6YOF5Atgn5hiKdjH8-7Sx8q3GKJOPUBKTk,3463
40
+ pcli/sandbox/selector.py,sha256=RkQguvSA7mYHyi8Ryz3J6G0NJCBgmMPuDE0pSxLqMck,3095
41
+ pcli/sandbox/subprocess_backend.py,sha256=MyDMRvGH13Qgvi8OHlqOhXWQqc0mmlZzP7Su6MiWDl8,15527
42
+ pcli/scheduler/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
43
+ pcli/scheduler/daemon.py,sha256=kdphUQV-4alWXvdO_bg6nmaQijFxCUDew2NVfuz4LVM,7647
44
+ pcli/scheduler/models.py,sha256=kxFnY2ZYO-9l-YCvNaFFqaONDefjSunwSKQaNx-_KxY,4660
45
+ pcli/scheduler/runner.py,sha256=lw7GxYdsBKLKtDNgcev5ybMhj76LnLX1i82Ytbq451g,3088
46
+ pcli/scheduler/store.py,sha256=oNx_PEBTBUCPFBrtL7ueXgb39uTt6aXATShnx8UwTI0,2450
47
+ pcli/scheduler/triggers.py,sha256=KU_dBdMsLmyWYQO8DRA3SYgVs_5BUZNit47QDOZ8S8g,3267
48
+ pcli/session/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
49
+ pcli/session/audit.py,sha256=e_adn6dvGRVN5nCgqiLDNoaYWYoCojyBC8kI4oAw0vU,4936
50
+ pcli/session/directory_check.py,sha256=vjxVfyR6ywTMKZqi5Ud25fMmXOgkmNa6d1YnurSQoBk,1210
51
+ pcli/session/export.py,sha256=H89b2TWewaTfvGhZ2OC95b5j3KnTr_GAUPpBdwDb3U0,1710
52
+ pcli/session/importer.py,sha256=8oGKUvPj8-mjIxW_YIxQB_8CXV4Y8W2F7z8BlghrITc,3276
53
+ pcli/session/models.py,sha256=csA7JSFlOsWtvswiNsJXSYcWJkJntfXMMTRKu26u130,6306
54
+ pcli/session/store.py,sha256=4CxNgeV4e8HgaEgERTiYn_-Hz2jEABZJ16zXgEyy13U,4946
55
+ pcli/telegram/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
56
+ pcli/telegram/bot.py,sha256=JtGShbhQjIetTlfLKrRD4lSPocZnIAaHnFo1vkDcGx0,12462
57
+ pcli/telegram/daemon.py,sha256=WQ2QKsESv08mhDUiFKDdVzdz8Vvs_pzzrDakGYBwwfU,55013
58
+ pcli/telegram/permissions.py,sha256=Iyn1li5bMSqZrbxZsH1bbn16LLDcmbKUjRrApzc8-iU,5573
59
+ pcli/telegram/sender.py,sha256=WSdbKofPy4DQ8bJsGk6-iryIILGp02LuLFyAj-1PVZA,2687
60
+ pcli/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
61
+ pcli/tools/_nested_agent.py,sha256=IhXUSC57c_sdoMCyb6imVtmL6bvQQRPoM8nTgTE3BZA,9931
62
+ pcli/tools/agent_tools.py,sha256=WQSgI0UZcRfpi1nLxpSRtl3fndmzC47TsniukZit1IY,12299
63
+ pcli/tools/agent_tools_store.py,sha256=i_HNaWjQTltckNsmhRzGDN7D95ex_wXMqdCA26gTSgg,2109
64
+ pcli/tools/artifacts.py,sha256=xEOK7Zlhuhh9JlFCjhFRwWNCDrIASMdv_3z7GETeYbk,1670
65
+ pcli/tools/base.py,sha256=sMqWPajKPDOto4RTG0msjByHVDfjplRFBsku92kS8IU,9111
66
+ pcli/tools/registry.py,sha256=EWU1T4CPTwyKFTHnKVvANo3Evo7kZ985ZV5omoC5E4E,4379
67
+ pcli/tools/builtin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
68
+ pcli/tools/builtin/agent_tool_register_tool.py,sha256=-NRfP3HD02j_fTu1WIKSPbcHxzRjHF8GGTtMDK8yUJw,4223
69
+ pcli/tools/builtin/artifact_tool.py,sha256=QZKcvXMBAlVgmIR1HED02NHNSw6fMil_NYtTk_g9JCI,8907
70
+ pcli/tools/builtin/ask_tool.py,sha256=d78oEIpawm23SOd0_NVuSiZXieL9MjrVDxeGDzZJXE0,3458
71
+ pcli/tools/builtin/browser_tool.py,sha256=SIY0jPDOiY0qS8P4ARO2dqs8EQTYCNyRZjLafSOEPOM,9539
72
+ pcli/tools/builtin/decision_tool.py,sha256=Wb4h4UvujUArKXD_X6_rgETfaJc2jx3LqNHzm6q_bcI,3201
73
+ pcli/tools/builtin/describe_tool.py,sha256=PV3Qtq4sje3o9Ah_xQRup6jqquWuMemhDSvsYH4_AMI,16627
74
+ pcli/tools/builtin/diff_tools.py,sha256=YPCBJM3spvemwnuFvipuadM7FuV0E47VPhQPUVL-uVs,9426
75
+ pcli/tools/builtin/fs_tools.py,sha256=hlfmeaAYFnxV9UdfVH-DYwLsBjMZTR5UoBBRsDHdR3M,15305
76
+ pcli/tools/builtin/grep_tool.py,sha256=rfce1R3vBBceO-ZkxYukcTMqiFFZLWyQ8AifBe-y1Fo,2825
77
+ pcli/tools/builtin/memory_tool.py,sha256=wdg5bdbzCbVSFn9KrnasasukEftCnySWTVbxCywb990,5708
78
+ pcli/tools/builtin/network_tools.py,sha256=PbPkR5Hel1dgQ-i0dQHRCl7MOJRVRoTbGUdvcIFkSnU,4580
79
+ pcli/tools/builtin/pip_tool.py,sha256=cHPC6x3CAueF1DsZobr9WpEpbs2TbAhawRcIPNpunCw,4540
80
+ pcli/tools/builtin/shell_tool.py,sha256=IkuSSC2g2IkWlBxheAsaxAYXpLPtcjAF-8JKEQWEDSM,10293
81
+ pcli/tools/builtin/subagent_tool.py,sha256=8cvq9HErA5qdxAjKSXVttIyeszznp9g9CR2ptozyrao,7249
82
+ pcli/tools/builtin/todo_tool.py,sha256=JUhDiZkyT6iEOxh479ISDlRf17EH-jrdUu8KSHqXTzk,5461
83
+ pcli/tools/builtin/toolbox_register_tool.py,sha256=wwj0Q5gEb7Msktdz41oaCrlsS6GUn1JU9T0TQoydAeA,3436
84
+ pcli/tools/builtin/web_tools.py,sha256=h1B9xszkBTWOMeDMar-OgpqGWL1EBNDhMn0AII7Hijo,13752
85
+ pcli/tools/pydiscovery/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
86
+ pcli/tools/pydiscovery/cache.py,sha256=vpKLxYks7jJBDg-bL3ObNk409tlFxVw-8MtobBM8eQU,1750
87
+ pcli/tools/pydiscovery/index.py,sha256=GdD8FarNMJL2Uvgc-73AmS63PBh0WBzb2HU_p9j3QUU,1705
88
+ pcli/tools/pydiscovery/invoke.py,sha256=mlbSjpuUF-AVnWuAvBn8T-rHORd56N4zg0F7_48TZPQ,6931
89
+ pcli/tools/pydiscovery/search.py,sha256=d_AJ-IfcwwSV2vnYw8zdVyPvo5KrKvhdMrDrIXt34KA,4368
90
+ pcli/tools/toolbox/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
91
+ pcli/tools/toolbox/introspect.py,sha256=R595cd3kbT3o4hBIckTnVVdkgftboqYkkPiXPw-TbSE,1827
92
+ pcli/tools/toolbox/manager.py,sha256=1TA_yiGgNW1CLXn5t6E8PobGNQj8VdK9qwArbBv75Es,14301
93
+ pcli/tools/toolbox/plugin_base.py,sha256=dtR_9geuWNyhUI1E7Ssi-M9U4g9Vl-s0RcshCEcQ_uM,1742
94
+ pcli/tools/toolbox/store.py,sha256=qJ_kWEjdpHWIFs4-Fku524PMVgHiXLNyK09oGo8x_yU,1915
95
+ pcli/tools/toolbox/synthesize.py,sha256=0EYpAJh6yFtAyiA_hVywt8UpPenku5-eZ3XTJCTYyG8,3989
96
+ pcli/tools/toolbox/plugins/__init__.py,sha256=UPFhX7qiQwVTNV-H5Vf0VBz8x6JLB7AWRjIdlRdjs_Q,304
97
+ pcli/tools/toolbox/plugins/httpd.py,sha256=2Ey9A8j3HhgL0JA5RojgrGpOsOQLT6-oypkWRfsWQPk,3159
98
+ pcli/tools/toolbox/plugins/kafka.py,sha256=zVspI8sHjl30VEF9SUqwjKrBUAWOWp9xeljpnI29nWc,5743
99
+ pcli/tools/toolbox/plugins/kubectl.py,sha256=AR-nhcYYDgMsLv0y0dTF4ZVH4ThTGBOdvnERxZmpDxM,7834
100
+ pcli/tools/toolbox/plugins/sge.py,sha256=HNoPqyqPnpUb0fjVmQ7zxmTJ5-G4s-hlllkGcAS_hOg,4984
101
+ pcli/tui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
102
+ pcli/tui/app.py,sha256=U0VvTlud9ZypcK6OuHdCc0qEezFkXCAbjUUSpHM4Df4,1379
103
+ pcli/tui/shell_passthrough.py,sha256=OnrQs5XlMBScDz1fZwfuDICoUWUH6jjAxzWSF4o_Fv0,1904
104
+ pcli/tui/themes.py,sha256=SPIN2IxZY32uD5M57hKR_MHRxlTRwVEk-paTpXh4Bg8,2813
105
+ pcli/tui/screens/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
106
+ pcli/tui/screens/ask_question_modal.py,sha256=i-9UGOGngNC0ikojcWTrKwL0p9rlBpwEd4SZF4wMy28,2110
107
+ pcli/tui/screens/chat.py,sha256=_MJjMSYqEnmDr48Nyldt3XQpaQlEbvbuF4PQ0mslQMM,104017
108
+ pcli/tui/screens/confirm_modal.py,sha256=CMjVQ086gOnPmPRAVh9JO3WMGF4RMLNGgW_wMYmhIbs,1439
109
+ pcli/tui/screens/models.py,sha256=UA-MTydL4Qt3jIfXYEx5LceqRAoyJmT0vKygaT-kyNY,1619
110
+ pcli/tui/screens/permission_modal.py,sha256=cLelgwivnV3wTqLRrFS6TRMd1AgeogNVa1i6hDdBOLY,3075
111
+ pcli/tui/screens/sessions.py,sha256=r0Yoet467ug3e6rnXjl28hlzCATm3Qdh_Gw5MuTOUws,6401
112
+ pcli/tui/screens/subagent_activity_modal.py,sha256=WWbPm3oddFN1_l4dOY3gnr7wVuEod6E5IKTbLmWnepQ,3154
113
+ pcli/tui/styles/pcli.tcss,sha256=5LJ-IhAQYpTCoiBmJvx_r_SjtInMCr1NgYuhKGBMhps,4817
114
+ pcli/tui/widgets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
115
+ pcli/tui/widgets/chat_input.py,sha256=jFmEBMmpnHIYSWdjSnhcq7dfLJ3w8RxXrBzD5JdmkDk,10706
116
+ pcli/tui/widgets/command_suggestions.py,sha256=broIv_V8fDUOkLsQpMSgyaBmVr6yVBtXUu4eBuncZ68,1563
117
+ pcli/tui/widgets/message_view.py,sha256=TnWrrdC1Wk19L8rbOQguocGXsLAbw1DjHe_a0bauM3g,16030
118
+ pcli/tui/widgets/paste_input.py,sha256=NCFB3sz0ispvbnaGExnHjK6ZsLwHfXZROMlaFLPAGdI,4734
119
+ pcli/tui/widgets/paste_marker.py,sha256=imu2MVOEzlpr-9z-LX4dTuSBjyO-BT8-H_JeiabKtOc,2759
120
+ pcli/tui/widgets/status_bar.py,sha256=EWt_Ce0nZdkjis3VBjgLfxOmQeYk2TBnwCL2ub4D5rk,5648
121
+ pcli/tui/widgets/status_pane.py,sha256=dNMdVzHTS2OJwS8tPBY8M4frosCM__QziX5lbOWtnD4,2453
122
+ pcli/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
123
+ pcli/util/ids.py,sha256=JckBTMp9OehPC1Gglt_M_yz9GCx-VvyM4dLjEsax1DA,422
124
+ pcli/util/logging.py,sha256=AalmC82_M7CBAA25SrgYcFP4CN9ZHzsf5Si1M8hrC5k,507
125
+ pcli/util/text.py,sha256=Q-V-9XmnBqjgVMJyvnDSVhSGwDqJbMca5ESjJquBTcQ,396
126
+ pcli_agent-0.1.0.dist-info/METADATA,sha256=XAGhxsQWvrtIttD9kIdRBkzeYrV7HuRN3MLR3iMFtwM,20098
127
+ pcli_agent-0.1.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
128
+ pcli_agent-0.1.0.dist-info/entry_points.txt,sha256=y6bOir3KKLNCxfH280hsOQew1GNWP9XMBFzdCR6eqJI,39
129
+ pcli_agent-0.1.0.dist-info/licenses/LICENSE,sha256=3L0BW_GvFn7GGmL8VNl6sCEzQ4HRlqyrWyZ-ZVUqdQU,1065
130
+ pcli_agent-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.32.4
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ pcli = pcli.cli:main
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Vikas NV
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.