@oh-my-pi/pi-coding-agent 3.33.0 → 3.35.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/CHANGELOG.md +57 -8
- package/docs/custom-tools.md +1 -1
- package/docs/extensions.md +4 -4
- package/docs/hooks.md +2 -2
- package/docs/sdk.md +4 -8
- package/examples/custom-tools/README.md +2 -2
- package/examples/extensions/README.md +1 -1
- package/examples/extensions/todo.ts +1 -1
- package/examples/hooks/custom-compaction.ts +4 -2
- package/examples/hooks/handoff.ts +1 -1
- package/examples/hooks/qna.ts +1 -1
- package/examples/sdk/02-custom-model.ts +1 -1
- package/examples/sdk/README.md +1 -1
- package/package.json +5 -5
- package/src/capability/ssh.ts +42 -0
- package/src/cli/file-processor.ts +1 -1
- package/src/cli/list-models.ts +1 -1
- package/src/core/agent-session.ts +214 -31
- package/src/core/auth-storage.ts +1 -1
- package/src/core/compaction/branch-summarization.ts +2 -2
- package/src/core/compaction/compaction.ts +2 -2
- package/src/core/compaction/utils.ts +1 -1
- package/src/core/custom-tools/types.ts +1 -1
- package/src/core/extensions/runner.ts +1 -1
- package/src/core/extensions/types.ts +1 -1
- package/src/core/extensions/wrapper.ts +1 -1
- package/src/core/hooks/runner.ts +2 -2
- package/src/core/hooks/types.ts +1 -1
- package/src/core/index.ts +11 -0
- package/src/core/messages.ts +1 -1
- package/src/core/model-registry.ts +1 -1
- package/src/core/model-resolver.ts +7 -6
- package/src/core/sdk.ts +33 -4
- package/src/core/session-manager.ts +16 -1
- package/src/core/settings-manager.ts +20 -6
- package/src/core/ssh/connection-manager.ts +466 -0
- package/src/core/ssh/ssh-executor.ts +190 -0
- package/src/core/ssh/sshfs-mount.ts +162 -0
- package/src/core/ssh-executor.ts +5 -0
- package/src/core/system-prompt.ts +424 -1
- package/src/core/title-generator.ts +2 -2
- package/src/core/tools/edit.ts +1 -0
- package/src/core/tools/grep.ts +1 -1
- package/src/core/tools/index.test.ts +1 -0
- package/src/core/tools/index.ts +5 -0
- package/src/core/tools/output.ts +1 -1
- package/src/core/tools/read.ts +24 -11
- package/src/core/tools/renderers.ts +3 -0
- package/src/core/tools/ssh.ts +302 -0
- package/src/core/tools/task/index.ts +11 -2
- package/src/core/tools/task/model-resolver.ts +5 -4
- package/src/core/tools/task/types.ts +1 -1
- package/src/core/tools/task/worker.ts +1 -1
- package/src/core/voice.ts +1 -1
- package/src/discovery/index.ts +3 -0
- package/src/discovery/ssh.ts +162 -0
- package/src/main.ts +4 -1
- package/src/modes/interactive/components/assistant-message.ts +1 -1
- package/src/modes/interactive/components/custom-message.ts +1 -1
- package/src/modes/interactive/components/footer.ts +1 -1
- package/src/modes/interactive/components/hook-message.ts +1 -1
- package/src/modes/interactive/components/model-selector.ts +1 -1
- package/src/modes/interactive/components/oauth-selector.ts +1 -1
- package/src/modes/interactive/components/status-line.ts +1 -1
- package/src/modes/interactive/components/tool-execution.ts +15 -12
- package/src/modes/interactive/interactive-mode.ts +43 -9
- package/src/modes/print-mode.ts +1 -1
- package/src/modes/rpc/rpc-client.ts +1 -1
- package/src/modes/rpc/rpc-types.ts +1 -1
- package/src/prompts/system-prompt.md +4 -0
- package/src/prompts/tools/ssh.md +74 -0
- package/src/utils/image-resize.ts +1 -1
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
import * as fs from "node:fs";
|
|
7
7
|
import * as os from "node:os";
|
|
8
8
|
import * as path from "node:path";
|
|
9
|
-
import type { AssistantMessage, ImageContent, Message, OAuthProvider } from "@mariozechner/pi-ai";
|
|
10
9
|
import type { AgentMessage, ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
10
|
+
import type { AssistantMessage, ImageContent, Message, OAuthProvider } from "@oh-my-pi/pi-ai";
|
|
11
11
|
import type { SlashCommand } from "@oh-my-pi/pi-tui";
|
|
12
12
|
import {
|
|
13
13
|
CombinedAutocompleteProvider,
|
|
@@ -38,6 +38,7 @@ import { VoiceSupervisor } from "../../core/voice-supervisor";
|
|
|
38
38
|
import { disableProvider, enableProvider } from "../../discovery";
|
|
39
39
|
import { getChangelogPath, parseChangelog } from "../../utils/changelog";
|
|
40
40
|
import { copyToClipboard, readImageFromClipboard } from "../../utils/clipboard";
|
|
41
|
+
import { resizeImage } from "../../utils/image-resize";
|
|
41
42
|
import { registerAsyncCleanup } from "../cleanup";
|
|
42
43
|
import { ArminComponent } from "./components/armin";
|
|
43
44
|
import { AssistantMessageComponent } from "./components/assistant-message";
|
|
@@ -1139,7 +1140,9 @@ export class InteractiveMode {
|
|
|
1139
1140
|
if (this.session.isStreaming) {
|
|
1140
1141
|
this.editor.addToHistory(text);
|
|
1141
1142
|
this.editor.setText("");
|
|
1142
|
-
|
|
1143
|
+
const images = this.pendingImages.length > 0 ? [...this.pendingImages] : undefined;
|
|
1144
|
+
this.pendingImages = [];
|
|
1145
|
+
await this.session.prompt(text, { streamingBehavior: "steer", images });
|
|
1143
1146
|
this.updatePendingMessagesDisplay();
|
|
1144
1147
|
this.ui.requestRender();
|
|
1145
1148
|
return;
|
|
@@ -1504,22 +1507,24 @@ export class InteractiveMode {
|
|
|
1504
1507
|
* If multiple status messages are emitted back-to-back (without anything else being added to the chat),
|
|
1505
1508
|
* we update the previous status line instead of appending new ones to avoid log spam.
|
|
1506
1509
|
*/
|
|
1507
|
-
private showStatus(message: string): void {
|
|
1510
|
+
private showStatus(message: string, options?: { dim?: boolean }): void {
|
|
1508
1511
|
if (this.isBackgrounded) {
|
|
1509
1512
|
return;
|
|
1510
1513
|
}
|
|
1511
1514
|
const children = this.chatContainer.children;
|
|
1512
1515
|
const last = children.length > 0 ? children[children.length - 1] : undefined;
|
|
1513
1516
|
const secondLast = children.length > 1 ? children[children.length - 2] : undefined;
|
|
1517
|
+
const useDim = options?.dim ?? true;
|
|
1518
|
+
const rendered = useDim ? theme.fg("dim", message) : message;
|
|
1514
1519
|
|
|
1515
1520
|
if (last && secondLast && last === this.lastStatusText && secondLast === this.lastStatusSpacer) {
|
|
1516
|
-
this.lastStatusText.setText(
|
|
1521
|
+
this.lastStatusText.setText(rendered);
|
|
1517
1522
|
this.ui.requestRender();
|
|
1518
1523
|
return;
|
|
1519
1524
|
}
|
|
1520
1525
|
|
|
1521
1526
|
const spacer = new Spacer(1);
|
|
1522
|
-
const text = new Text(
|
|
1527
|
+
const text = new Text(rendered, 1, 0);
|
|
1523
1528
|
this.chatContainer.addChild(spacer);
|
|
1524
1529
|
this.chatContainer.addChild(text);
|
|
1525
1530
|
this.lastStatusSpacer = spacer;
|
|
@@ -1822,10 +1827,24 @@ export class InteractiveMode {
|
|
|
1822
1827
|
try {
|
|
1823
1828
|
const image = await readImageFromClipboard();
|
|
1824
1829
|
if (image) {
|
|
1830
|
+
let imageData = image;
|
|
1831
|
+
if (this.settingsManager.getImageAutoResize()) {
|
|
1832
|
+
try {
|
|
1833
|
+
const resized = await resizeImage({
|
|
1834
|
+
type: "image",
|
|
1835
|
+
data: image.data,
|
|
1836
|
+
mimeType: image.mimeType,
|
|
1837
|
+
});
|
|
1838
|
+
imageData = { data: resized.data, mimeType: resized.mimeType };
|
|
1839
|
+
} catch {
|
|
1840
|
+
imageData = image;
|
|
1841
|
+
}
|
|
1842
|
+
}
|
|
1843
|
+
|
|
1825
1844
|
this.pendingImages.push({
|
|
1826
1845
|
type: "image",
|
|
1827
|
-
data:
|
|
1828
|
-
mimeType:
|
|
1846
|
+
data: imageData.data,
|
|
1847
|
+
mimeType: imageData.mimeType,
|
|
1829
1848
|
});
|
|
1830
1849
|
// Insert styled placeholder at cursor like Claude does
|
|
1831
1850
|
const imageNum = this.pendingImages.length;
|
|
@@ -1980,7 +1999,8 @@ export class InteractiveMode {
|
|
|
1980
1999
|
|
|
1981
2000
|
private async cycleRoleModel(options?: { temporary?: boolean }): Promise<void> {
|
|
1982
2001
|
try {
|
|
1983
|
-
const
|
|
2002
|
+
const roleOrder = ["slow", "default", "smol"];
|
|
2003
|
+
const result = await this.session.cycleRoleModels(roleOrder, options);
|
|
1984
2004
|
if (!result) {
|
|
1985
2005
|
this.showStatus("Only one role model available");
|
|
1986
2006
|
return;
|
|
@@ -1989,10 +2009,24 @@ export class InteractiveMode {
|
|
|
1989
2009
|
this.statusLine.invalidate();
|
|
1990
2010
|
this.updateEditorBorderColor();
|
|
1991
2011
|
const roleLabel = result.role === "default" ? "default" : result.role;
|
|
2012
|
+
const roleLabelStyled = theme.bold(theme.fg("accent", roleLabel));
|
|
1992
2013
|
const thinkingStr =
|
|
1993
2014
|
result.model.reasoning && result.thinkingLevel !== "off" ? ` (thinking: ${result.thinkingLevel})` : "";
|
|
1994
2015
|
const tempLabel = options?.temporary ? " (temporary)" : "";
|
|
1995
|
-
|
|
2016
|
+
const cycleSeparator = theme.fg("dim", " > ");
|
|
2017
|
+
const cycleLabel = roleOrder
|
|
2018
|
+
.map((role) => {
|
|
2019
|
+
if (role === result.role) {
|
|
2020
|
+
return theme.bold(theme.fg("accent", role));
|
|
2021
|
+
}
|
|
2022
|
+
return theme.fg("muted", role);
|
|
2023
|
+
})
|
|
2024
|
+
.join(cycleSeparator);
|
|
2025
|
+
const orderLabel = ` (cycle: ${cycleLabel})`;
|
|
2026
|
+
this.showStatus(
|
|
2027
|
+
`Switched to ${roleLabelStyled}: ${result.model.name || result.model.id}${thinkingStr}${tempLabel}${orderLabel}`,
|
|
2028
|
+
{ dim: false },
|
|
2029
|
+
);
|
|
1996
2030
|
} catch (error) {
|
|
1997
2031
|
this.showError(error instanceof Error ? error.message : String(error));
|
|
1998
2032
|
}
|
package/src/modes/print-mode.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* - `omp --mode json "prompt"` - JSON event stream
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import type { AssistantMessage, ImageContent } from "@
|
|
9
|
+
import type { AssistantMessage, ImageContent } from "@oh-my-pi/pi-ai";
|
|
10
10
|
import type { AgentSession } from "../core/agent-session";
|
|
11
11
|
|
|
12
12
|
/**
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* Spawns the agent in RPC mode and provides a typed API for all operations.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import type { ImageContent } from "@mariozechner/pi-ai";
|
|
8
7
|
import type { AgentEvent, AgentMessage, ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
8
|
+
import type { ImageContent } from "@oh-my-pi/pi-ai";
|
|
9
9
|
import type { Subprocess } from "bun";
|
|
10
10
|
import type { SessionStats } from "../../core/agent-session";
|
|
11
11
|
import type { BashResult } from "../../core/bash-executor";
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* Responses and events are emitted as JSON lines on stdout.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import type { ImageContent, Model } from "@mariozechner/pi-ai";
|
|
9
8
|
import type { AgentMessage, ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
9
|
+
import type { ImageContent, Model } from "@oh-my-pi/pi-ai";
|
|
10
10
|
import type { SessionStats } from "../../core/agent-session";
|
|
11
11
|
import type { BashResult } from "../../core/bash-executor";
|
|
12
12
|
import type { CompactionResult } from "../../core/compaction/index";
|
|
@@ -21,6 +21,10 @@ Core behavior:
|
|
|
21
21
|
- After each tool result, check relevance; iterate or clarify if results conflict or are insufficient.
|
|
22
22
|
- Use concise, scannable responses; include file paths in backticks; use short bullets for multi-item lists; avoid dumping large files.
|
|
23
23
|
|
|
24
|
+
<environment>
|
|
25
|
+
{{environmentInfo}}
|
|
26
|
+
</environment>
|
|
27
|
+
|
|
24
28
|
Documentation:
|
|
25
29
|
- Main documentation: {{readmePath}}
|
|
26
30
|
- Additional docs: {{docsPath}}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
Execute commands on remote SSH hosts.
|
|
2
|
+
|
|
3
|
+
## Critical: Match Commands to Host Shell
|
|
4
|
+
|
|
5
|
+
Each host runs a specific shell. **You MUST use commands native to that shell.**
|
|
6
|
+
|
|
7
|
+
### Command Reference
|
|
8
|
+
|
|
9
|
+
**linux/bash, linux/zsh, macos/bash, macos/zsh** — Unix-like systems:
|
|
10
|
+
- Files: `ls`, `cat`, `head`, `tail`, `grep`, `find`
|
|
11
|
+
- System: `ps`, `top`, `df`, `uname`, `free` (Linux), `df`, `uname`, `top` (macOS)
|
|
12
|
+
- Navigation: `cd`, `pwd`
|
|
13
|
+
|
|
14
|
+
**windows/bash, windows/sh** — Windows with Unix compatibility layer (WSL, Cygwin, Git Bash):
|
|
15
|
+
- Files: `ls`, `cat`, `head`, `tail`, `grep`, `find`
|
|
16
|
+
- System: `ps`, `top`, `df`, `uname`
|
|
17
|
+
- Navigation: `cd`, `pwd`
|
|
18
|
+
- Note: These are Windows hosts but use Unix commands
|
|
19
|
+
|
|
20
|
+
**windows/powershell** — Native Windows PowerShell:
|
|
21
|
+
- Files: `Get-ChildItem`, `Get-Content`, `Select-String`
|
|
22
|
+
- System: `Get-Process`, `Get-ComputerInfo`
|
|
23
|
+
- Navigation: `Set-Location`, `Get-Location`
|
|
24
|
+
|
|
25
|
+
**windows/cmd** — Native Windows Command Prompt:
|
|
26
|
+
- Files: `dir`, `type`, `findstr`, `where`
|
|
27
|
+
- System: `tasklist`, `systeminfo`
|
|
28
|
+
- Navigation: `cd`, `echo %CD%`
|
|
29
|
+
|
|
30
|
+
## Execution Pattern
|
|
31
|
+
|
|
32
|
+
1. Check the host's shell type from "Available hosts" below
|
|
33
|
+
2. Use ONLY commands for that shell type
|
|
34
|
+
3. Construct your command using the reference above
|
|
35
|
+
|
|
36
|
+
## Examples
|
|
37
|
+
|
|
38
|
+
<example>
|
|
39
|
+
Task: List files in /home/user on host "server1"
|
|
40
|
+
Host: server1 (10.0.0.1) | linux/bash
|
|
41
|
+
Command: `ls -la /home/user`
|
|
42
|
+
</example>
|
|
43
|
+
|
|
44
|
+
<example>
|
|
45
|
+
Task: Show running processes on host "winbox"
|
|
46
|
+
Host: winbox (192.168.1.5) | windows/cmd
|
|
47
|
+
Command: `tasklist /v`
|
|
48
|
+
</example>
|
|
49
|
+
|
|
50
|
+
<example>
|
|
51
|
+
Task: Check disk usage on host "wsl-dev"
|
|
52
|
+
Host: wsl-dev (192.168.1.10) | windows/bash
|
|
53
|
+
Command: `df -h`
|
|
54
|
+
Note: Windows host with WSL — use Unix commands
|
|
55
|
+
</example>
|
|
56
|
+
|
|
57
|
+
<example>
|
|
58
|
+
Task: Get system info on host "macbook"
|
|
59
|
+
Host: macbook (10.0.0.20) | macos/zsh
|
|
60
|
+
Command: `uname -a && sw_vers`
|
|
61
|
+
</example>
|
|
62
|
+
|
|
63
|
+
## Parameters
|
|
64
|
+
|
|
65
|
+
- **host**: Host name from "Available hosts" below
|
|
66
|
+
- **command**: Command to execute (see Command Reference above)
|
|
67
|
+
- **cwd**: Working directory (optional)
|
|
68
|
+
- **timeout**: Timeout in seconds (optional)
|
|
69
|
+
|
|
70
|
+
## Output
|
|
71
|
+
|
|
72
|
+
Truncated at 50KB. Exit codes captured.
|
|
73
|
+
|
|
74
|
+
**Before executing: verify host shell type below and use matching commands.**
|