@oh-my-pi/pi-coding-agent 11.8.0 → 11.8.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 +25 -0
- package/package.json +7 -7
- package/src/cli/file-processor.ts +27 -2
- package/src/modes/utils/ui-helpers.ts +12 -5
- package/src/prompts/system/system-prompt.md +1 -0
- package/src/prompts/tools/task.md +25 -13
- package/src/session/messages.ts +4 -0
- package/src/system-prompt.ts +7 -0
- package/src/tools/truncate.ts +3 -1
- package/src/utils/file-mentions.ts +24 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [11.8.1] - 2026-02-10
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Added current date to system prompt context in YYYY-MM-DD format for date-aware agent reasoning
|
|
10
|
+
- Added file size display in UI when files are skipped due to size limits
|
|
11
|
+
- Added support for gigabyte (GB) file size formatting in truncate utility
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- Changed skipped file messages to include file size information for better visibility into why files were excluded
|
|
16
|
+
- Changed file processing to skip reading files exceeding 5MB (text) or 25MB (images) and include them as path-only references instead
|
|
17
|
+
- Changed @mention auto-reading to skip files exceeding 5MB (text) or 25MB (images) to prevent out-of-memory issues with large files
|
|
18
|
+
- Clarified that subagents automatically inherit full system prompt including AGENTS.md, context files, and skills — do not repeat project rules or conventions in task context
|
|
19
|
+
- Updated task context guidance to focus on session-specific information subagents lack, eliminating redundant documentation of project constraints already available to them
|
|
20
|
+
- Refined constraints template to emphasize task-specific rules and session decisions rather than global project conventions
|
|
21
|
+
- Expanded anti-patterns section to explicitly flag redundant context that wastes tokens by repeating AGENTS.md rules, project constraints, and tool preferences
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
- Fixed bash tool hanging when commands spawn background jobs by properly detecting foreground process completion
|
|
26
|
+
- Fixed bash tool occasionally hanging after command completion when background jobs keep stdout/stderr open
|
|
27
|
+
- Fixed crash when auto-reading @mentions for very large files by skipping content injection with an explicit "skipped" note
|
|
28
|
+
- Improved bash tool output draining after foreground completion to reduce tail output truncation
|
|
29
|
+
|
|
5
30
|
## [11.8.0] - 2026-02-10
|
|
6
31
|
### Added
|
|
7
32
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oh-my-pi/pi-coding-agent",
|
|
3
|
-
"version": "11.8.
|
|
3
|
+
"version": "11.8.2",
|
|
4
4
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"ompConfig": {
|
|
@@ -90,12 +90,12 @@
|
|
|
90
90
|
"@mozilla/readability": "0.6.0",
|
|
91
91
|
"@oclif/core": "^4.8.0",
|
|
92
92
|
"@oclif/plugin-autocomplete": "^3.2.40",
|
|
93
|
-
"@oh-my-pi/omp-stats": "11.8.
|
|
94
|
-
"@oh-my-pi/pi-agent-core": "11.8.
|
|
95
|
-
"@oh-my-pi/pi-ai": "11.8.
|
|
96
|
-
"@oh-my-pi/pi-natives": "11.8.
|
|
97
|
-
"@oh-my-pi/pi-tui": "11.8.
|
|
98
|
-
"@oh-my-pi/pi-utils": "11.8.
|
|
93
|
+
"@oh-my-pi/omp-stats": "11.8.2",
|
|
94
|
+
"@oh-my-pi/pi-agent-core": "11.8.2",
|
|
95
|
+
"@oh-my-pi/pi-ai": "11.8.2",
|
|
96
|
+
"@oh-my-pi/pi-natives": "11.8.2",
|
|
97
|
+
"@oh-my-pi/pi-tui": "11.8.2",
|
|
98
|
+
"@oh-my-pi/pi-utils": "11.8.2",
|
|
99
99
|
"@sinclair/typebox": "^0.34.48",
|
|
100
100
|
"ajv": "^8.17.1",
|
|
101
101
|
"chalk": "^5.6.2",
|
|
@@ -7,9 +7,15 @@ import type { ImageContent } from "@oh-my-pi/pi-ai";
|
|
|
7
7
|
import { isEnoent } from "@oh-my-pi/pi-utils";
|
|
8
8
|
import chalk from "chalk";
|
|
9
9
|
import { resolveReadPath } from "../tools/path-utils";
|
|
10
|
+
import { formatSize } from "../tools/truncate";
|
|
10
11
|
import { formatDimensionNote, resizeImage } from "../utils/image-resize";
|
|
11
12
|
import { detectSupportedImageMimeTypeFromFile } from "../utils/mime";
|
|
12
13
|
|
|
14
|
+
// Keep CLI startup responsive and avoid OOM when users pass huge files.
|
|
15
|
+
// If a file exceeds these limits, we include it as a path-only <file/> block.
|
|
16
|
+
const MAX_CLI_TEXT_BYTES = 5 * 1024 * 1024; // 5MB
|
|
17
|
+
const MAX_CLI_IMAGE_BYTES = 25 * 1024 * 1024; // 25MB
|
|
18
|
+
|
|
13
19
|
export interface ProcessedFiles {
|
|
14
20
|
text: string;
|
|
15
21
|
images: ImageContent[];
|
|
@@ -30,6 +36,27 @@ export async function processFileArguments(fileArgs: string[], options?: Process
|
|
|
30
36
|
// Expand and resolve path (handles ~ expansion and macOS screenshot Unicode spaces)
|
|
31
37
|
const absolutePath = path.resolve(resolveReadPath(fileArg, process.cwd()));
|
|
32
38
|
|
|
39
|
+
let stat: Awaited<ReturnType<typeof fs.stat>>;
|
|
40
|
+
try {
|
|
41
|
+
stat = await fs.stat(absolutePath);
|
|
42
|
+
} catch (err) {
|
|
43
|
+
if (isEnoent(err)) {
|
|
44
|
+
console.error(chalk.red(`Error: File not found: ${absolutePath}`));
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
throw err;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const mimeType = await detectSupportedImageMimeTypeFromFile(absolutePath);
|
|
51
|
+
const maxBytes = mimeType ? MAX_CLI_IMAGE_BYTES : MAX_CLI_TEXT_BYTES;
|
|
52
|
+
if (stat.size > maxBytes) {
|
|
53
|
+
console.error(
|
|
54
|
+
chalk.yellow(`Warning: Skipping file contents (too large: ${formatSize(stat.size)}): ${absolutePath}`),
|
|
55
|
+
);
|
|
56
|
+
text += `<file name="${absolutePath}">(skipped: too large, ${formatSize(stat.size)})</file>\n`;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
|
|
33
60
|
// Read file, handling not-found gracefully
|
|
34
61
|
let buffer: Buffer;
|
|
35
62
|
try {
|
|
@@ -45,8 +72,6 @@ export async function processFileArguments(fileArgs: string[], options?: Process
|
|
|
45
72
|
continue;
|
|
46
73
|
}
|
|
47
74
|
|
|
48
|
-
const mimeType = await detectSupportedImageMimeTypeFromFile(absolutePath);
|
|
49
|
-
|
|
50
75
|
if (mimeType) {
|
|
51
76
|
// Handle image file
|
|
52
77
|
const base64Content = buffer.toBase64();
|
|
@@ -17,6 +17,7 @@ import { theme } from "../../modes/theme/theme";
|
|
|
17
17
|
import type { CompactionQueuedMessage, InteractiveModeContext } from "../../modes/types";
|
|
18
18
|
import { type CustomMessage, SKILL_PROMPT_MESSAGE_TYPE, type SkillPromptDetails } from "../../session/messages";
|
|
19
19
|
import type { SessionContext } from "../../session/session-manager";
|
|
20
|
+
import { formatSize } from "../../tools/truncate";
|
|
20
21
|
|
|
21
22
|
type TextBlock = { type: "text"; text: string };
|
|
22
23
|
|
|
@@ -127,11 +128,17 @@ export class UiHelpers {
|
|
|
127
128
|
case "fileMention": {
|
|
128
129
|
// Render compact file mention display
|
|
129
130
|
for (const file of message.files) {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
131
|
+
let suffix: string;
|
|
132
|
+
if (file.skippedReason === "tooLarge") {
|
|
133
|
+
const size = typeof file.byteSize === "number" ? formatSize(file.byteSize) : "unknown size";
|
|
134
|
+
suffix = `(skipped: ${size})`;
|
|
135
|
+
} else {
|
|
136
|
+
suffix = file.image
|
|
137
|
+
? "(image)"
|
|
138
|
+
: file.lineCount === undefined
|
|
139
|
+
? "(unknown lines)"
|
|
140
|
+
: `(${file.lineCount} lines)`;
|
|
141
|
+
}
|
|
135
142
|
const text = `${theme.fg("dim", `${theme.tree.last} `)}${theme.fg("muted", "Read")} ${theme.fg(
|
|
136
143
|
"accent",
|
|
137
144
|
file.path,
|
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
# Task
|
|
2
2
|
|
|
3
|
-
Launch subagents to execute parallel, well-scoped tasks
|
|
3
|
+
Launch subagents to execute parallel, well-scoped tasks.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## What subagents inherit automatically
|
|
6
|
+
Subagents receive the **full system prompt**, including AGENTS.md, context files, and skills. Do NOT repeat project rules, coding conventions, or style guidelines in `context` — they already have them.
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
## What subagents do NOT have
|
|
9
|
+
Subagents have no access to your conversation history. They don't know:
|
|
8
10
|
- Decisions you made but didn't write down
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
+
- Which approach you chose among alternatives
|
|
12
|
+
- What you learned from reading files during this session
|
|
13
|
+
- Requirements the user stated only in conversation
|
|
14
|
+
|
|
15
|
+
Subagents CAN grep the parent conversation file for supplementary details.
|
|
11
16
|
---
|
|
12
17
|
|
|
13
18
|
## Parameters
|
|
@@ -18,9 +23,13 @@ Agent type for all tasks in this batch.
|
|
|
18
23
|
|
|
19
24
|
### `context` (optional — strongly recommended)
|
|
20
25
|
|
|
21
|
-
Shared background prepended verbatim to every task `assignment`.
|
|
26
|
+
Shared background prepended verbatim to every task `assignment`. Use only for session-specific information subagents lack.
|
|
27
|
+
|
|
28
|
+
<critical>
|
|
29
|
+
Do NOT include project rules, coding conventions, or style guidelines — subagents already have AGENTS.md and context files in their system prompt. Repeating them wastes tokens.
|
|
30
|
+
</critical>
|
|
22
31
|
|
|
23
|
-
Use template; omit non-applicable sections
|
|
32
|
+
Use template; omit non-applicable sections:
|
|
24
33
|
|
|
25
34
|
````
|
|
26
35
|
## Goal
|
|
@@ -30,9 +39,8 @@ One sentence: batch accomplishes together.
|
|
|
30
39
|
Explicitly exclude tempting scope — what tasks must not touch/attempt.
|
|
31
40
|
|
|
32
41
|
## Constraints
|
|
33
|
-
- MUST / MUST NOT rules
|
|
34
|
-
-
|
|
35
|
-
- What exists vs what to create
|
|
42
|
+
- Task-specific MUST / MUST NOT rules not already in AGENTS.md
|
|
43
|
+
- Decisions made during this session that affect implementation
|
|
36
44
|
|
|
37
45
|
## Reference Files
|
|
38
46
|
- `path/to/file.ext` — pattern demo
|
|
@@ -47,9 +55,9 @@ Explicitly exclude tempting scope — what tasks must not touch/attempt.
|
|
|
47
55
|
- Definition of "done" for batch
|
|
48
56
|
- Note: build/test/lint verification happens AFTER all tasks complete — not inside tasks (see below)
|
|
49
57
|
````
|
|
50
|
-
**Belongs in `context`**:
|
|
58
|
+
**Belongs in `context`**: task-specific goal, non-goals, session decisions, reference paths, shared type definitions, API contracts, global acceptance commands — anything 2+ tasks need that isn't already in AGENTS.md.
|
|
51
59
|
**Rule of thumb:** if repeat in 2+ tasks, belongs in `context`.
|
|
52
|
-
**Does NOT belong in `context`**: per-task file lists, one-off requirements (go in `assignment`), structured output format (goes in `schema`).
|
|
60
|
+
**Does NOT belong in `context`**: project rules already in AGENTS.md/context files, per-task file lists, one-off requirements (go in `assignment`), structured output format (goes in `schema`).
|
|
53
61
|
|
|
54
62
|
### `tasks` (required)
|
|
55
63
|
|
|
@@ -117,6 +125,10 @@ Use structure every assignment:
|
|
|
117
125
|
- "Use existing patterns."
|
|
118
126
|
- "Follow conventions."
|
|
119
127
|
- "No WASM."
|
|
128
|
+
**Redundant context** — wastes tokens repeating what subagents already have:
|
|
129
|
+
- Restating AGENTS.md rules (coding style, import conventions, logger usage)
|
|
130
|
+
- Repeating project constraints from context files
|
|
131
|
+
- Listing tool/framework preferences already documented in the repo
|
|
120
132
|
|
|
121
133
|
If tempted to write above, expand using templates.
|
|
122
134
|
**Output format in prose instead of `schema`** — agent returns null:
|
|
@@ -252,7 +264,7 @@ Layered work with dependencies:
|
|
|
252
264
|
## Pre-flight checklist
|
|
253
265
|
|
|
254
266
|
Before calling tool, verify:
|
|
255
|
-
- [ ] `context` includes
|
|
267
|
+
- [ ] `context` includes only session-specific info not already in AGENTS.md/context files
|
|
256
268
|
- [ ] Each `assignment` follows assignment template — not one-liner
|
|
257
269
|
- [ ] Each `assignment` includes edge cases / "don’t break" items
|
|
258
270
|
- [ ] Tasks truly parallel (no hidden dependencies)
|
package/src/session/messages.ts
CHANGED
|
@@ -114,6 +114,10 @@ export interface FileMentionMessage {
|
|
|
114
114
|
path: string;
|
|
115
115
|
content: string;
|
|
116
116
|
lineCount?: number;
|
|
117
|
+
/** File size in bytes, if known. */
|
|
118
|
+
byteSize?: number;
|
|
119
|
+
/** Why the file contents were omitted from auto-read. */
|
|
120
|
+
skippedReason?: "tooLarge";
|
|
117
121
|
image?: ImageContent;
|
|
118
122
|
}>;
|
|
119
123
|
timestamp: number;
|
package/src/system-prompt.ts
CHANGED
|
@@ -473,6 +473,11 @@ export async function buildSystemPrompt(options: BuildSystemPromptOptions = {}):
|
|
|
473
473
|
const systemPromptCustomization = await loadSystemPromptFiles({ cwd: resolvedCwd });
|
|
474
474
|
|
|
475
475
|
const now = new Date();
|
|
476
|
+
const date = now.toLocaleDateString("en-CA", {
|
|
477
|
+
year: "numeric",
|
|
478
|
+
month: "2-digit",
|
|
479
|
+
day: "2-digit",
|
|
480
|
+
});
|
|
476
481
|
const dateTime = now.toLocaleString("en-US", {
|
|
477
482
|
weekday: "long",
|
|
478
483
|
year: "numeric",
|
|
@@ -529,6 +534,7 @@ export async function buildSystemPrompt(options: BuildSystemPromptOptions = {}):
|
|
|
529
534
|
skills: filteredSkills,
|
|
530
535
|
preloadedSkills: preloadedSkillContents,
|
|
531
536
|
rules: rules ?? [],
|
|
537
|
+
date,
|
|
532
538
|
dateTime,
|
|
533
539
|
cwd: resolvedCwd,
|
|
534
540
|
});
|
|
@@ -544,6 +550,7 @@ export async function buildSystemPrompt(options: BuildSystemPromptOptions = {}):
|
|
|
544
550
|
skills: filteredSkills,
|
|
545
551
|
preloadedSkills: preloadedSkillContents,
|
|
546
552
|
rules: rules ?? [],
|
|
553
|
+
date,
|
|
547
554
|
dateTime,
|
|
548
555
|
cwd: resolvedCwd,
|
|
549
556
|
appendSystemPrompt: resolvedAppendPrompt ?? "",
|
package/src/tools/truncate.ts
CHANGED
|
@@ -53,8 +53,10 @@ export function formatSize(bytes: number): string {
|
|
|
53
53
|
return `${bytes}B`;
|
|
54
54
|
} else if (bytes < 1024 * 1024) {
|
|
55
55
|
return `${(bytes / 1024).toFixed(1)}KB`;
|
|
56
|
-
} else {
|
|
56
|
+
} else if (bytes < 1024 * 1024 * 1024) {
|
|
57
57
|
return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
|
|
58
|
+
} else {
|
|
59
|
+
return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)}GB`;
|
|
58
60
|
}
|
|
59
61
|
}
|
|
60
62
|
|
|
@@ -22,6 +22,11 @@ const TRAILING_PUNCTUATION_REGEX = /[)\]}>.,;:!?"'`]+$/;
|
|
|
22
22
|
const MENTION_BOUNDARY_REGEX = /[\s([{<"'`]/;
|
|
23
23
|
const DEFAULT_DIR_LIMIT = 500;
|
|
24
24
|
|
|
25
|
+
// Avoid OOM when users @mention very large files. Above these limits we skip
|
|
26
|
+
// auto-reading and only include the path in the message.
|
|
27
|
+
const MAX_AUTO_READ_TEXT_BYTES = 5 * 1024 * 1024; // 5MB
|
|
28
|
+
const MAX_AUTO_READ_IMAGE_BYTES = 25 * 1024 * 1024; // 25MB
|
|
29
|
+
|
|
25
30
|
function isMentionBoundary(text: string, index: number): boolean {
|
|
26
31
|
if (index === 0) return true;
|
|
27
32
|
return MENTION_BOUNDARY_REGEX.test(text[index - 1]);
|
|
@@ -183,6 +188,15 @@ export async function generateFileMentionMessages(
|
|
|
183
188
|
|
|
184
189
|
const mimeType = await detectSupportedImageMimeTypeFromFile(absolutePath);
|
|
185
190
|
if (mimeType) {
|
|
191
|
+
if (stat.size > MAX_AUTO_READ_IMAGE_BYTES) {
|
|
192
|
+
files.push({
|
|
193
|
+
path: filePath,
|
|
194
|
+
content: `(skipped auto-read: too large, ${formatSize(stat.size)})`,
|
|
195
|
+
byteSize: stat.size,
|
|
196
|
+
skippedReason: "tooLarge",
|
|
197
|
+
});
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
186
200
|
const buffer = await fs.readFile(absolutePath);
|
|
187
201
|
if (buffer.length === 0) {
|
|
188
202
|
continue;
|
|
@@ -210,6 +224,16 @@ export async function generateFileMentionMessages(
|
|
|
210
224
|
continue;
|
|
211
225
|
}
|
|
212
226
|
|
|
227
|
+
if (stat.size > MAX_AUTO_READ_TEXT_BYTES) {
|
|
228
|
+
files.push({
|
|
229
|
+
path: filePath,
|
|
230
|
+
content: `(skipped auto-read: too large, ${formatSize(stat.size)})`,
|
|
231
|
+
byteSize: stat.size,
|
|
232
|
+
skippedReason: "tooLarge",
|
|
233
|
+
});
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
|
|
213
237
|
const content = await Bun.file(absolutePath).text();
|
|
214
238
|
const { output, lineCount } = buildTextOutput(content);
|
|
215
239
|
files.push({ path: filePath, content: output, lineCount });
|