@heyhuynhgiabuu/pi-task 0.1.3 → 0.1.4
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 +23 -0
- package/dist/helpers.d.ts +3 -1
- package/dist/helpers.js +23 -2
- package/dist/index.js +21 -2
- package/dist/subagent/tmux.d.ts +4 -0
- package/dist/subagent/tmux.js +21 -10
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,29 @@ All notable changes to `@heyhuynhgiabuu/pi-task` are documented here.
|
|
|
4
4
|
The format is based on [Keep a Changelog](https://keepachangelog.com/),
|
|
5
5
|
and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
6
6
|
|
|
7
|
+
## [0.1.4] — 2026-06-21
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- Detect the current tmux pane size before launching a task pane and choose
|
|
12
|
+
the split direction based on available space: side-by-side for wide panes,
|
|
13
|
+
stacked for narrow panes.
|
|
14
|
+
- Target the exact pane that was measured when running `tmux split-window`,
|
|
15
|
+
avoiding focus races where a different pane could be split.
|
|
16
|
+
- Apply the same pane-size-aware split logic to the subagent tmux helper.
|
|
17
|
+
|
|
18
|
+
### Verified
|
|
19
|
+
|
|
20
|
+
- `npm test` passes
|
|
21
|
+
- `npm run typecheck` passes
|
|
22
|
+
- `npm run build` passes
|
|
23
|
+
- `npm run smoke` passes
|
|
24
|
+
- `npm pack --dry-run` succeeds
|
|
25
|
+
- Real tmux integration check passed for narrow `120x40` and wide `200x40`
|
|
26
|
+
sessions.
|
|
27
|
+
|
|
28
|
+
[0.1.4]: https://github.com/heyhuynhgiabuu/pi-task/releases/tag/v0.1.4
|
|
29
|
+
|
|
7
30
|
## [0.1.3] — 2026-06-21
|
|
8
31
|
|
|
9
32
|
### Fixed
|
package/dist/helpers.d.ts
CHANGED
|
@@ -50,7 +50,9 @@ export declare function parseResultXml(raw: string): ParsedResult;
|
|
|
50
50
|
export declare function formatMs(ms: number): string;
|
|
51
51
|
export declare function parseIdTimestamp(id: string): number;
|
|
52
52
|
export declare function shellQuote(value: string): string;
|
|
53
|
-
export
|
|
53
|
+
export type TmuxSplitDirection = "-h" | "-v";
|
|
54
|
+
export declare function chooseTmuxSplitDirection(paneWidth: number, paneHeight: number): TmuxSplitDirection;
|
|
55
|
+
export declare function buildTmuxSplitWindowArgs(cwd: string, command: string, direction?: TmuxSplitDirection, targetPane?: string | null): string[];
|
|
54
56
|
export interface BackgroundReceiptInput {
|
|
55
57
|
taskId: string;
|
|
56
58
|
agentType: string;
|
package/dist/helpers.js
CHANGED
|
@@ -128,8 +128,29 @@ export function parseIdTimestamp(id) {
|
|
|
128
128
|
export function shellQuote(value) {
|
|
129
129
|
return `'${value.replace(/'/g, `'"'"'`)}'`;
|
|
130
130
|
}
|
|
131
|
-
export function
|
|
132
|
-
|
|
131
|
+
export function chooseTmuxSplitDirection(paneWidth, paneHeight) {
|
|
132
|
+
const minSideBySideWidth = 160;
|
|
133
|
+
const minStackedHeight = 24;
|
|
134
|
+
if (Number.isFinite(paneWidth) && paneWidth >= minSideBySideWidth) {
|
|
135
|
+
return "-h";
|
|
136
|
+
}
|
|
137
|
+
if (Number.isFinite(paneHeight) && paneHeight >= minStackedHeight) {
|
|
138
|
+
return "-v";
|
|
139
|
+
}
|
|
140
|
+
return "-h";
|
|
141
|
+
}
|
|
142
|
+
export function buildTmuxSplitWindowArgs(cwd, command, direction = "-h", targetPane) {
|
|
143
|
+
const args = [
|
|
144
|
+
"split-window",
|
|
145
|
+
direction,
|
|
146
|
+
"-P",
|
|
147
|
+
"-F",
|
|
148
|
+
"#{pane_id}",
|
|
149
|
+
];
|
|
150
|
+
if (targetPane)
|
|
151
|
+
args.push("-t", targetPane);
|
|
152
|
+
args.push("-c", cwd, command);
|
|
153
|
+
return args;
|
|
133
154
|
}
|
|
134
155
|
export function formatBackgroundReceipt(input) {
|
|
135
156
|
return [
|
package/dist/index.js
CHANGED
|
@@ -22,7 +22,7 @@ import { dirname, join } from "node:path";
|
|
|
22
22
|
import { fileURLToPath } from "node:url";
|
|
23
23
|
import { Type } from "@sinclair/typebox";
|
|
24
24
|
import { Text, truncateToWidth } from "@earendil-works/pi-tui";
|
|
25
|
-
import { TASK_BACKGROUND_DEFAULT, TASK_RESULT_XML_INSTRUCTIONS, TASK_TOOL_DESCRIPTION, buildTmuxSplitWindowArgs, formatBackgroundReceipt, buildPiArgs, parseResultXml, formatMs, shellQuote, discoverAgents, formatAgentList, countToolUses, readRecentToolCalls, } from "./helpers.js";
|
|
25
|
+
import { TASK_BACKGROUND_DEFAULT, TASK_RESULT_XML_INSTRUCTIONS, TASK_TOOL_DESCRIPTION, buildTmuxSplitWindowArgs, chooseTmuxSplitDirection, formatBackgroundReceipt, buildPiArgs, parseResultXml, formatMs, shellQuote, discoverAgents, formatAgentList, countToolUses, readRecentToolCalls, } from "./helpers.js";
|
|
26
26
|
import { runSdkSubagent } from "./subagent/runSdk.js";
|
|
27
27
|
import { checkTaskCompletion, waitForTaskCompletion as waitForSessionTaskCompletion, } from "./subagent/waitCompletion.js";
|
|
28
28
|
import { buildAgentToolSelection } from "./agent-tools.js";
|
|
@@ -79,9 +79,28 @@ function getCurrentPaneId() {
|
|
|
79
79
|
return null;
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
|
+
function getCurrentPaneSize(targetPane) {
|
|
83
|
+
try {
|
|
84
|
+
const args = ["display-message", "-p", "#{pane_width} #{pane_height}"];
|
|
85
|
+
if (targetPane)
|
|
86
|
+
args.splice(1, 0, "-t", targetPane);
|
|
87
|
+
const raw = tmuxCmd(args);
|
|
88
|
+
const [widthRaw, heightRaw] = raw.trim().split(/\s+/, 2);
|
|
89
|
+
const width = Number(widthRaw);
|
|
90
|
+
const height = Number(heightRaw);
|
|
91
|
+
if (!Number.isFinite(width) || !Number.isFinite(height))
|
|
92
|
+
return null;
|
|
93
|
+
return { width, height };
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
82
99
|
function splitWindowPane(cwd, command) {
|
|
83
100
|
const originalPane = getCurrentPaneId();
|
|
84
|
-
const
|
|
101
|
+
const paneSize = getCurrentPaneSize(originalPane);
|
|
102
|
+
const direction = chooseTmuxSplitDirection(paneSize?.width ?? 0, paneSize?.height ?? 0);
|
|
103
|
+
const paneId = tmuxCmd(buildTmuxSplitWindowArgs(cwd, command, direction, originalPane));
|
|
85
104
|
return { paneId, originalPane };
|
|
86
105
|
}
|
|
87
106
|
function killAgentPane(paneId, originalPane) {
|
package/dist/subagent/tmux.d.ts
CHANGED
|
@@ -5,6 +5,10 @@ export declare function tmuxCmd(args: string[]): string;
|
|
|
5
5
|
export declare function hasTmux(): boolean;
|
|
6
6
|
export declare function paneExists(paneId: string): boolean;
|
|
7
7
|
export declare function getCurrentPaneId(): string | null;
|
|
8
|
+
export declare function getCurrentPaneSize(targetPane?: string | null): {
|
|
9
|
+
width: number;
|
|
10
|
+
height: number;
|
|
11
|
+
} | null;
|
|
8
12
|
export declare function splitWindowPane(cwd: string, command: string): {
|
|
9
13
|
paneId: string;
|
|
10
14
|
originalPane: string | null;
|
package/dist/subagent/tmux.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Tmux helpers for subagent panes (shared by task extension).
|
|
3
3
|
*/
|
|
4
4
|
import { execFileSync } from "node:child_process";
|
|
5
|
+
import { buildTmuxSplitWindowArgs, chooseTmuxSplitDirection } from "../helpers.js";
|
|
5
6
|
export function tmuxCmd(args) {
|
|
6
7
|
return execFileSync("tmux", args, {
|
|
7
8
|
encoding: "utf-8",
|
|
@@ -34,18 +35,28 @@ export function getCurrentPaneId() {
|
|
|
34
35
|
return null;
|
|
35
36
|
}
|
|
36
37
|
}
|
|
38
|
+
export function getCurrentPaneSize(targetPane) {
|
|
39
|
+
try {
|
|
40
|
+
const args = ["display-message", "-p", "#{pane_width} #{pane_height}"];
|
|
41
|
+
if (targetPane)
|
|
42
|
+
args.splice(1, 0, "-t", targetPane);
|
|
43
|
+
const raw = tmuxCmd(args);
|
|
44
|
+
const [widthRaw, heightRaw] = raw.trim().split(/\s+/, 2);
|
|
45
|
+
const width = Number(widthRaw);
|
|
46
|
+
const height = Number(heightRaw);
|
|
47
|
+
if (!Number.isFinite(width) || !Number.isFinite(height))
|
|
48
|
+
return null;
|
|
49
|
+
return { width, height };
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
37
55
|
export function splitWindowPane(cwd, command) {
|
|
38
56
|
const originalPane = getCurrentPaneId();
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
"-P",
|
|
43
|
-
"-F",
|
|
44
|
-
"#{pane_id}",
|
|
45
|
-
"-c",
|
|
46
|
-
cwd,
|
|
47
|
-
command,
|
|
48
|
-
]);
|
|
57
|
+
const paneSize = getCurrentPaneSize(originalPane);
|
|
58
|
+
const direction = chooseTmuxSplitDirection(paneSize?.width ?? 0, paneSize?.height ?? 0);
|
|
59
|
+
const paneId = tmuxCmd(buildTmuxSplitWindowArgs(cwd, command, direction, originalPane));
|
|
49
60
|
return { paneId, originalPane };
|
|
50
61
|
}
|
|
51
62
|
export function killAgentPane(paneId, originalPane) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@heyhuynhgiabuu/pi-task",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Delegating task/subagent extension for Pi: foreground/background subagents, widgets, tmux observability, SDK fallback.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|