@pithosai/pithosai 1.0.0

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.
package/README.md ADDED
@@ -0,0 +1,456 @@
1
+ # Pithosai (pi-agent)
2
+
3
+ Pithosai is a CLI that implements code or projects from a natural-language request. Role prompts are loaded from the SQLite DB at runtime (with optional fallback to `.pithosai/<role>/*.md`). A project-local `.pithosai/` directory holds role-specific prompt files when used and persists conversation sessions under `.pithosai/sessions/`.
4
+
5
+ **Requirements:** Node.js (ESM), and a model provider — Cursor CLI (browser auth, no API key), DeepSeek API key, or OpenRouter API key.
6
+
7
+ ---
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ npm install
13
+ ```
14
+
15
+ Set up at least one model provider:
16
+
17
+ - **Cursor CLI** (recommended — no API key needed):
18
+ ```bash
19
+ curl https://cursor.com/install -fsS | bash
20
+ cursor-agent login
21
+ export CURSOR_MODEL=auto # or: sonnet-4.6, opus-4.6, gpt-5.2
22
+ ```
23
+ - **DeepSeek:** `export DEEPSEEK_API_KEY=sk-...`
24
+ - **OpenRouter:** `export OPENROUTER_API_KEY=sk-or-...`
25
+
26
+ Provider priority: `CURSOR_MODEL` / `--cursor` > `DEEPSEEK_API_KEY` > `OPENROUTER_API_KEY`.
27
+
28
+ ---
29
+
30
+ ## Docker
31
+
32
+ If you want to build the Docker image, please git clone a new project from the repo, then run the following command:
33
+
34
+ ```bash
35
+ docker build --no-cache -t pithosai .
36
+ ```
37
+
38
+ **Important:** Never share the project directory that is used by the non-Docker runtime.
39
+
40
+ ---
41
+
42
+ ## Quick start
43
+
44
+ 1. **Create a project**
45
+
46
+ ```bash
47
+ pithosai init
48
+ # or: pithosai init my-app --type js
49
+ # or: pithosai init ./backend --type ts --lang zh --role RD
50
+ ```
51
+
52
+ This creates the target directory (if needed), scaffolds by project type (`--type js|ts|python`) and role (`--role RD|PM|QA|CO|SRE` and other template roles), creates `.pithosai/sessions/`, and writes `.settings.json` (lang, project, supportedRoles, tools). Role prompts are loaded from the SQLite DB at runtime; no prompt files are copied into the project by default. For PM, QA, CO, MKT, or SRE roles, a starter `rules/requirements.md` is created for you to fill in.
53
+
54
+ 2. **Run a request**
55
+
56
+ ```bash
57
+ pithosai "Add a REST endpoint that returns the current time"
58
+ pithosai -C ./my-app "Run tests and fix failures"
59
+ pithosai "Refactor the auth module" --cursor # use Cursor models (auto)
60
+ pithosai --cursor sonnet-4.6 "Explain this codebase" # specific Cursor model
61
+ ```
62
+
63
+ By default, after the agent replies you get an interactive session to type more requests. Type `exit` or `quit` to leave.
64
+
65
+ 3. **Interactive-only mode (no initial request)**
66
+
67
+ ```bash
68
+ pithosai -i
69
+ ```
70
+
71
+ **Terminal UI (TTY):** When both stdin and stdout are TTYs, the default run command uses **`@mariozechner/pi-tui`**: the **input area stays at the bottom** in a **boxed Editor** (no `You:` prefix on the prompt), **assistant output streams above**, and a **loading row** sits **just above the input box** while the model is working. When output hits the transcript, that row **switches to a simpler running indicator** (same idea as the stderr spinner in non-TUI mode) and **stays until the run finishes**, instead of disappearing immediately. While the TUI is up, **CWD/request banners and run status go through the transcript sink** (and the **log file** via the file-only logger), not raw stdout, so **extra `process.stdout` traffic does not paint over the full-screen layout**; **Ctrl+S** and **Ctrl+P** notices are **appended to the transcript** instead of raw stdout. **Run failures** (including guard timeouts), **dialog/plan `success: false` errors**, and **failed result previews** are **appended to the transcript in red** so they stay visible without corrupting the layout. Slash-command output, `/list` tables, and `/shell` results are drawn in the same transcript (multi-line `/list` output is split into real rows and the view **scrolls to the table header**; use the **mouse wheel**, **arrow keys**, **PgUp/PgDn**, or **Ctrl+U / Ctrl+F** (page) to scroll long output, **including while the agent is running** (**Ctrl+U/Ctrl+F** scroll the log instead of the editor’s usual line-edit shortcuts; **Ctrl+D** remains EOF / exit on an empty line). Set **`PITHOSAI_NO_TUI=1`** to use the classic readline **`You:`** line instead (e.g. scripts or SSH without a proper terminal).
72
+
73
+ In **`agent`** mode (default), prints CWD and short tips (full tools, task-scoped history in the local DB, `/new`, `/shell`, `/list`, `/show`, `/show-task [index]`, `/show-prompt`, **`/list-skill`**, **`/install-skill`**, **`/remove-skill`** — same behavior as `pithosai skills list`, `install`, and `remove` — keyboard controls), then prompts for input. **`dialog`** and **`plan`** show their own tips. After the banner, all three modes start the same input loop when interactive is enabled (plan keeps transcript output minimal until each plan file is written). **Tab** completes slash commands (e.g. `/list`, `/list-skill`, `/show`, `/show-prompt`, `/show-task`, `/install-skill`, `/remove-skill`) and `exit` / `quit` in both the pi-tui **Editor** prompt (dropdown + Enter to apply) and **readline** mode; **`/shell`** is only offered in **agent** mode. Typing **`/`** also opens the slash menu as you continue the command. The pause sub-prompt still uses readline **Tab** for `continue` / `c` and `exit` / `e`.
74
+
75
+ While an agent run is in progress, keyboard controls are available:
76
+ - `Ctrl+S` — stop current run and return to prompt
77
+ - `Ctrl+P` — pause current run and enter pause sub-prompt
78
+ - `continue` / `c` resumes with current request
79
+ - `exit` / `e` exits the CLI
80
+ - any other non-empty input replaces the pending request
81
+
82
+ 4. **One-shot (no follow-up prompt)**
83
+
84
+ ```bash
85
+ pithosai --no-interactive "One request only"
86
+ ```
87
+
88
+ 5. **Run variant (`--mode`)**
89
+
90
+ The default command supports a run variant:
91
+
92
+ | Mode | Behavior |
93
+ |------|----------|
94
+ | `agent` (default) | Answer and use tools (implement, run commands via tools, etc.). |
95
+ | `dialog` | Answer-focused mode with **read-only tools only** (`read`, `list_files`, `read_pdf`, `web_fetch`, `web_search`, `proxy_downloader`, `read_email`). `/shell` is disabled; `/list`, `/select`, `/show`, `/show-prompt`, `/show-task [index]`, `/list-skill`, `/install-skill`, and `/remove-skill` still work. |
96
+ | `plan` | Writes the model reply only to `<slug>-plan.md` in the **project root** (`-C` / cwd). Same **read-only tools** as dialog; `/shell` is disabled. `/list`, `/select`, `/show`, `/show-prompt`, `/show-task [index]`, `/list-skill`, `/install-skill`, and `/remove-skill` work like dialog. With `-i`, the follow-up prompt runs another plan per line (output stays minimal in the UI until each run completes). |
97
+
98
+ **Note:** In `plan` mode the run uses a **discard output sink** by default, so you often will not see streamed tokens in the terminal until the model finishes (or times out). While waiting, a **spinner on stderr** shows progress; when anything writes to **stdout**, the line **switches to a lighter running spinner** (TTY) until the run completes, instead of being cleared immediately. On a non-TTY stderr, the spinner **stops** on first stdout as before. The default max run time is **30 minutes** (`AGENT_RUN_TIMEOUT_MS`); pass `--timeout <seconds>` for a shorter cap.
99
+
100
+ **Dialog / plan result preview:** After each run completes, **dialog** and **plan** open a full-screen terminal viewer built on **`@mariozechner/pi-tui`** (`Markdown` with the same themed styling as **pi** via **`@mariozechner/pi-coding-agent`**’s `getMarkdownTheme`): scroll with **↑↓** or **j**/**k**, **PgUp**/**PgDn** or **Ctrl+U**/**Ctrl+D**, **Home**/**End**, **gg** (top), or **G** (bottom); press **q**, **Esc**, or **Ctrl+C** to close. While the preview is open, the interactive agent TUI is suspended so those keys only affect the viewer. If stdin/stdout are not both TTY (e.g. CI), the raw markdown is printed to stdout instead. If you set `PITHOSAI_RESULT_BROWSER=chrome`, preview switches to the browser viewer implemented with Playwright and rendered as **WeChat-style HTML** (inline styles, same pipeline as the `markdown_to_html` tool with `forWechat: true`). In Chrome mode the page includes a **Copy markdown** button (copies the raw markdown via the Clipboard API, with a textarea fallback) and **Close** (closes the whole preview browser via Playwright, not only the tab—needed so Chrome does not keep an empty window after the last tab closes). Content is passed in memory via `page.setContent` (no temp file). The Chrome window is opened with **Chromium app mode** (`--app=about:blank` plus a few flags) using Playwright’s **`launchPersistentContext`** so the omnibox and tab strip stay hidden—plain `browser.newPage()` would open a normal Chrome window and ignore app mode. Only your page content and the in-page toolbar are shown (standard window title bar may still appear). Chrome mode defaults to **Google Chrome stable** (`channel: chrome`) and falls back to bundled Chromium if Chrome is missing (install with `npm run playwright:install` / `npx playwright install chromium`). To always use the bundled browser in Chrome mode, set `PITHOSAI_PLAYWRIGHT_CHANNEL=bundled`. Other channels (e.g. `msedge`, `chrome-beta`) are supported via the same variable. To disable preview (e.g. CI), set `PITHOSAI_SKIP_RESULT_BROWSER=1`.
101
+
102
+ In **`agent`** mode the model may call the **`playwright_view_markdown`** tool to open the same Playwright preview from **either** raw `markdown` **or** a project `path` to a `.md` file (exactly one of the two). The tool blocks until the user closes the preview window and respects `PITHOSAI_SKIP_RESULT_BROWSER` and `PITHOSAI_PLAYWRIGHT_CHANNEL`. It is **not** available in `dialog` / `plan` read-only toolsets.
103
+
104
+ ```bash
105
+ pithosai --mode dialog "Explain this stack trace"
106
+ pithosai -C ./my-app --mode plan "Sprint plan for the API work"
107
+ pithosai -l zh --mode plan --timeout 120 "迭代计划"
108
+ ```
109
+
110
+ 6. **Shell commands in interactive mode**
111
+
112
+ ```bash
113
+ pithosai -i
114
+ You: /shell ls -la
115
+ You: /shell git status
116
+ You: /shell npm test
117
+ ```
118
+
119
+ Prefix commands with `/shell` to execute shell commands directly.
120
+
121
+ The same prompt also supports **task-scoped commands** (conversation rows live in the local SQLite DB): `/list` lists persisted tasks as a markdown table (`index`, `task id`, `task title`, `description`, `createTime`); `/select <index>` selects the active task id, prints a selected-task line, and then shows current task stats (`/show`); `/show` prints current task stats; **`/show-prompt`** builds the system prompt for the current `--mode`, language, and role (same logic as `pithosai show-prompt`) and opens it in the same result viewer as dialog/plan, with the prompt body rendered as **markdown** (not a fenced code block); **`/show-task`** shows Q&A for the current task, and **`/show-task <index>`** shows Q&A for that persisted task index. Q&A and **`/show-prompt`** use the same configured result viewer (**pi-tui** terminal viewer by default, Playwright preview when `PITHOSAI_RESULT_BROWSER=chrome`); if `PITHOSAI_SKIP_RESULT_BROWSER=1`, markdown is printed to the terminal instead.
122
+
123
+ **Skill commands (ClawHub):** **`/list-skill`** lists installed skills under `.pithosai/skills` (like `pithosai skills list`). **`/install-skill`** with no name installs all remote skills from `clawhub list`; **`/install-skill <name>`** installs one skill; add **`--force`** to reinstall. **`/remove-skill <name>`** removes an installed skill (like `pithosai skills remove`). These use the same implementation as the `pithosai skills` CLI; `clawhub install` still uses inherited stdio when run from the REPL.
124
+
125
+ 7. **Add another role**
126
+
127
+ ```bash
128
+ pithosai add-role CO
129
+ ```
130
+
131
+ Creates `.pithosai/<role>/` if it does not exist and adds the role to `supportedRoles` in project settings. If `.pithosai/<role>/` already exists, the command returns without overwriting. Prompts are loaded from the SQLite DB at runtime (with file fallback). Use `-r CO` or project settings to select the role.
132
+
133
+ 8. **Task mode (watch and process tasks from markdown)**
134
+
135
+ ```bash
136
+ pithosai task --file prompts.md
137
+ pithosai task -C ./my-app --file prompts.md --model deepSeekCoder
138
+ ```
139
+
140
+ The task runner watches the task file and processes one task at a time (prioritizing `processing` tasks first, then `pending` tasks). During a running task:
141
+ - `Ctrl+S` stops the current task run
142
+ - `Ctrl+P` pauses and enters the same pause sub-prompt as interactive mode
143
+ - If you edit request text in pause sub-prompt, the resumed task run uses the edited text as the task request
144
+
145
+ 9. **Memorize (role memory file from persisted tasks)**
146
+
147
+ ```bash
148
+ pithosai memorize --start 2026-01-01 --end 2026-01-31 -r RD
149
+ pithosai -r PM memorize --start 2026-04-01 --end 2026-04-10 -C ./my-app
150
+ ```
151
+
152
+ Reads the local SQLite task store (`~/.pithosai/pithosai.db` unless `PITHOSAI_DB_PATH` is set), finds tasks where the **role** has persisted task messages whose timestamps fall in the inclusive date range, and writes **`.pithosai/<role>/memory.md`** with a short summary per task (title, status, contribution excerpt from assistant output, and a suggested improvement line). Dates are **YYYY-MM-DD** (whole UTC days) or full ISO datetimes. LLM summarization uses the same model selection as the default **`pithosai`** run: **`--reasoner`**, **`--chat`**, **`--cursor [model]`**, and optional **`--model <key>`** (same `KEY_TO_MODEL` keys as **`pithosai task`**). The optional LLM tightening step uses **Chinese** instructions when global **`--lang`** (or project **`lang`** in settings) is Chinese (`zh`…), and **English** otherwise. Use **`--no-llm`** or **`PITHOSAI_MEMORIZE_SKIP_LLM=1`** to write only the structured file without an LLM pass, or if the model is unavailable the command falls back to the structured markdown and prints a notice.
153
+
154
+ ---
155
+
156
+ ## Role-specific commands
157
+
158
+ Besides `pithosai`, you can use role-specific entry points. Each one runs the same CLI with a default **role** (and, for some, the **chat** model). All support the same subcommands and options as `pithosai`.
159
+
160
+ | Command | Default role | Model | Use case |
161
+ |--------|----------------|-------|----------|
162
+ | **pithosai** | RD | Coder | General coding; implement from natural language. |
163
+ | **rdsai** | RD | Coder | Same as `pithosai`; RD (e.g. R&D) coding agent. |
164
+ | **pmsai** | PM | Chat | Product/project management; uses PM templates + chat model. |
165
+ | **qasai** | QA | Chat | QA; uses QA templates + chat model. |
166
+ | **cosai** | CO | Chat | CO role; uses CO templates + chat model. |
167
+ | **mktai** | MKT | Chat | Professional marketing (positioning, GTM, campaigns); uses MKT templates + chat model. |
168
+
169
+ Examples:
170
+
171
+ ```bash
172
+ rdsai "Refactor the auth module"
173
+ pmsai "Draft a sprint plan for the API work"
174
+ qasai "Generate test cases for the login flow"
175
+ cosai -i
176
+ mktai "Pressure-test our positioning vs two named competitors; output a matrix, proof gaps, and homepage narrative fixes"
177
+ ```
178
+
179
+ You can still override role or model (e.g. `pmsai -r QA`, `qasai --reasoner`, or `rdsai --cursor`). Add a role's templates with `pithosai add-role PM` (or QA, CO, MKT, SRE, etc.) before using that role.
180
+
181
+ ---
182
+
183
+ ## Cursor CLI Integration
184
+
185
+ Use models from your Cursor subscription (Claude Sonnet/Opus, GPT-5.2, etc.) without separate API keys. Authentication is handled by the Cursor CLI's browser-based login.
186
+
187
+ **Setup (one-time):**
188
+
189
+ ```bash
190
+ # Install the Cursor agent CLI
191
+ curl https://cursor.com/install -fsS | bash
192
+
193
+ # Log in via browser
194
+ cursor-agent login
195
+
196
+ # Verify auth
197
+ cursor-agent status
198
+ ```
199
+
200
+ **Usage:**
201
+
202
+ ```bash
203
+ # Environment variable
204
+ export CURSOR_MODEL=auto
205
+ pithosai "Build a REST API"
206
+
207
+ # CLI flag (overrides env)
208
+ # Note: `--cursor` has an optional value. To avoid parsing the request as model id,
209
+ # put request before `--cursor`, or use `--` as separator.
210
+ pithosai "Explain this code" --cursor
211
+ pithosai --cursor -- "Explain this code"
212
+ pithosai --cursor sonnet-4.6 "Refactor auth module"
213
+ pithosai --cursor opus-4.6 "Design a database schema"
214
+ pithosai --cursor gpt-5.2 "Write unit tests"
215
+ ```
216
+
217
+ **Available models:**
218
+
219
+ | Model id | Description |
220
+ |----------|-------------|
221
+ | `auto` | Cursor's default model selection |
222
+ | `sonnet-4.6` | Claude Sonnet 4.6 |
223
+ | `sonnet-4.6-thinking` | Claude Sonnet 4.6 with extended thinking |
224
+ | `opus-4.6` | Claude Opus 4.6 |
225
+ | `gpt-5.2` | GPT 5.2 |
226
+
227
+ Any model id supported by `cursor-agent --list-models` can be used; the above are pre-defined with metadata. Unknown ids are passed through to `cursor-agent` as-is.
228
+
229
+ ---
230
+
231
+ ## Heartbeat
232
+
233
+ Heartbeat polls the role's email inbox for **task emails** (subjects starting with `task:` or `任务:`), enqueues them, and runs the agent on one task per tick. State (processed IDs and unprocessed queue) is stored in `~/.pithosai/heartbeat-state.json` and is keyed by role and optionally by project.
234
+
235
+ **Requirements:** The role must have IMAP/SMTP configured in `.settings.json` (see `roles.<role>.imap` and `roles.<role>.smtp`). After each task the agent sends a reply email: on success to the task sender; on failure to the support address (see `SUPPORT_EMAIL` below).
236
+
237
+ - **One tick (fetch + process one task, then exit):**
238
+ ```bash
239
+ pithosai heartbeat --once
240
+ ```
241
+ - **Continuous loop (poll every N seconds):**
242
+ ```bash
243
+ pithosai heartbeat
244
+ pithosai heartbeat --interval 120
245
+ ```
246
+
247
+ You can pass `-C`, `-r`, `-l`, `--reasoner`, `--chat`, `--cursor`, `--timeout`, etc. as with other commands. Programmatic API: `heartbeatTick(cwd, runOpts)` runs one tick and returns `{ processedCount, ranOne, unprocessedCount }`; `heartbeatLoop(cwd, opts)` runs the loop with `opts.intervalSeconds` (default 60).
248
+
249
+ ---
250
+
251
+ ## Skills Management
252
+
253
+ Install, list, and remove AI skills from Clawhub AI. Skills are stored in `.pithosai/skills/` and can be used by agents via the `read_skill` tool. `clawhub install` output and install/list status messages are written to **stdout** / **stderr** in the terminal (not only to the log file).
254
+
255
+ **Requirements:** ScraperAPI account and API key (set as `SCRAPERAPI_API_KEY` environment variable).
256
+
257
+ - **Install skills:**
258
+ ```bash
259
+ pithosai skills install
260
+ pithosai skills install greet --api-key your_key
261
+ pithosai skills install --force --url https://custom-skills.example.com
262
+ ```
263
+ - **List installed skills:**
264
+ ```bash
265
+ pithosai skills list
266
+ pithosai skills list -l zh
267
+ ```
268
+ - **Remove skill:**
269
+ ```bash
270
+ pithosai skills remove greet
271
+ ```
272
+
273
+ See [Skills CLI Documentation](docs/SKILLS-CLI.md) for complete usage.
274
+
275
+ ---
276
+
277
+ ## Skill Conversion
278
+
279
+ Automatically convert frequently used skills into permanent tools for better performance and reliability. The system monitors skill usage, analyzes patterns, and generates optimized tool implementations.
280
+
281
+ **Features:**
282
+ - **Usage Tracking**: Automatically records skill executions, parameters, and success rates
283
+ - **Pattern Analysis**: Identifies common parameter combinations and usage patterns
284
+ - **Smart Conversion**: Suggests when skills are ready for conversion based on usage statistics
285
+ - **Tool Generation**: Creates optimized JavaScript tools with proper parameter validation
286
+ - **Performance Boost**: Converted tools run 50-80% faster than skill-based execution
287
+
288
+ **Usage:**
289
+
290
+ - **List convertible skills:**
291
+ ```bash
292
+ pithosai skill-convert list
293
+ pithosai skill-convert list --threshold 70
294
+ ```
295
+
296
+ - **Convert a skill:**
297
+ ```bash
298
+ pithosai skill-convert convert screenshot
299
+ pithosai skill-convert convert screenshot --dry-run # Preview conversion
300
+ pithosai skill-convert convert screenshot --force # Force re-conversion
301
+ ```
302
+
303
+ - **View statistics:**
304
+ ```bash
305
+ pithosai skill-convert stats
306
+ pithosai skill-convert stats --skill screenshot
307
+ ```
308
+
309
+ - **Manage converted tools:**
310
+ ```bash
311
+ pithosai skill-convert tools list
312
+ pithosai skill-convert tools remove screenshot_tool
313
+ pithosai skill-convert tools enable/disable screenshot_tool
314
+ ```
315
+
316
+ - **Clear records:**
317
+ ```bash
318
+ pithosai skill-convert clear screenshot
319
+ pithosai skill-convert clear --all
320
+ ```
321
+
322
+ **How it works:**
323
+ 1. When you use skills via `read_skill`, the system tracks each execution
324
+ 2. After sufficient usage (minimum 3 successful executions), skills become eligible for conversion
325
+ 3. The system analyzes parameter patterns and generates optimized tool code
326
+ 4. Converted tools are stored in `.pithosai/custom-tools/` and automatically loaded
327
+ 5. Future requests use the optimized tool instead of reading skill documentation
328
+
329
+ **Example workflow:**
330
+ ```bash
331
+ # 1. Use a skill multiple times
332
+ pithosai "Take a screenshot of the terminal"
333
+ pithosai "Capture the browser window after 2 seconds"
334
+ pithosai "Take a screenshot of a specific region"
335
+
336
+ # 2. Check if it's ready for conversion
337
+ pithosai skill-convert list
338
+
339
+ # 3. Convert to permanent tool
340
+ pithosai skill-convert convert screenshot
341
+
342
+ # 4. Use the optimized tool directly
343
+ # (The agent will now use screenshot_tool instead of read_skill screenshot)
344
+ pithosai "Take another screenshot with delay"
345
+ ```
346
+
347
+ See [Skill-to-Tool Design](docs/SKILL-TO-TOOL-DESIGN.md) for technical details.
348
+
349
+ ---
350
+
351
+ ## Shell Command
352
+
353
+ Execute shell commands directly or from interactive mode. Useful for file operations, git commands, and system tasks.
354
+
355
+ - **Standalone command:**
356
+ ```bash
357
+ pithosai shell "ls -la"
358
+ pithosai shell "git status" --cwd ./my-project
359
+ pithosai shell "npm test" --timeout 60
360
+ pithosai shell --raw "echo hello"
361
+ ```
362
+ - **Interactive mode:**
363
+ ```
364
+ You: /shell ls -la
365
+ ```
366
+ Use `/shell` prefix in interactive sessions to run shell commands.
367
+
368
+ See [Shell CLI Documentation](docs/SHELL-CLI.md) for complete usage.
369
+
370
+ ---
371
+
372
+ ## Commands and options
373
+
374
+ | Command / option | Description |
375
+ |------------------|-------------|
376
+ | `pithosai [request]` | Run the agent for `request`. Omit to show help (or use `-i` for interactive mode). |
377
+ | `pithosai init [dir]` | Create project: scaffold by type/role, `.pithosai/sessions/`, and settings. Prompts loaded from SQLite at runtime. |
378
+ | `pithosai add-role <role>` | Add role: create `.pithosai/<role>/` if missing and update `supportedRoles`. |
379
+ | `pithosai skills` | Manage skills from Clawhub AI (install, list, remove). |
380
+ | `pithosai skill-convert` | Convert successful skills to permanent tools (monitor usage, analyze patterns, generate tools). |
381
+ | `pithosai shell <command>` | Execute shell commands with timeout and formatting. |
382
+ | `pithosai task` | Watch a task markdown file and process tasks sequentially (`processing` first, then `pending`). |
383
+ | `pithosai heartbeat` | Poll inbox for task emails (`task:...` / `任务:...`), enqueue and run one per tick. State in `~/.pithosai/heartbeat-state.json`. |
384
+ | `pithosai heartbeat --once` | Run one tick (fetch emails, process one task if any) then exit. |
385
+ | `pithosai heartbeat --interval <seconds>` | Poll interval in seconds (default: 60). |
386
+ | `pithosai show-prompt` | Display the system prompt that would be used for a run. Options: `--mode <agent|dialog|plan>`, `--raw` (show before truncation), `--truncated` (show truncated version). |
387
+ | `-i, --interactive` | Start in interactive mode without a request; load latest session and prompt. |
388
+ | `--no-interactive` | After running a request, do not prompt for more (one-shot). |
389
+ | `-C, --cwd <dir>` | Project directory (default: current directory). |
390
+ | `-l, --lang <lang>` | Language for prompts and init (e.g. `en`, `zh`). |
391
+ | `-r, --role <role>` | Role/template set (e.g. `RD`, `CO`). |
392
+ | `--timeout <seconds>` | Max agent run time (default: 1800). |
393
+ | `--cursor [model]` | Use Cursor CLI model (no API key; auth via `cursor-agent login`). Optional model: `auto`, `sonnet-4.6`, `opus-4.6`, `gpt-5.2`. If model is omitted, use `pithosai "<request>" --cursor` (or `--cursor -- "<request>"`) to avoid argument ambiguity. |
394
+ | `--reasoner` | Use DeepSeek Reasoner (thinking) model. |
395
+ | `--chat` | Use DeepSeek Chat model (general chat). |
396
+ | `--no-markdown` | Disable terminal markdown rendering and print plain text only. |
397
+ | `--skills-dir <dir>` | Directory for `read_skill` (default: `./.pithosai/skills` or `PITHOSAI_SKILLS_DIR`). |
398
+ | `--log-path <file>` | Log file path (default: `<project>/logs/pithosai.log`). |
399
+
400
+ ---
401
+
402
+ ## Environment variables
403
+
404
+ | Variable | Description |
405
+ |----------|-------------|
406
+ | `CURSOR_MODEL` | Cursor CLI model id (e.g. `auto`, `sonnet-4.6`, `opus-4.6`, `gpt-5.2`). No API key needed — uses `cursor-agent login` auth. |
407
+ | `CURSOR_AGENT_BIN` | Path to `cursor-agent` binary (default: `cursor-agent` on `PATH`). |
408
+ | `DEEPSEEK_API_KEY` | API key for DeepSeek (Coder / Chat / Reasoner). |
409
+ | `OPENROUTER_API_KEY` | API key when using OpenRouter. |
410
+ | `SCRAPERAPI_API_KEY` | API key for ScraperAPI (used by skills command and proxy downloader). |
411
+ | `PITHOSAI_TIMEOUT_MS` | Max run time in milliseconds (overrides `--timeout` when set). |
412
+ | `PITHOSAI_SKILLS_DIR` | Default skills directory for `read_skill`. |
413
+ | `PITHOSAI_RESULT_BROWSER` | Result viewer selection. Default: **pi-tui** full-screen markdown viewer. Set to `chrome` to use Playwright browser preview. |
414
+ | `PITHOSAI_PLAYWRIGHT_CHANNEL` | Playwright browser channel for Chrome preview mode (e.g. `chrome`, `msedge`, `chrome-beta`, `bundled`). |
415
+ | `PITHOSAI_SKIP_RESULT_BROWSER` | Set to `1` to skip result preview and print markdown in terminal instead. |
416
+ | `PITHOSAI_DEBUG_STREAM` | Set to `1` to log stream completion (for troubleshooting hangs). |
417
+ | `PITHOSAI_DEBUG_HOOKS` | Set to `1` to enable debug hook handlers (logging, performance, stats). |
418
+ | `PITHOSAI_SECURITY_HOOKS` | Set to `1` to enable security hook handlers (tool blocking, sensitive-info detection). |
419
+ | `PITHOSAI_BLOCKED_TOOLS` | Comma-separated list of tool names to block (requires `PITHOSAI_SECURITY_HOOKS=1`). |
420
+ | `PITHOSAI_DB_PATH` | Override SQLite database path (default: `~/.pithosai/pithosai.db`). |
421
+ | `SUPPORT_EMAIL` | When a heartbeat task fails, the failure reply is sent to this address instead of the customer. Default: `support@pithosai.com`. |
422
+ | `PITHOSAI_MAX_MESSAGE_TOKENS` | Max tokens for conversation messages before compression (defaults to model context minus reserved system tokens). |
423
+ | `PITHOSAI_MAX_HISTORY_MESSAGES` | Max number of recent messages kept before earlier history is dropped (default: 40). |
424
+ | `PITHOSAI_MIN_HISTORY_MESSAGES` | Minimum number of recent messages to keep when aggressively compacting history (default: 10). |
425
+ | `PITHOSAI_MAX_TOOL_RESULT_CHARS` | Max characters per tool result string before truncation (default: 8000). |
426
+ | `PITHOSAI_MIN_TOOL_RESULT_CHARS` | Minimum characters per tool result when aggressively truncating tool outputs (default: 2000). |
427
+
428
+ ---
429
+
430
+ ## Testing
431
+
432
+ Unit tests use [Vitest](https://vitest.dev/). Run all tests:
433
+
434
+ ```bash
435
+ npm test
436
+ ```
437
+
438
+ Tests cover prompts (loader, validator), agent event handlers (message-utils, chat, reasoner), skills (loader, read-skill tool), init (scaffold, templates, init/add-role), models (DeepSeek config, Cursor config, resolution), utils (paths, path-utils, sleep, logger), settings (read/write and merge), heartbeat, and agent tools (common, web, list-files, playwright-markdown-preview, playwright-view-tool, email).
439
+
440
+ ---
441
+
442
+ ## Docs
443
+
444
+ - [Changelog](CHANGELOG.md) - Release history ([Keep a Changelog](https://keepachangelog.com/) style).
445
+ - [Architecture](docs/ARCHITECTURE.md) - Layout, data flow, public API.
446
+ - [Configuration](docs/Configuration.md) - Global and project config files (`~/.pithosai/heartbeat-state.json`, `.pithosai/sessions`, `.pithosai/<role>` prompts). In **agent** mode, `.pithosai/<role>/TOOLS.md` (or `TOOLS-zh.md`) can list allowed tools under `# pi-agent-tools` and `# pithosai tools`; if those sections are missing or empty, the full toolset is used. **Dialog** / **plan** modes do not apply this filter.
447
+ - [Troubleshooting](docs/TROUBLESHOOTING.md) - Agent hangs, timeouts, stream debug.
448
+ - [Tools loop](docs/TOOLS-LOOP.md) - How the agent uses tools.
449
+
450
+ ---
451
+
452
+ ## License
453
+
454
+ ISC
455
+
456
+ Copyright © SHC lidh04@qq.com 2026
package/dist/935.cjs ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ "use strict";exports.ids=["935"],exports.modules={117(t,e,i){i.d(e,{showMarkdownInPiTui:()=>a});var s=i(895),l=i(950),r=i(168);let h=!1;class n{constructor(t){const{terminal:e,tui:i,markdown:s,hintText:l,documentTitle:r,onClose:h}=t;this.terminal=e,this.tui=i,this._markdown=s,this.hintText=l,this.documentTitle=r?.trim()||"",this.onClose=h,this.scrollTop=0,this._fullLines=null,this._cachedWidth=null,this._ggAwaitingSecondG=!1,this._ggTimer=null}clearGgPrefixState(){null!=this._ggTimer&&(clearTimeout(this._ggTimer),this._ggTimer=null),this._ggAwaitingSecondG=!1}invalidate(){this._markdown.invalidate(),this._fullLines=null,this._cachedWidth=null}handleInput(t){let e=this.terminal.columns,i=Math.max(1,this.terminal.rows-!!this.documentTitle-1),s=Math.max(0,this._getFullLines(e).length-i);if((0,r.matchesKey)(t,"escape")||(0,r.matchesKey)(t,"esc")||(0,r.matchesKey)(t,"q")||(0,r.matchesKey)(t,"shift+q")||(0,r.matchesKey)(t,"ctrl+c")){this.clearGgPrefixState(),this.onClose();return}if((0,r.matchesKey)(t,"shift+g")){this.clearGgPrefixState(),this.scrollTop=s;return}if((0,r.matchesKey)(t,"g")){if(this._ggAwaitingSecondG){this.clearGgPrefixState(),this.scrollTop=0;return}this._ggAwaitingSecondG=!0,null!=this._ggTimer&&clearTimeout(this._ggTimer),this._ggTimer=setTimeout(()=>{this._ggTimer=null,this._ggAwaitingSecondG=!1},500);return}if(this.clearGgPrefixState(),(0,r.matchesKey)(t,"up")||(0,r.matchesKey)(t,"k")){this.scrollTop=Math.max(0,this.scrollTop-1);return}if((0,r.matchesKey)(t,"down")||(0,r.matchesKey)(t,"j")){this.scrollTop=Math.min(s,this.scrollTop+1);return}if((0,r.matchesKey)(t,"pageUp")||(0,r.matchesKey)(t,"ctrl+u")){this.scrollTop=Math.max(0,this.scrollTop-i);return}if((0,r.matchesKey)(t,"pageDown")||(0,r.matchesKey)(t,"ctrl+d")){this.scrollTop=Math.min(s,this.scrollTop+i);return}if((0,r.matchesKey)(t,"home")){this.scrollTop=0;return}if((0,r.matchesKey)(t,"end")){this.scrollTop=s;return}}_getFullLines(t){return this._fullLines&&this._cachedWidth===t||(this._cachedWidth=t,this._fullLines=this._markdown.render(t)),this._fullLines}render(t){let e=this.terminal.rows,i=this.documentTitle?[s.bold.cyan((0,r.truncateToWidth)(this.documentTitle,t))]:[],l=Math.max(1,e-i.length-1);null!=this._cachedWidth&&this._cachedWidth!==t&&this.invalidate();let h=this._getFullLines(t),n=Math.max(0,h.length-l);this.scrollTop=Math.min(this.scrollTop,n);let a=h.slice(this.scrollTop,this.scrollTop+l);for(;a.length<l;)a.push("");return[...i,...a,s.dim((0,r.truncateToWidth)(this.hintText,t))]}}async function a(t){let{markdown:e,t:i,documentTitle:s,tuiSession:a=null}=t;if(!e||"string"!=typeof e||!e.trim())return;if(!(process.stdout.isTTY&&process.stdin.isTTY))return void process.stdout.write(`${e}
3
+ `);let o=a&&"function"==typeof a.suspendForReadline&&"function"==typeof a.resumeFromReadline;o&&a.suspendForReadline();try{h||((0,l.CK)("dark"),h=!0);let t=(0,l.pd)(),a=new r.Markdown(e,1,1,t),o=i("cli.resultPreviewTerminalHint"),c=new r.ProcessTerminal,u=new r.TUI(c);u.setClearOnShrink(!0),await new Promise(t=>{let e,i=new n({terminal:c,tui:u,markdown:a,hintText:o,documentTitle:s,onClose:()=>{e?.clearGgPrefixState(),u.stop(),t()}});e=i;let l=new r.Container;l.addChild(i),u.addChild(l),u.setFocus(i),u.start(),u.requestRender(!0)})}finally{o&&a.resumeFromReadline()}}}};