@code-yeongyu/senpi 2026.6.10 → 2026.6.12-2
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/CHANGELOG.md +28 -1
- package/README.md +18 -18
- package/dist/cli/startup-ui.d.ts +10 -0
- package/dist/cli/startup-ui.d.ts.map +1 -1
- package/dist/cli/startup-ui.js +72 -1
- package/dist/cli/startup-ui.js.map +1 -1
- package/dist/core/bash-executor.d.ts.map +1 -1
- package/dist/core/bash-executor.js +31 -7
- package/dist/core/bash-executor.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/degradation-monitor.d.ts +0 -1
- package/dist/core/extensions/builtin/compaction/degradation-monitor.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/degradation-monitor.js +0 -1
- package/dist/core/extensions/builtin/compaction/degradation-monitor.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/index.js +4 -4
- package/dist/core/extensions/builtin/compaction/index.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/policy.d.ts +0 -5
- package/dist/core/extensions/builtin/compaction/policy.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/policy.js +0 -4
- package/dist/core/extensions/builtin/compaction/policy.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/speculative.d.ts +0 -6
- package/dist/core/extensions/builtin/compaction/speculative.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/speculative.js +0 -3
- package/dist/core/extensions/builtin/compaction/speculative.js.map +1 -1
- package/dist/core/extensions/builtin/gpt-apply-patch/extension.d.ts +1 -1
- package/dist/core/extensions/builtin/gpt-apply-patch/extension.d.ts.map +1 -1
- package/dist/core/extensions/builtin/gpt-apply-patch/extension.js +10 -2
- package/dist/core/extensions/builtin/gpt-apply-patch/extension.js.map +1 -1
- package/dist/core/extensions/builtin/permission-system/cli.d.ts +0 -3
- package/dist/core/extensions/builtin/permission-system/cli.d.ts.map +1 -1
- package/dist/core/extensions/builtin/permission-system/cli.js +0 -13
- package/dist/core/extensions/builtin/permission-system/cli.js.map +1 -1
- package/dist/core/extensions/types.d.ts +1 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/model-registry.d.ts +0 -3
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +1 -3
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts +1 -0
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +20 -5
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/resolve-config-value.d.ts +0 -4
- package/dist/core/resolve-config-value.d.ts.map +1 -1
- package/dist/core/resolve-config-value.js +0 -15
- package/dist/core/resolve-config-value.js.map +1 -1
- package/dist/core/settings-manager.d.ts +6 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +17 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/tools/edit-diff.d.ts +0 -5
- package/dist/core/tools/edit-diff.d.ts.map +1 -1
- package/dist/core/tools/edit-diff.js +0 -7
- package/dist/core/tools/edit-diff.js.map +1 -1
- package/dist/core/tools/index.d.ts +0 -5
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +0 -67
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/output-accumulator.d.ts +3 -5
- package/dist/core/tools/output-accumulator.d.ts.map +1 -1
- package/dist/core/tools/output-accumulator.js +38 -34
- package/dist/core/tools/output-accumulator.js.map +1 -1
- package/dist/core/tools/tail-window.d.ts +15 -0
- package/dist/core/tools/tail-window.d.ts.map +1 -0
- package/dist/core/tools/tail-window.js +75 -0
- package/dist/core/tools/tail-window.js.map +1 -0
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +8 -1
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/first-time-setup.d.ts +25 -0
- package/dist/modes/interactive/components/first-time-setup.d.ts.map +1 -0
- package/dist/modes/interactive/components/first-time-setup.js +101 -0
- package/dist/modes/interactive/components/first-time-setup.js.map +1 -0
- package/dist/modes/interactive/components/index.d.ts +1 -0
- package/dist/modes/interactive/components/index.d.ts.map +1 -1
- package/dist/modes/interactive/components/index.js +1 -0
- package/dist/modes/interactive/components/index.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +6 -0
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +45 -0
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +12 -5
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/theme.d.ts +0 -4
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +0 -7
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +0 -1
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/docs/compaction-guide.md +9 -9
- package/docs/compaction.md +2 -2
- package/docs/containerization.md +22 -22
- package/docs/custom-provider.md +13 -13
- package/docs/development.md +4 -2
- package/docs/extensions.md +18 -19
- package/docs/index.md +4 -4
- package/docs/json.md +21 -15
- package/docs/keybindings.md +6 -3
- package/docs/models.md +6 -6
- package/docs/packages.md +11 -11
- package/docs/prompt-templates.md +2 -2
- package/docs/providers.md +9 -9
- package/docs/rpc.md +14 -13
- package/docs/sdk.md +13 -9
- package/docs/security.md +7 -7
- package/docs/session-format.md +4 -4
- package/docs/sessions.md +14 -14
- package/docs/settings.md +13 -11
- package/docs/skills.md +8 -8
- package/docs/terminal-setup.md +2 -2
- package/docs/termux.md +3 -3
- package/docs/tui.md +4 -4
- package/docs/usage.md +51 -58
- package/node_modules/@earendil-works/pi-agent-core/README.md +4 -3
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/types.d.ts +0 -2
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/types.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/types.js +0 -4
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/types.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/types.d.ts +1 -1
- package/node_modules/@earendil-works/pi-agent-core/dist/types.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/package.json +2 -2
- package/node_modules/@earendil-works/pi-ai/README.md +2 -4
- package/node_modules/@earendil-works/pi-ai/dist/api-registry.d.ts +0 -1
- package/node_modules/@earendil-works/pi-ai/dist/api-registry.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api-registry.js +0 -3
- package/node_modules/@earendil-works/pi-ai/dist/api-registry.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/models.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts +104 -454
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.js +162 -475
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/models.js +12 -5
- package/node_modules/@earendil-works/pi-ai/dist/models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.js +11 -2
- package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/google-shared.d.ts +0 -4
- package/node_modules/@earendil-works/pi-ai/dist/providers/google-shared.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/google-shared.js +0 -13
- package/node_modules/@earendil-works/pi-ai/dist/providers/google-shared.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/simple-options.d.ts +0 -6
- package/node_modules/@earendil-works/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/simple-options.js +0 -14
- package/node_modules/@earendil-works/pi-ai/dist/providers/simple-options.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/event-stream.d.ts +4 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/event-stream.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/event-stream.js +54 -8
- package/node_modules/@earendil-works/pi-ai/dist/utils/event-stream.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/overflow.d.ts +0 -4
- package/node_modules/@earendil-works/pi-ai/dist/utils/overflow.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/overflow.js +0 -6
- package/node_modules/@earendil-works/pi-ai/dist/utils/overflow.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/package.json +1 -1
- package/node_modules/@earendil-works/pi-tui/README.md +1 -2
- package/node_modules/@earendil-works/pi-tui/dist/components/editor.d.ts +2 -0
- package/node_modules/@earendil-works/pi-tui/dist/components/editor.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/components/editor.js +80 -7
- package/node_modules/@earendil-works/pi-tui/dist/components/editor.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/components/markdown.d.ts +1 -0
- package/node_modules/@earendil-works/pi-tui/dist/components/markdown.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/components/markdown.js +72 -1
- package/node_modules/@earendil-works/pi-tui/dist/components/markdown.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/index.d.ts +2 -2
- package/node_modules/@earendil-works/pi-tui/dist/index.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/index.js +2 -2
- package/node_modules/@earendil-works/pi-tui/dist/index.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/terminal-image.d.ts +0 -1
- package/node_modules/@earendil-works/pi-tui/dist/terminal-image.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/terminal-image.js +4 -7
- package/node_modules/@earendil-works/pi-tui/dist/terminal-image.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/utils.d.ts +1 -4
- package/node_modules/@earendil-works/pi-tui/dist/utils.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/utils.js +1 -7
- package/node_modules/@earendil-works/pi-tui/dist/utils.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/package.json +1 -1
- package/npm-shrinkwrap.json +12 -12
- package/package.json +4 -4
- package/dist/core/experimental.d.ts +0 -2
- package/dist/core/experimental.d.ts.map +0 -1
- package/dist/core/experimental.js +0 -4
- package/dist/core/experimental.js.map +0 -1
- package/dist/core/extensions/builtin/compaction/overflow-detection.d.ts +0 -11
- package/dist/core/extensions/builtin/compaction/overflow-detection.d.ts.map +0 -1
- package/dist/core/extensions/builtin/compaction/overflow-detection.js +0 -40
- package/dist/core/extensions/builtin/compaction/overflow-detection.js.map +0 -1
- package/dist/core/extensions/builtin/system-messages.d.ts +0 -47
- package/dist/core/extensions/builtin/system-messages.d.ts.map +0 -1
- package/dist/core/extensions/builtin/system-messages.js +0 -117
- package/dist/core/extensions/builtin/system-messages.js.map +0 -1
- package/dist/core/index.d.ts +0 -13
- package/dist/core/index.d.ts.map +0 -1
- package/dist/core/index.js +0 -13
- package/dist/core/index.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## [
|
|
3
|
+
## [2026.6.12-2] - 2026-06-12
|
|
4
4
|
|
|
5
5
|
### Added
|
|
6
6
|
|
|
@@ -8,6 +8,33 @@
|
|
|
8
8
|
|
|
9
9
|
### Removed
|
|
10
10
|
|
|
11
|
+
## [2026.6.12] - 2026-06-12
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- Added an experimental first-time setup flow behind `PI_EXPERIMENTAL=1` that asks for a dark/light theme choice (preselecting the detected appearance) and opt-in analytics data sharing on first launch with the default agent directory; opting in stores a `trackingId` in `settings.json`.
|
|
16
|
+
- Added local benchmark coverage for interactive assistant transcript rendering and large bash output handling.
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- Improved large bash output retention by using a head-indexed rolling buffer and a compact tail window for streaming output snapshots.
|
|
21
|
+
- Restored pending tool-call wait rendering during thinking updates and stopped stale pending animations after the interactive display clears.
|
|
22
|
+
|
|
23
|
+
### Removed
|
|
24
|
+
|
|
25
|
+
## [2026.6.10-2] - 2026-06-10
|
|
26
|
+
|
|
27
|
+
### Added
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
|
|
31
|
+
- `apply_patch` now activates based on the model's API (`openai-responses`, `azure-openai-responses`, `openai-codex-responses`) instead of a provider allowlist, so OpenAI-compatible custom providers serving `gpt-*` models get the freeform patch tool, and Chat Completions models (which reject freeform tools) never do.
|
|
32
|
+
- The `compaction.restorationEnabled` setting is now honored at runtime; previously the restoration tracker read a hardcoded default and could not be disabled.
|
|
33
|
+
|
|
34
|
+
### Removed
|
|
35
|
+
|
|
36
|
+
- Removed dead internal modules and exports: `system-messages.ts`, compaction `overflow-detection.ts`, the `PI_EXPERIMENTAL` flag, unused tool factory functions (`createTool`, `createToolDefinition`, `createCodingToolDefinitions`, `createReadOnlyToolDefinitions`, `createAllTools`), `computeEditDiff`, `resolveHeaders`, `isLightTheme`, `RpcCommandType`, and the unwired compaction cooldown helpers.
|
|
37
|
+
|
|
11
38
|
## [2026.6.10] - 2026-06-10
|
|
12
39
|
|
|
13
40
|
### Added
|
package/README.md
CHANGED
|
@@ -142,7 +142,7 @@ For each built-in provider, pi maintains a list of tool-capable models, updated
|
|
|
142
142
|
|
|
143
143
|
See [docs/providers.md](docs/providers.md) for detailed setup instructions.
|
|
144
144
|
|
|
145
|
-
**Custom providers & models:** Add providers via `~/.
|
|
145
|
+
**Custom providers & models:** Add providers via `~/.senpi/agent/models.json` if they speak a supported API (OpenAI, Anthropic, Google). For custom APIs or OAuth, use extensions. See [docs/models.md](docs/models.md) and [docs/custom-provider.md](docs/custom-provider.md).
|
|
146
146
|
|
|
147
147
|
---
|
|
148
148
|
|
|
@@ -179,7 +179,7 @@ Type `/` in the editor to trigger commands. [Extensions](#extensions) can regist
|
|
|
179
179
|
|---------|-------------|
|
|
180
180
|
| `/login`, `/logout` | OAuth authentication |
|
|
181
181
|
| `/model` | Switch models |
|
|
182
|
-
| `/
|
|
182
|
+
| `/favorite-models` | Manage favorite models for Ctrl+P cycling |
|
|
183
183
|
| `/settings` | Thinking level, theme, message delivery, transport |
|
|
184
184
|
| `/resume` | Pick from previous sessions |
|
|
185
185
|
| `/new` | Start a new session |
|
|
@@ -200,7 +200,7 @@ Type `/` in the editor to trigger commands. [Extensions](#extensions) can regist
|
|
|
200
200
|
|
|
201
201
|
### Keyboard Shortcuts
|
|
202
202
|
|
|
203
|
-
See `/hotkeys` for the full list. Customize via `~/.
|
|
203
|
+
See `/hotkeys` for the full list. Customize via `~/.senpi/agent/keybindings.json`. See [docs/keybindings.md](docs/keybindings.md).
|
|
204
204
|
|
|
205
205
|
**Commonly used:**
|
|
206
206
|
|
|
@@ -237,7 +237,7 @@ Sessions are stored as JSONL files with a tree structure. Each entry has an `id`
|
|
|
237
237
|
|
|
238
238
|
### Management
|
|
239
239
|
|
|
240
|
-
Sessions auto-save to `~/.
|
|
240
|
+
Sessions auto-save to `~/.senpi/agent/sessions/` organized by working directory.
|
|
241
241
|
|
|
242
242
|
```bash
|
|
243
243
|
pi -c # Continue most recent session
|
|
@@ -284,14 +284,14 @@ Use `/settings` to modify common options, or edit JSON files directly:
|
|
|
284
284
|
|
|
285
285
|
| Location | Scope |
|
|
286
286
|
|----------|-------|
|
|
287
|
-
| `~/.
|
|
288
|
-
| `.
|
|
287
|
+
| `~/.senpi/agent/settings.json` | Global (all projects) |
|
|
288
|
+
| `.senpi/settings.json` | Project (overrides global) |
|
|
289
289
|
|
|
290
290
|
See [docs/settings.md](docs/settings.md) for all options.
|
|
291
291
|
|
|
292
292
|
### Project Trust
|
|
293
293
|
|
|
294
|
-
On interactive startup, pi asks before trusting a project folder that contains project-local extensions or settings and has no saved decision for the folder or a parent folder in `~/.
|
|
294
|
+
On interactive startup, pi asks before trusting a project folder that contains project-local extensions or settings and has no saved decision for the folder or a parent folder in `~/.senpi/agent/trust.json`. Trusting a project allows pi to load `.senpi/settings.json` and `.senpi` resources, install missing project packages, and execute project extensions.
|
|
295
295
|
|
|
296
296
|
Before the trust decision, pi loads only context files, user/global extensions, and CLI `-e` extensions so they can handle the `project_trust` event. Project-local extensions, project package-managed extensions, and project settings are loaded only after the project is trusted. This split also applies when switching to a session from a different cwd whose trust has not been resolved in the current process.
|
|
297
297
|
|
|
@@ -327,7 +327,7 @@ Disable context file loading with `--no-context-files` (or `-nc`).
|
|
|
327
327
|
|
|
328
328
|
### System Prompt
|
|
329
329
|
|
|
330
|
-
|
|
330
|
+
Senpi builds its system prompt dynamically from the registered tools. Replace it with `--system-prompt <text>` or from an extension via the `before_agent_start` event; append without replacing via `--append-system-prompt <text>`. Upstream pi's `SYSTEM.md`/`APPEND_SYSTEM.md` file overrides are not supported in this fork.
|
|
331
331
|
|
|
332
332
|
---
|
|
333
333
|
|
|
@@ -338,19 +338,19 @@ Replace the default system prompt with `.pi/SYSTEM.md` (project) or `~/.pi/agent
|
|
|
338
338
|
Reusable prompts as Markdown files. Type `/name` to expand.
|
|
339
339
|
|
|
340
340
|
```markdown
|
|
341
|
-
<!-- ~/.
|
|
341
|
+
<!-- ~/.senpi/agent/prompts/review.md -->
|
|
342
342
|
Review this code for bugs, security issues, and performance problems.
|
|
343
343
|
Focus on: {{focus}}
|
|
344
344
|
```
|
|
345
345
|
|
|
346
|
-
Place in `~/.
|
|
346
|
+
Place in `~/.senpi/agent/prompts/`, `.senpi/prompts/`, or a [pi package](#pi-packages) to share with others. See [docs/prompt-templates.md](docs/prompt-templates.md).
|
|
347
347
|
|
|
348
348
|
### Skills
|
|
349
349
|
|
|
350
350
|
On-demand capability packages following the [Agent Skills standard](https://agentskills.io). Invoke via `/skill:name` or let the agent load them automatically.
|
|
351
351
|
|
|
352
352
|
```markdown
|
|
353
|
-
<!-- ~/.
|
|
353
|
+
<!-- ~/.senpi/agent/skills/my-skill/SKILL.md -->
|
|
354
354
|
# My Skill
|
|
355
355
|
Use this skill when the user asks about X.
|
|
356
356
|
|
|
@@ -359,7 +359,7 @@ Use this skill when the user asks about X.
|
|
|
359
359
|
2. Then that
|
|
360
360
|
```
|
|
361
361
|
|
|
362
|
-
Place in `~/.
|
|
362
|
+
Place in `~/.senpi/agent/skills/`, `~/.agents/skills/`, `.senpi/skills/`, or `.agents/skills/` (from `cwd` up through parent directories) or a [pi package](#pi-packages) to share with others. See [docs/skills.md](docs/skills.md).
|
|
363
363
|
|
|
364
364
|
### Extensions
|
|
365
365
|
|
|
@@ -391,13 +391,13 @@ The default export can also be `async`. pi waits for async extension factories b
|
|
|
391
391
|
- Games while waiting (yes, Doom runs)
|
|
392
392
|
- ...anything you can dream up
|
|
393
393
|
|
|
394
|
-
Place in `~/.
|
|
394
|
+
Place in `~/.senpi/agent/extensions/`, `.senpi/extensions/`, or a [pi package](#pi-packages) to share with others. See [docs/extensions.md](docs/extensions.md) and [examples/extensions/](examples/extensions/).
|
|
395
395
|
|
|
396
396
|
### Themes
|
|
397
397
|
|
|
398
398
|
Built-in: `dark`, `light`. Themes hot-reload: modify the active theme file and pi immediately applies changes.
|
|
399
399
|
|
|
400
|
-
Place in `~/.
|
|
400
|
+
Place in `~/.senpi/agent/themes/`, `.senpi/themes/`, or a [pi package](#pi-packages) to share with others. See [docs/themes.md](docs/themes.md).
|
|
401
401
|
|
|
402
402
|
### Pi Packages
|
|
403
403
|
|
|
@@ -427,7 +427,7 @@ pi update npm:@foo/pi-tools # update one package
|
|
|
427
427
|
pi config # enable/disable extensions, skills, prompts, themes
|
|
428
428
|
```
|
|
429
429
|
|
|
430
|
-
Packages install to `~/.
|
|
430
|
+
Packages install to `~/.senpi/agent/git/` (git) or `~/.senpi/agent/npm/` (npm). Use `-l` for project-local installs (`.senpi/git/`, `.senpi/npm/`). Git `@ref` values are pinned tags or commits; pinned packages are skipped by `pi update`, so use `pi install git:host/user/repo@new-ref` to move an existing package to a new ref. Git packages install dependencies with `npm install --omit=dev` by default, so runtime deps must be listed under `dependencies`; when `npmCommand` is configured, git packages use plain `install` for compatibility with wrappers. If you use a Node version manager and want package installs to reuse a stable npm context, set `npmCommand` in `settings.json`, for example `["mise", "exec", "node@20", "--", "npm"]`.
|
|
431
431
|
|
|
432
432
|
Create a package by adding a `pi` key to `package.json`:
|
|
433
433
|
|
|
@@ -552,7 +552,7 @@ cat README.md | pi -p "Summarize this text"
|
|
|
552
552
|
| `--provider <name>` | Provider (anthropic, openai, google, etc.) |
|
|
553
553
|
| `--model <pattern>` | Model pattern or ID (supports `provider/id` and optional `:<thinking>`) |
|
|
554
554
|
| `--api-key <key>` | API key (overrides env vars) |
|
|
555
|
-
| `--thinking <level>` | `off`, `minimal`, `low`, `medium`, `high`, `xhigh` |
|
|
555
|
+
| `--thinking <level>` | `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max` |
|
|
556
556
|
| `--models <patterns>` | Comma-separated patterns for Ctrl+P cycling |
|
|
557
557
|
| `--list-models [search]` | List available models |
|
|
558
558
|
|
|
@@ -658,8 +658,8 @@ pi --thinking high "Solve this complex problem"
|
|
|
658
658
|
|
|
659
659
|
| Variable | Description |
|
|
660
660
|
|----------|-------------|
|
|
661
|
-
| `
|
|
662
|
-
| `
|
|
661
|
+
| `SENPI_CODING_AGENT_DIR` | Override config directory (default: `~/.senpi/agent`) |
|
|
662
|
+
| `SENPI_CODING_AGENT_SESSION_DIR` | Override session storage directory (overridden by `--session-dir`) |
|
|
663
663
|
| `PI_PACKAGE_DIR` | Override package directory (useful for Nix/Guix where store paths tokenize poorly) |
|
|
664
664
|
| `PI_OFFLINE` | Disable startup network operations, including update checks, package update checks, and install/update telemetry |
|
|
665
665
|
| `PI_SKIP_VERSION_CHECK` | Skip the Pi version update check at startup. This prevents the `pi.dev` latest-version request |
|
package/dist/cli/startup-ui.d.ts
CHANGED
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
import type { SettingsManager } from "../core/settings-manager.ts";
|
|
2
|
+
/**
|
|
3
|
+
* First-time setup runs when all of these hold:
|
|
4
|
+
* - this is the official Pi distribution (not a fork/rebrand)
|
|
5
|
+
* - experimental features are enabled (PI_EXPERIMENTAL=1)
|
|
6
|
+
* - the default agent directory is used (no custom agent dir override)
|
|
7
|
+
* - setup was not completed before (settings.json does not exist)
|
|
8
|
+
*/
|
|
9
|
+
export declare function shouldRunFirstTimeSetup(settingsPath?: string): boolean;
|
|
2
10
|
export declare function showStartupSelector<T>(settingsManager: SettingsManager, title: string, options: Array<{
|
|
3
11
|
label: string;
|
|
4
12
|
value: T;
|
|
5
13
|
}>): Promise<T | undefined>;
|
|
14
|
+
/** Show the first-time setup dialog and persist the result */
|
|
15
|
+
export declare function showFirstTimeSetup(settingsManager: SettingsManager): Promise<void>;
|
|
6
16
|
export declare function showStartupInput(settingsManager: SettingsManager, title: string, placeholder?: string): Promise<string | undefined>;
|
|
7
17
|
//# sourceMappingURL=startup-ui.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"startup-ui.d.ts","sourceRoot":"","sources":["../../src/cli/startup-ui.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"startup-ui.d.ts","sourceRoot":"","sources":["../../src/cli/startup-ui.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AA6CnE;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,YAAY,GAAE,MAA0B,GAAG,OAAO,CAiBzF;AAED,wBAAsB,mBAAmB,CAAC,CAAC,EAC1C,eAAe,EAAE,eAAe,EAChC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,CAAC,CAAA;CAAE,CAAC,GACzC,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CA0BxB;AAED,8DAA8D;AAC9D,wBAAsB,kBAAkB,CAAC,eAAe,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAkCxF;AAED,wBAAsB,gBAAgB,CACrC,eAAe,EAAE,eAAe,EAChC,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CA6B7B"}
|
package/dist/cli/startup-ui.js
CHANGED
|
@@ -1,8 +1,22 @@
|
|
|
1
1
|
import { ProcessTerminal, setKeybindings, TUI } from "@earendil-works/pi-tui";
|
|
2
|
+
import { existsSync } from "fs";
|
|
3
|
+
import { APP_NAME, CONFIG_DIR_NAME, ENV_AGENT_DIR, getSettingsPath, PACKAGE_NAME } from "../config.js";
|
|
2
4
|
import { KeybindingsManager } from "../core/keybindings.js";
|
|
3
5
|
import { ExtensionInputComponent } from "../modes/interactive/components/extension-input.js";
|
|
4
6
|
import { ExtensionSelectorComponent } from "../modes/interactive/components/extension-selector.js";
|
|
5
|
-
import {
|
|
7
|
+
import { FirstTimeSetupComponent, } from "../modes/interactive/components/first-time-setup.js";
|
|
8
|
+
import { detectTerminalBackground, initTheme, setTheme } from "../modes/interactive/theme/theme.js";
|
|
9
|
+
const OFFICIAL_PACKAGE_NAME = "@earendil-works/pi-coding-agent";
|
|
10
|
+
const OFFICIAL_APP_NAME = "pi";
|
|
11
|
+
const OFFICIAL_CONFIG_DIR_NAME = ".pi";
|
|
12
|
+
function isOfficialDistribution({ packageName, appName, configDirName }) {
|
|
13
|
+
return (packageName === OFFICIAL_PACKAGE_NAME &&
|
|
14
|
+
appName === OFFICIAL_APP_NAME &&
|
|
15
|
+
configDirName === OFFICIAL_CONFIG_DIR_NAME);
|
|
16
|
+
}
|
|
17
|
+
function areExperimentalFeaturesEnabled() {
|
|
18
|
+
return process.env.PI_EXPERIMENTAL === "1";
|
|
19
|
+
}
|
|
6
20
|
function createStartupTui(settingsManager) {
|
|
7
21
|
initTheme(settingsManager.getTheme());
|
|
8
22
|
setKeybindings(KeybindingsManager.create());
|
|
@@ -15,6 +29,29 @@ async function clearStartupTui(ui) {
|
|
|
15
29
|
ui.requestRender();
|
|
16
30
|
await new Promise((resolve) => setTimeout(resolve, 25));
|
|
17
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* First-time setup runs when all of these hold:
|
|
34
|
+
* - this is the official Pi distribution (not a fork/rebrand)
|
|
35
|
+
* - experimental features are enabled (PI_EXPERIMENTAL=1)
|
|
36
|
+
* - the default agent directory is used (no custom agent dir override)
|
|
37
|
+
* - setup was not completed before (settings.json does not exist)
|
|
38
|
+
*/
|
|
39
|
+
export function shouldRunFirstTimeSetup(settingsPath = getSettingsPath()) {
|
|
40
|
+
if (!isOfficialDistribution({
|
|
41
|
+
packageName: PACKAGE_NAME,
|
|
42
|
+
appName: APP_NAME,
|
|
43
|
+
configDirName: CONFIG_DIR_NAME,
|
|
44
|
+
})) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
if (!areExperimentalFeaturesEnabled()) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
if (process.env[ENV_AGENT_DIR]) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
return !existsSync(settingsPath);
|
|
54
|
+
}
|
|
18
55
|
export async function showStartupSelector(settingsManager, title, options) {
|
|
19
56
|
return new Promise((resolve) => {
|
|
20
57
|
const ui = createStartupTui(settingsManager);
|
|
@@ -34,6 +71,40 @@ export async function showStartupSelector(settingsManager, title, options) {
|
|
|
34
71
|
ui.start();
|
|
35
72
|
});
|
|
36
73
|
}
|
|
74
|
+
/** Show the first-time setup dialog and persist the result */
|
|
75
|
+
export async function showFirstTimeSetup(settingsManager) {
|
|
76
|
+
return new Promise((resolve) => {
|
|
77
|
+
const ui = createStartupTui(settingsManager);
|
|
78
|
+
let settled = false;
|
|
79
|
+
const finish = async (result) => {
|
|
80
|
+
if (settled) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
settled = true;
|
|
84
|
+
if (result) {
|
|
85
|
+
settingsManager.setTheme(result.theme);
|
|
86
|
+
settingsManager.setEnableAnalytics(result.shareAnalytics);
|
|
87
|
+
await settingsManager.flush();
|
|
88
|
+
}
|
|
89
|
+
await clearStartupTui(ui);
|
|
90
|
+
ui.stop();
|
|
91
|
+
resolve();
|
|
92
|
+
};
|
|
93
|
+
const component = new FirstTimeSetupComponent({
|
|
94
|
+
detectedTheme: detectTerminalBackground().theme,
|
|
95
|
+
onThemePreview: (themeName) => {
|
|
96
|
+
setTheme(themeName);
|
|
97
|
+
ui.invalidate();
|
|
98
|
+
ui.requestRender();
|
|
99
|
+
},
|
|
100
|
+
onSubmit: (result) => void finish(result),
|
|
101
|
+
onCancel: () => void finish(undefined),
|
|
102
|
+
});
|
|
103
|
+
ui.addChild(component);
|
|
104
|
+
ui.setFocus(component);
|
|
105
|
+
ui.start();
|
|
106
|
+
});
|
|
107
|
+
}
|
|
37
108
|
export async function showStartupInput(settingsManager, title, placeholder) {
|
|
38
109
|
return new Promise((resolve) => {
|
|
39
110
|
const ui = createStartupTui(settingsManager);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"startup-ui.js","sourceRoot":"","sources":["../../src/cli/startup-ui.ts"],"names":[],"mappings":"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","sourcesContent":["import { ProcessTerminal, setKeybindings, TUI } from \"@earendil-works/pi-tui\";\nimport { KeybindingsManager } from \"../core/keybindings.ts\";\nimport type { SettingsManager } from \"../core/settings-manager.ts\";\nimport { ExtensionInputComponent } from \"../modes/interactive/components/extension-input.ts\";\nimport { ExtensionSelectorComponent } from \"../modes/interactive/components/extension-selector.ts\";\nimport { initTheme } from \"../modes/interactive/theme/theme.ts\";\n\nfunction createStartupTui(settingsManager: SettingsManager): TUI {\n\tinitTheme(settingsManager.getTheme());\n\tsetKeybindings(KeybindingsManager.create());\n\tconst ui = new TUI(new ProcessTerminal(), settingsManager.getShowHardwareCursor());\n\tui.setClearOnShrink(settingsManager.getClearOnShrink());\n\treturn ui;\n}\n\nasync function clearStartupTui(ui: TUI): Promise<void> {\n\tui.clear();\n\tui.requestRender();\n\tawait new Promise((resolve) => setTimeout(resolve, 25));\n}\n\nexport async function showStartupSelector<T>(\n\tsettingsManager: SettingsManager,\n\ttitle: string,\n\toptions: Array<{ label: string; value: T }>,\n): Promise<T | undefined> {\n\treturn new Promise((resolve) => {\n\t\tconst ui = createStartupTui(settingsManager);\n\n\t\tlet settled = false;\n\t\tconst finish = async (result: T | undefined) => {\n\t\t\tif (settled) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsettled = true;\n\t\t\tawait clearStartupTui(ui);\n\t\t\tui.stop();\n\t\t\tresolve(result);\n\t\t};\n\n\t\tconst selector = new ExtensionSelectorComponent(\n\t\t\ttitle,\n\t\t\toptions.map((option) => option.label),\n\t\t\t(option) => void finish(options.find((entry) => entry.label === option)?.value),\n\t\t\t() => void finish(undefined),\n\t\t\t{ tui: ui },\n\t\t);\n\t\tui.addChild(selector);\n\t\tui.setFocus(selector);\n\t\tui.start();\n\t});\n}\n\nexport async function showStartupInput(\n\tsettingsManager: SettingsManager,\n\ttitle: string,\n\tplaceholder?: string,\n): Promise<string | undefined> {\n\treturn new Promise((resolve) => {\n\t\tconst ui = createStartupTui(settingsManager);\n\n\t\tlet settled = false;\n\t\tconst finish = async (result: string | undefined) => {\n\t\t\tif (settled) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsettled = true;\n\t\t\tinput.dispose();\n\t\t\tawait clearStartupTui(ui);\n\t\t\tui.stop();\n\t\t\tresolve(result);\n\t\t};\n\n\t\tconst input = new ExtensionInputComponent(\n\t\t\ttitle,\n\t\t\tplaceholder,\n\t\t\t(value) => void finish(value),\n\t\t\t() => void finish(undefined),\n\t\t\t{\n\t\t\t\ttui: ui,\n\t\t\t},\n\t\t);\n\t\tui.addChild(input);\n\t\tui.setFocus(input);\n\t\tui.start();\n\t});\n}\n"]}
|
|
1
|
+
{"version":3,"file":"startup-ui.js","sourceRoot":"","sources":["../../src/cli/startup-ui.ts"],"names":[],"mappings":"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","sourcesContent":["import { ProcessTerminal, setKeybindings, TUI } from \"@earendil-works/pi-tui\";\nimport { existsSync } from \"fs\";\nimport { APP_NAME, CONFIG_DIR_NAME, ENV_AGENT_DIR, getSettingsPath, PACKAGE_NAME } from \"../config.ts\";\nimport { KeybindingsManager } from \"../core/keybindings.ts\";\nimport type { SettingsManager } from \"../core/settings-manager.ts\";\nimport { ExtensionInputComponent } from \"../modes/interactive/components/extension-input.ts\";\nimport { ExtensionSelectorComponent } from \"../modes/interactive/components/extension-selector.ts\";\nimport {\n\tFirstTimeSetupComponent,\n\ttype FirstTimeSetupResult,\n} from \"../modes/interactive/components/first-time-setup.ts\";\nimport { detectTerminalBackground, initTheme, setTheme } from \"../modes/interactive/theme/theme.ts\";\n\nconst OFFICIAL_PACKAGE_NAME = \"@earendil-works/pi-coding-agent\";\nconst OFFICIAL_APP_NAME = \"pi\";\nconst OFFICIAL_CONFIG_DIR_NAME = \".pi\";\n\ninterface DistributionMetadata {\n\tpackageName: string;\n\tappName: string;\n\tconfigDirName: string;\n}\n\nfunction isOfficialDistribution({ packageName, appName, configDirName }: DistributionMetadata): boolean {\n\treturn (\n\t\tpackageName === OFFICIAL_PACKAGE_NAME &&\n\t\tappName === OFFICIAL_APP_NAME &&\n\t\tconfigDirName === OFFICIAL_CONFIG_DIR_NAME\n\t);\n}\n\nfunction areExperimentalFeaturesEnabled(): boolean {\n\treturn process.env.PI_EXPERIMENTAL === \"1\";\n}\n\nfunction createStartupTui(settingsManager: SettingsManager): TUI {\n\tinitTheme(settingsManager.getTheme());\n\tsetKeybindings(KeybindingsManager.create());\n\tconst ui = new TUI(new ProcessTerminal(), settingsManager.getShowHardwareCursor());\n\tui.setClearOnShrink(settingsManager.getClearOnShrink());\n\treturn ui;\n}\n\nasync function clearStartupTui(ui: TUI): Promise<void> {\n\tui.clear();\n\tui.requestRender();\n\tawait new Promise((resolve) => setTimeout(resolve, 25));\n}\n\n/**\n * First-time setup runs when all of these hold:\n * - this is the official Pi distribution (not a fork/rebrand)\n * - experimental features are enabled (PI_EXPERIMENTAL=1)\n * - the default agent directory is used (no custom agent dir override)\n * - setup was not completed before (settings.json does not exist)\n */\nexport function shouldRunFirstTimeSetup(settingsPath: string = getSettingsPath()): boolean {\n\tif (\n\t\t!isOfficialDistribution({\n\t\t\tpackageName: PACKAGE_NAME,\n\t\t\tappName: APP_NAME,\n\t\t\tconfigDirName: CONFIG_DIR_NAME,\n\t\t})\n\t) {\n\t\treturn false;\n\t}\n\tif (!areExperimentalFeaturesEnabled()) {\n\t\treturn false;\n\t}\n\tif (process.env[ENV_AGENT_DIR]) {\n\t\treturn false;\n\t}\n\treturn !existsSync(settingsPath);\n}\n\nexport async function showStartupSelector<T>(\n\tsettingsManager: SettingsManager,\n\ttitle: string,\n\toptions: Array<{ label: string; value: T }>,\n): Promise<T | undefined> {\n\treturn new Promise((resolve) => {\n\t\tconst ui = createStartupTui(settingsManager);\n\n\t\tlet settled = false;\n\t\tconst finish = async (result: T | undefined) => {\n\t\t\tif (settled) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsettled = true;\n\t\t\tawait clearStartupTui(ui);\n\t\t\tui.stop();\n\t\t\tresolve(result);\n\t\t};\n\n\t\tconst selector = new ExtensionSelectorComponent(\n\t\t\ttitle,\n\t\t\toptions.map((option) => option.label),\n\t\t\t(option) => void finish(options.find((entry) => entry.label === option)?.value),\n\t\t\t() => void finish(undefined),\n\t\t\t{ tui: ui },\n\t\t);\n\t\tui.addChild(selector);\n\t\tui.setFocus(selector);\n\t\tui.start();\n\t});\n}\n\n/** Show the first-time setup dialog and persist the result */\nexport async function showFirstTimeSetup(settingsManager: SettingsManager): Promise<void> {\n\treturn new Promise((resolve) => {\n\t\tconst ui = createStartupTui(settingsManager);\n\n\t\tlet settled = false;\n\t\tconst finish = async (result: FirstTimeSetupResult | undefined) => {\n\t\t\tif (settled) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsettled = true;\n\t\t\tif (result) {\n\t\t\t\tsettingsManager.setTheme(result.theme);\n\t\t\t\tsettingsManager.setEnableAnalytics(result.shareAnalytics);\n\t\t\t\tawait settingsManager.flush();\n\t\t\t}\n\t\t\tawait clearStartupTui(ui);\n\t\t\tui.stop();\n\t\t\tresolve();\n\t\t};\n\n\t\tconst component = new FirstTimeSetupComponent({\n\t\t\tdetectedTheme: detectTerminalBackground().theme,\n\t\t\tonThemePreview: (themeName) => {\n\t\t\t\tsetTheme(themeName);\n\t\t\t\tui.invalidate();\n\t\t\t\tui.requestRender();\n\t\t\t},\n\t\t\tonSubmit: (result) => void finish(result),\n\t\t\tonCancel: () => void finish(undefined),\n\t\t});\n\t\tui.addChild(component);\n\t\tui.setFocus(component);\n\t\tui.start();\n\t});\n}\n\nexport async function showStartupInput(\n\tsettingsManager: SettingsManager,\n\ttitle: string,\n\tplaceholder?: string,\n): Promise<string | undefined> {\n\treturn new Promise((resolve) => {\n\t\tconst ui = createStartupTui(settingsManager);\n\n\t\tlet settled = false;\n\t\tconst finish = async (result: string | undefined) => {\n\t\t\tif (settled) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsettled = true;\n\t\t\tinput.dispose();\n\t\t\tawait clearStartupTui(ui);\n\t\t\tui.stop();\n\t\t\tresolve(result);\n\t\t};\n\n\t\tconst input = new ExtensionInputComponent(\n\t\t\ttitle,\n\t\t\tplaceholder,\n\t\t\t(value) => void finish(value),\n\t\t\t() => void finish(undefined),\n\t\t\t{\n\t\t\t\ttui: ui,\n\t\t\t},\n\t\t);\n\t\tui.addChild(input);\n\t\tui.setFocus(input);\n\t\tui.start();\n\t});\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bash-executor.d.ts","sourceRoot":"","sources":["../../src/core/bash-executor.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAQH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAOtD,MAAM,WAAW,mBAAmB;IACnC,+DAA+D;IAC/D,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,mCAAmC;IACnC,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB;AAED,MAAM,WAAW,UAAU;IAC1B,sEAAsE;IACtE,MAAM,EAAE,MAAM,CAAC;IACf,wDAAwD;IACxD,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,mDAAmD;IACnD,SAAS,EAAE,OAAO,CAAC;IACnB,uCAAuC;IACvC,SAAS,EAAE,OAAO,CAAC;IACnB,yFAAyF;IACzF,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAMD;;;GAGG;AACH,wBAAsB,yBAAyB,CAC9C,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,cAAc,EAC1B,OAAO,CAAC,EAAE,mBAAmB,GAC3B,OAAO,CAAC,UAAU,CAAC,
|
|
1
|
+
{"version":3,"file":"bash-executor.d.ts","sourceRoot":"","sources":["../../src/core/bash-executor.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAQH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAOtD,MAAM,WAAW,mBAAmB;IACnC,+DAA+D;IAC/D,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,mCAAmC;IACnC,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB;AAED,MAAM,WAAW,UAAU;IAC1B,sEAAsE;IACtE,MAAM,EAAE,MAAM,CAAC;IACf,wDAAwD;IACxD,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,mDAAmD;IACnD,SAAS,EAAE,OAAO,CAAC;IACnB,uCAAuC;IACvC,SAAS,EAAE,OAAO,CAAC;IACnB,yFAAyF;IACzF,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAMD;;;GAGG;AACH,wBAAsB,yBAAyB,CAC9C,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,cAAc,EAC1B,OAAO,CAAC,EAAE,mBAAmB,GAC3B,OAAO,CAAC,UAAU,CAAC,CAgIrB"}
|
|
@@ -21,11 +21,20 @@ import { DEFAULT_MAX_BYTES, truncateTail } from "./tools/truncate.js";
|
|
|
21
21
|
*/
|
|
22
22
|
export async function executeBashWithOperations(command, cwd, operations, options) {
|
|
23
23
|
const outputChunks = [];
|
|
24
|
+
let outputChunkStart = 0;
|
|
24
25
|
let outputBytes = 0;
|
|
25
26
|
const maxOutputBytes = DEFAULT_MAX_BYTES * 2;
|
|
26
27
|
let tempFilePath;
|
|
27
28
|
let tempFileStream;
|
|
28
29
|
let totalBytes = 0;
|
|
30
|
+
const compactOutputChunks = () => {
|
|
31
|
+
if (outputChunkStart < 64) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
outputChunks.splice(0, outputChunkStart);
|
|
35
|
+
outputChunkStart = 0;
|
|
36
|
+
};
|
|
37
|
+
const outputText = () => outputChunks.slice(outputChunkStart).join("");
|
|
29
38
|
const ensureTempFile = () => {
|
|
30
39
|
if (tempFilePath) {
|
|
31
40
|
return;
|
|
@@ -33,8 +42,11 @@ export async function executeBashWithOperations(command, cwd, operations, option
|
|
|
33
42
|
const id = randomBytes(8).toString("hex");
|
|
34
43
|
tempFilePath = join(tmpdir(), `pi-bash-${id}.log`);
|
|
35
44
|
tempFileStream = createWriteStream(tempFilePath);
|
|
36
|
-
for (
|
|
37
|
-
|
|
45
|
+
for (let i = outputChunkStart; i < outputChunks.length; i++) {
|
|
46
|
+
const chunk = outputChunks[i];
|
|
47
|
+
if (chunk !== undefined) {
|
|
48
|
+
tempFileStream.write(chunk);
|
|
49
|
+
}
|
|
38
50
|
}
|
|
39
51
|
};
|
|
40
52
|
const decoder = new TextDecoder();
|
|
@@ -49,24 +61,35 @@ export async function executeBashWithOperations(command, cwd, operations, option
|
|
|
49
61
|
if (tempFileStream) {
|
|
50
62
|
tempFileStream.write(text);
|
|
51
63
|
}
|
|
52
|
-
// Keep rolling buffer
|
|
53
64
|
outputChunks.push(text);
|
|
54
65
|
outputBytes += text.length;
|
|
55
|
-
while (outputBytes > maxOutputBytes && outputChunks.length
|
|
56
|
-
const removed = outputChunks
|
|
66
|
+
while (outputBytes > maxOutputBytes && outputChunkStart < outputChunks.length - 1) {
|
|
67
|
+
const removed = outputChunks[outputChunkStart];
|
|
68
|
+
if (removed === undefined) {
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
57
71
|
outputBytes -= removed.length;
|
|
72
|
+
outputChunkStart++;
|
|
58
73
|
}
|
|
74
|
+
compactOutputChunks();
|
|
59
75
|
// Stream to callback
|
|
60
76
|
if (options?.onChunk) {
|
|
61
77
|
options.onChunk(text);
|
|
62
78
|
}
|
|
63
79
|
};
|
|
80
|
+
const finishDecoder = () => {
|
|
81
|
+
const finalText = sanitizeBinaryOutput(stripAnsi(decoder.decode())).replace(/\r/g, "");
|
|
82
|
+
if (finalText.length > 0) {
|
|
83
|
+
onData(Buffer.from(finalText, "utf-8"));
|
|
84
|
+
}
|
|
85
|
+
};
|
|
64
86
|
try {
|
|
65
87
|
const result = await operations.exec(command, cwd, {
|
|
66
88
|
onData,
|
|
67
89
|
signal: options?.signal,
|
|
68
90
|
});
|
|
69
|
-
|
|
91
|
+
finishDecoder();
|
|
92
|
+
const fullOutput = outputText();
|
|
70
93
|
const truncationResult = truncateTail(fullOutput);
|
|
71
94
|
if (truncationResult.truncated) {
|
|
72
95
|
ensureTempFile();
|
|
@@ -86,7 +109,8 @@ export async function executeBashWithOperations(command, cwd, operations, option
|
|
|
86
109
|
catch (err) {
|
|
87
110
|
// Check if it was an abort
|
|
88
111
|
if (options?.signal?.aborted) {
|
|
89
|
-
|
|
112
|
+
finishDecoder();
|
|
113
|
+
const fullOutput = outputText();
|
|
90
114
|
const truncationResult = truncateTail(fullOutput);
|
|
91
115
|
if (truncationResult.truncated) {
|
|
92
116
|
ensureTempFile();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bash-executor.js","sourceRoot":"","sources":["../../src/core/bash-executor.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAoB,MAAM,SAAS,CAAC;AAC9D,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAEzD,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AA0BtE,+EAA+E;AAC/E,iBAAiB;AACjB,+EAA+E;AAE/E;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC9C,OAAe,EACf,GAAW,EACX,UAA0B,EAC1B,OAA6B;IAE7B,MAAM,YAAY,GAAa,EAAE,CAAC;IAClC,IAAI,WAAW,GAAG,CAAC,CAAC;IACpB,MAAM,cAAc,GAAG,iBAAiB,GAAG,CAAC,CAAC;IAE7C,IAAI,YAAgC,CAAC;IACrC,IAAI,cAAuC,CAAC;IAC5C,IAAI,UAAU,GAAG,CAAC,CAAC;IAEnB,MAAM,cAAc,GAAG,GAAG,EAAE;QAC3B,IAAI,YAAY,EAAE,CAAC;YAClB,OAAO;QACR,CAAC;QACD,MAAM,EAAE,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC1C,YAAY,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC;QACnD,cAAc,GAAG,iBAAiB,CAAC,YAAY,CAAC,CAAC;QACjD,KAAK,MAAM,KAAK,
|
|
1
|
+
{"version":3,"file":"bash-executor.js","sourceRoot":"","sources":["../../src/core/bash-executor.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Bash command execution with streaming support and cancellation.\n *\n * This module provides a unified bash execution implementation used by:\n * - AgentSession.executeBash() for interactive and RPC modes\n * - Direct calls from modes that need bash execution\n */\n\nimport { randomBytes } from \"node:crypto\";\nimport { createWriteStream, type WriteStream } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { stripAnsi } from \"../utils/ansi.ts\";\nimport { sanitizeBinaryOutput } from \"../utils/shell.ts\";\nimport type { BashOperations } from \"./tools/bash.ts\";\nimport { DEFAULT_MAX_BYTES, truncateTail } from \"./tools/truncate.ts\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface BashExecutorOptions {\n\t/** Callback for streaming output chunks (already sanitized) */\n\tonChunk?: (chunk: string) => void;\n\t/** AbortSignal for cancellation */\n\tsignal?: AbortSignal;\n}\n\nexport interface BashResult {\n\t/** Combined stdout + stderr output (sanitized, possibly truncated) */\n\toutput: string;\n\t/** Process exit code (undefined if killed/cancelled) */\n\texitCode: number | undefined;\n\t/** Whether the command was cancelled via signal */\n\tcancelled: boolean;\n\t/** Whether the output was truncated */\n\ttruncated: boolean;\n\t/** Path to temp file containing full output (if output exceeded truncation threshold) */\n\tfullOutputPath?: string;\n}\n\n// ============================================================================\n// Implementation\n// ============================================================================\n\n/**\n * Execute a bash command using custom BashOperations.\n * Used for remote execution (SSH, containers, etc.).\n */\nexport async function executeBashWithOperations(\n\tcommand: string,\n\tcwd: string,\n\toperations: BashOperations,\n\toptions?: BashExecutorOptions,\n): Promise<BashResult> {\n\tconst outputChunks: string[] = [];\n\tlet outputChunkStart = 0;\n\tlet outputBytes = 0;\n\tconst maxOutputBytes = DEFAULT_MAX_BYTES * 2;\n\n\tlet tempFilePath: string | undefined;\n\tlet tempFileStream: WriteStream | undefined;\n\tlet totalBytes = 0;\n\n\tconst compactOutputChunks = () => {\n\t\tif (outputChunkStart < 64) {\n\t\t\treturn;\n\t\t}\n\t\toutputChunks.splice(0, outputChunkStart);\n\t\toutputChunkStart = 0;\n\t};\n\n\tconst outputText = () => outputChunks.slice(outputChunkStart).join(\"\");\n\n\tconst ensureTempFile = () => {\n\t\tif (tempFilePath) {\n\t\t\treturn;\n\t\t}\n\t\tconst id = randomBytes(8).toString(\"hex\");\n\t\ttempFilePath = join(tmpdir(), `pi-bash-${id}.log`);\n\t\ttempFileStream = createWriteStream(tempFilePath);\n\t\tfor (let i = outputChunkStart; i < outputChunks.length; i++) {\n\t\t\tconst chunk = outputChunks[i];\n\t\t\tif (chunk !== undefined) {\n\t\t\t\ttempFileStream.write(chunk);\n\t\t\t}\n\t\t}\n\t};\n\n\tconst decoder = new TextDecoder();\n\n\tconst onData = (data: Buffer) => {\n\t\ttotalBytes += data.length;\n\n\t\t// Sanitize: strip ANSI, replace binary garbage, normalize newlines\n\t\tconst text = sanitizeBinaryOutput(stripAnsi(decoder.decode(data, { stream: true }))).replace(/\\r/g, \"\");\n\n\t\t// Start writing to temp file if exceeds threshold\n\t\tif (totalBytes > DEFAULT_MAX_BYTES) {\n\t\t\tensureTempFile();\n\t\t}\n\n\t\tif (tempFileStream) {\n\t\t\ttempFileStream.write(text);\n\t\t}\n\n\t\toutputChunks.push(text);\n\t\toutputBytes += text.length;\n\t\twhile (outputBytes > maxOutputBytes && outputChunkStart < outputChunks.length - 1) {\n\t\t\tconst removed = outputChunks[outputChunkStart];\n\t\t\tif (removed === undefined) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\toutputBytes -= removed.length;\n\t\t\toutputChunkStart++;\n\t\t}\n\t\tcompactOutputChunks();\n\n\t\t// Stream to callback\n\t\tif (options?.onChunk) {\n\t\t\toptions.onChunk(text);\n\t\t}\n\t};\n\n\tconst finishDecoder = () => {\n\t\tconst finalText = sanitizeBinaryOutput(stripAnsi(decoder.decode())).replace(/\\r/g, \"\");\n\t\tif (finalText.length > 0) {\n\t\t\tonData(Buffer.from(finalText, \"utf-8\"));\n\t\t}\n\t};\n\n\ttry {\n\t\tconst result = await operations.exec(command, cwd, {\n\t\t\tonData,\n\t\t\tsignal: options?.signal,\n\t\t});\n\n\t\tfinishDecoder();\n\t\tconst fullOutput = outputText();\n\t\tconst truncationResult = truncateTail(fullOutput);\n\t\tif (truncationResult.truncated) {\n\t\t\tensureTempFile();\n\t\t}\n\t\tif (tempFileStream) {\n\t\t\ttempFileStream.end();\n\t\t}\n\t\tconst cancelled = options?.signal?.aborted ?? false;\n\n\t\treturn {\n\t\t\toutput: truncationResult.truncated ? truncationResult.content : fullOutput,\n\t\t\texitCode: cancelled ? undefined : (result.exitCode ?? undefined),\n\t\t\tcancelled,\n\t\t\ttruncated: truncationResult.truncated,\n\t\t\tfullOutputPath: tempFilePath,\n\t\t};\n\t} catch (err) {\n\t\t// Check if it was an abort\n\t\tif (options?.signal?.aborted) {\n\t\t\tfinishDecoder();\n\t\t\tconst fullOutput = outputText();\n\t\t\tconst truncationResult = truncateTail(fullOutput);\n\t\t\tif (truncationResult.truncated) {\n\t\t\t\tensureTempFile();\n\t\t\t}\n\t\t\tif (tempFileStream) {\n\t\t\t\ttempFileStream.end();\n\t\t\t}\n\t\t\treturn {\n\t\t\t\toutput: truncationResult.truncated ? truncationResult.content : fullOutput,\n\t\t\t\texitCode: undefined,\n\t\t\t\tcancelled: true,\n\t\t\t\ttruncated: truncationResult.truncated,\n\t\t\t\tfullOutputPath: tempFilePath,\n\t\t\t};\n\t\t}\n\n\t\tif (tempFileStream) {\n\t\t\ttempFileStream.end();\n\t\t}\n\n\t\tthrow err;\n\t}\n}\n"]}
|
|
@@ -25,7 +25,6 @@
|
|
|
25
25
|
export declare const POST_COMPACTION_MONITOR_COUNT = 5;
|
|
26
26
|
export declare const POST_COMPACTION_NO_TEXT_THRESHOLD = 3;
|
|
27
27
|
export declare const MAX_RECOVERY_ATTEMPTS = 3;
|
|
28
|
-
export declare const RECOVERY_COMPACTION_SUPPRESSION_MS = 5000;
|
|
29
28
|
export declare const RECOVERY_INSTRUCTIONS = "RECOVERY: prior compaction caused degraded responses; rebuild context";
|
|
30
29
|
export declare const RECOVERY_NOTIFICATION = "Detected repeated no-text assistant responses; retried compaction recovery.";
|
|
31
30
|
export interface DegradationMonitorState {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"degradation-monitor.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/compaction/degradation-monitor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,eAAO,MAAM,6BAA6B,IAAI,CAAC;AAC/C,eAAO,MAAM,iCAAiC,IAAI,CAAC;AACnD,eAAO,MAAM,qBAAqB,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"degradation-monitor.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/compaction/degradation-monitor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,eAAO,MAAM,6BAA6B,IAAI,CAAC;AAC/C,eAAO,MAAM,iCAAiC,IAAI,CAAC;AACnD,eAAO,MAAM,qBAAqB,IAAI,CAAC;AAEvC,eAAO,MAAM,qBAAqB,0EAA0E,CAAC;AAC7G,eAAO,MAAM,qBAAqB,gFAAgF,CAAC;AAEnH,MAAM,WAAW,uBAAuB;IACvC,4BAA4B,EAAE,MAAM,CAAC;IACrC,aAAa,EAAE,MAAM,CAAC;IACtB,0BAA0B,EAAE,OAAO,CAAC;IACpC,gBAAgB,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,yBAAyB;IACzC,eAAe,EAAE,CAAC,OAAO,EAAE;QAAE,kBAAkB,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC5G,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC;AAED,UAAU,2BAA2B;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED,UAAU,qBAAqB;IAC9B,OAAO,EAAE;QACR,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,2BAA2B,EAAE,CAAC;KACvC,CAAC;CACF;AAED,wBAAgB,6BAA6B,IAAI,uBAAuB,CAOvE;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,uBAAuB,GAAG,IAAI,CAI1E;AAcD,wBAAsB,gBAAgB,CACrC,KAAK,EAAE,uBAAuB,EAC9B,KAAK,EAAE,qBAAqB,EAC5B,OAAO,EAAE,yBAAyB,GAChC,OAAO,CAAC,IAAI,CAAC,CA8Bf;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,uBAAuB,GAAG,IAAI,CAIlE"}
|
|
@@ -25,7 +25,6 @@
|
|
|
25
25
|
export const POST_COMPACTION_MONITOR_COUNT = 5;
|
|
26
26
|
export const POST_COMPACTION_NO_TEXT_THRESHOLD = 3;
|
|
27
27
|
export const MAX_RECOVERY_ATTEMPTS = 3;
|
|
28
|
-
export const RECOVERY_COMPACTION_SUPPRESSION_MS = 5_000;
|
|
29
28
|
export const RECOVERY_INSTRUCTIONS = "RECOVERY: prior compaction caused degraded responses; rebuild context";
|
|
30
29
|
export const RECOVERY_NOTIFICATION = "Detected repeated no-text assistant responses; retried compaction recovery.";
|
|
31
30
|
export function createDegradationMonitorState() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"degradation-monitor.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/compaction/degradation-monitor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,CAAC;AAC/C,MAAM,CAAC,MAAM,iCAAiC,GAAG,CAAC,CAAC;AACnD,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"degradation-monitor.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/compaction/degradation-monitor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,CAAC;AAC/C,MAAM,CAAC,MAAM,iCAAiC,GAAG,CAAC,CAAC;AACnD,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC;AAEvC,MAAM,CAAC,MAAM,qBAAqB,GAAG,uEAAuE,CAAC;AAC7G,MAAM,CAAC,MAAM,qBAAqB,GAAG,6EAA6E,CAAC;AA0BnH,MAAM,UAAU,6BAA6B;IAC5C,OAAO;QACN,4BAA4B,EAAE,CAAC;QAC/B,aAAa,EAAE,CAAC;QAChB,0BAA0B,EAAE,KAAK;QACjC,gBAAgB,EAAE,CAAC;KACnB,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,KAA8B;IACnE,KAAK,CAAC,4BAA4B,GAAG,6BAA6B,CAAC;IACnE,KAAK,CAAC,aAAa,GAAG,CAAC,CAAC;IACxB,KAAK,CAAC,0BAA0B,GAAG,KAAK,CAAC;AAC1C,CAAC;AAED,SAAS,uBAAuB,CAAC,KAA4B;IAC5D,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;QACxC,OAAO,IAAI,CAAC;IACb,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QAC1C,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACnF,OAAO,IAAI,CAAC;QACb,CAAC;IACF,CAAC;IACD,OAAO,KAAK,CAAC;AACd,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACrC,KAA8B,EAC9B,KAA4B,EAC5B,OAAkC;IAElC,IAAI,KAAK,CAAC,4BAA4B,IAAI,CAAC,EAAE,CAAC;QAC7C,OAAO;IACR,CAAC;IAED,IAAI,uBAAuB,CAAC,KAAK,CAAC,EAAE,CAAC;QACpC,KAAK,CAAC,aAAa,GAAG,CAAC,CAAC;QACxB,OAAO;IACR,CAAC;IAED,KAAK,CAAC,aAAa,IAAI,CAAC,CAAC;IAEzB,IAAI,KAAK,CAAC,aAAa,GAAG,iCAAiC,EAAE,CAAC;QAC7D,OAAO;IACR,CAAC;IAED,IAAI,KAAK,CAAC,0BAA0B,EAAE,CAAC;QACtC,OAAO;IACR,CAAC;IAED,IAAI,KAAK,CAAC,gBAAgB,IAAI,qBAAqB,EAAE,CAAC;QACrD,OAAO;IACR,CAAC;IAED,KAAK,CAAC,0BAA0B,GAAG,IAAI,CAAC;IACxC,KAAK,CAAC,gBAAgB,IAAI,CAAC,CAAC;IAC5B,KAAK,CAAC,aAAa,GAAG,CAAC,CAAC;IAExB,MAAM,OAAO,CAAC,eAAe,CAAC,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,CAAC,CAAC;IAC7E,OAAO,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAA8B;IAC3D,IAAI,KAAK,CAAC,4BAA4B,GAAG,CAAC,EAAE,CAAC;QAC5C,KAAK,CAAC,4BAA4B,IAAI,CAAC,CAAC;IACzC,CAAC;AACF,CAAC","sourcesContent":["/**\n * Post-compaction degradation monitor.\n *\n * Watches the first POST_COMPACTION_MONITOR_COUNT assistant turns after a\n * compaction completes and triggers a single recovery compaction if the\n * model emits POST_COMPACTION_NO_TEXT_THRESHOLD consecutive assistant\n * messages with no text content (only step-start/step-finish parts).\n *\n * Algorithm ported from omo's preemptive-compaction-degradation-monitor:\n * `/Users/yeongyu/local-workspaces/omo/src/hooks/preemptive-compaction-degradation-monitor.ts`\n *\n * Pi extension surface differences vs omo:\n * - Recovery dispatch: speculative generation plus `ctx.applyCompaction(...)`\n * instead of omo's `client.session.summarize(...)`. The \"RECOVERY:\" prefix\n * in customInstructions is the disambiguator; CompactionReason stays\n * \"extension\" (no new variant in v1).\n * - Notification: `ctx.notify(message)` instead of omo's\n * `client.tui.showToast(...)`.\n *\n * Recovery cap: 1 per compaction cycle (gate via recoveryTriggeredThisCycle).\n * MAX_RECOVERY_ATTEMPTS = 3 is exported for future iteration but the v1 cycle\n * gate keeps the effective cap at 1 — recoveryAttempts is incremented only on\n * successful trigger, so once it hits 1 the cycle gate also fires regardless.\n */\n\nexport const POST_COMPACTION_MONITOR_COUNT = 5;\nexport const POST_COMPACTION_NO_TEXT_THRESHOLD = 3;\nexport const MAX_RECOVERY_ATTEMPTS = 3;\n\nexport const RECOVERY_INSTRUCTIONS = \"RECOVERY: prior compaction caused degraded responses; rebuild context\";\nexport const RECOVERY_NOTIFICATION = \"Detected repeated no-text assistant responses; retried compaction recovery.\";\n\nexport interface DegradationMonitorState {\n\tpostCompactionTurnsRemaining: number;\n\tnoTextCounter: number;\n\trecoveryTriggeredThisCycle: boolean;\n\trecoveryAttempts: number;\n}\n\nexport interface DegradationMonitorContext {\n\tapplyCompaction: (options: { customInstructions: string }) => Promise<{ applied: boolean; reason: string }>;\n\tnotify: (message: string) => void;\n}\n\ninterface MonitoredMessageContentPart {\n\ttype: string;\n\ttext?: string;\n}\n\ninterface MonitoredMessageEvent {\n\tmessage: {\n\t\trole: string;\n\t\tcontent: MonitoredMessageContentPart[];\n\t};\n}\n\nexport function createDegradationMonitorState(): DegradationMonitorState {\n\treturn {\n\t\tpostCompactionTurnsRemaining: 0,\n\t\tnoTextCounter: 0,\n\t\trecoveryTriggeredThisCycle: false,\n\t\trecoveryAttempts: 0,\n\t};\n}\n\n/**\n * Reset the per-cycle monitor fields when a fresh compaction completes.\n * Opens a new POST_COMPACTION_MONITOR_COUNT-turn window and clears the\n * cycle-trigger gate. recoveryAttempts is preserved across cycles so the\n * MAX_RECOVERY_ATTEMPTS ceiling remains a session-wide guard.\n */\nexport function resetOnSessionCompact(state: DegradationMonitorState): void {\n\tstate.postCompactionTurnsRemaining = POST_COMPACTION_MONITOR_COUNT;\n\tstate.noTextCounter = 0;\n\tstate.recoveryTriggeredThisCycle = false;\n}\n\nfunction assistantMessageHasText(event: MonitoredMessageEvent): boolean {\n\tif (event.message.role !== \"assistant\") {\n\t\treturn true;\n\t}\n\tfor (const part of event.message.content) {\n\t\tif (part.type === \"text\" && typeof part.text === \"string\" && part.text.length > 0) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\nexport async function handleMessageEnd(\n\tstate: DegradationMonitorState,\n\tevent: MonitoredMessageEvent,\n\tcontext: DegradationMonitorContext,\n): Promise<void> {\n\tif (state.postCompactionTurnsRemaining <= 0) {\n\t\treturn;\n\t}\n\n\tif (assistantMessageHasText(event)) {\n\t\tstate.noTextCounter = 0;\n\t\treturn;\n\t}\n\n\tstate.noTextCounter += 1;\n\n\tif (state.noTextCounter < POST_COMPACTION_NO_TEXT_THRESHOLD) {\n\t\treturn;\n\t}\n\n\tif (state.recoveryTriggeredThisCycle) {\n\t\treturn;\n\t}\n\n\tif (state.recoveryAttempts >= MAX_RECOVERY_ATTEMPTS) {\n\t\treturn;\n\t}\n\n\tstate.recoveryTriggeredThisCycle = true;\n\tstate.recoveryAttempts += 1;\n\tstate.noTextCounter = 0;\n\n\tawait context.applyCompaction({ customInstructions: RECOVERY_INSTRUCTIONS });\n\tcontext.notify(RECOVERY_NOTIFICATION);\n}\n\nexport function handleTurnEnd(state: DegradationMonitorState): void {\n\tif (state.postCompactionTurnsRemaining > 0) {\n\t\tstate.postCompactionTurnsRemaining -= 1;\n\t}\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/compaction/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAgB,YAAY,EAA+C,MAAM,gBAAgB,CAAC;AAuI9G,MAAM,CAAC,OAAO,UAAU,mBAAmB,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/compaction/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAgB,YAAY,EAA+C,MAAM,gBAAgB,CAAC;AAuI9G,MAAM,CAAC,OAAO,UAAU,mBAAmB,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CAuTlE"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
|
-
import { DEFAULT_COMPACTION_SETTINGS } from "../../../compaction/index.js";
|
|
3
2
|
import { convertToLlm } from "../../../messages.js";
|
|
4
3
|
import * as checkpointState from "./checkpoint-state.js";
|
|
5
4
|
import * as breaker from "./circuit-breaker.js";
|
|
@@ -247,15 +246,16 @@ export default function compactionExtension(pi) {
|
|
|
247
246
|
resetOnSessionCompact(degradationState);
|
|
248
247
|
todoBridge.restoreTodosIfMissing(pi, ctx);
|
|
249
248
|
const usage = ctx.getContextUsage();
|
|
250
|
-
|
|
249
|
+
const settings = ctx.getCompactionSettings();
|
|
250
|
+
if (settings.restorationEnabled ?? true) {
|
|
251
251
|
restoration.preparePendingPayload(restorationState, {
|
|
252
252
|
accepted: true,
|
|
253
253
|
reason: event.reason,
|
|
254
254
|
compactionEntryId: event.compactionEntry.id,
|
|
255
255
|
contextWindow: usage?.contextWindow ?? ctx.model?.contextWindow ?? DEFAULT_CONTEXT_WINDOW,
|
|
256
256
|
usageTokens: usage?.tokens ?? null,
|
|
257
|
-
reserveTokens:
|
|
258
|
-
settings
|
|
257
|
+
reserveTokens: settings.reserveTokens,
|
|
258
|
+
settings,
|
|
259
259
|
keptMessages: keptEntries.flatMap((entry) => {
|
|
260
260
|
if (entry.type !== "message")
|
|
261
261
|
return [];
|