@oh-my-pi/pi-coding-agent 11.10.4 → 11.12.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 CHANGED
@@ -2,6 +2,79 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [11.12.0] - 2026-02-11
6
+ ### Added
7
+
8
+ - Added `resolveFileDisplayMode` utility to centralize file display mode resolution across tools (read, grep, file mentions)
9
+ - Added automatic hashline formatting to @file mentions when hashline mode is active
10
+ - Added `replace` hashline edit operation for substr-style fuzzy text replacement without line references, with optional `all` flag for replace-all behavior
11
+ - Added `noopEdits` array to `applyHashlineEdits` return value to report edits that produced no changes, including edit index, location, and current content for diagnostics
12
+ - Added validation to detect and reject hashline edits using wrong-format fields (`old_text`/`new_text` from replace mode, `diff` from patch mode) with helpful error messages
13
+ - Added `additionalProperties: true` to all hashline edit schemas (`single`, `range`, `insertAfter`, and root) to tolerate extra fields from models
14
+ - Added whitespace normalization in line reference parsing to tolerate spaces around colons (e.g., `5 : ab` now parses as `5:ab`)
15
+ - Added `remaps` property to `HashlineMismatchError` providing quick-fix mapping of stale line references to corrected hashes
16
+ - Added warnings detection in `applyHashlineEdits` to alert users when edits affect significantly more lines than expected, indicating possible unintended reformatting
17
+ - Added diagnostic output showing target line content when an edit produces no changes, helping users identify hash mismatches or incorrect replacement content
18
+ - Added `{{hashline}}` Handlebars helper to compute accurate `LINE:HASH` references for prompt examples and documentation
19
+ - Added deduplication of identical hashline edits targeting the same line(s) in a single call
20
+ - Added `replacement` as accepted alias for `content` in `insertAfter` operations
21
+ - Added graceful degradation of `range` edits with missing `end` field to single-line edits
22
+ - Added `additionalProperties: true` to hashline edit schemas to tolerate extra fields from models
23
+
24
+ ### Changed
25
+
26
+ - Reverted hashline display format from `LINE:HASH content` (two spaces) back to `LINE:HASH|content` (pipe separator) for consistency with legacy format
27
+ - Changed hashline display format from `LINE:HASH| content` to `LINE:HASH content` (two spaces instead of pipe separator) for improved readability
28
+ - Removed `lines` and `hashes` parameters from `read` tool—file display mode (line numbers, hashlines) now determined automatically by settings and edit mode
29
+ - Simplified `read` tool prompt to reflect automatic display mode detection based on configuration
30
+ - Updated `grep` tool to respect file display mode settings, showing hashline-prefixed output when hashline mode is active
31
+ - Renamed hashline edit operation keys from `single`/`range`/`insertAfter` to `set_line`/`replace_lines`/`insert_after` for clearer semantics
32
+ - Renamed hashline edit fields: `loc` → `anchor`, `replacement` → `new_text`, `content` → `text` for consistency across all operation types
33
+ - Separated hashline anchor-based edits (`set_line`, `replace_lines`, `insert_after`) from content-replace edits (`replace`) in application pipeline
34
+ - Improved no-op edit diagnostics to use `noopEdits` array from `applyHashlineEdits`, providing precise line-by-line comparison when replacements match current content
35
+ - Enhanced error messages for wrong-format hashline edits to guide users toward correct operation syntax
36
+ - Strengthened hashline prompt guidance to emphasize that `replacement` must differ from current line content and clarify no-op error recovery procedures
37
+ - Improved hashline prompt to clarify atomicity: all edits in one call are validated against the original file state, with line numbers and hashes referring to the pre-edit state
38
+ - Added explicit instruction in hashline prompt to preserve exact whitespace and formatting when replacing lines, changing only the targeted token/expression
39
+ - Added guidance in hashline prompt for swap operations: use two `single` operations in one call rather than attempting to account for line number shifts
40
+ - Strengthened anti-reformatting instructions in hashline prompt to reduce formatting-only failures
41
+ - Improved no-op error recovery guidance in hashline prompt to prevent infinite retry loops
42
+ - Renamed hashline edit operation keys from `replaceLine`/`replaceLines` to `single`/`range` for clearer semantics
43
+ - Renamed hashline edit field `content` to `replacement` in `single` and `range` operations to distinguish from `insertAfter.content`
44
+ - Improved no-op edit diagnostics to show specific line-by-line comparisons when replacements match current content, helping users identify hash mismatches or formatting issues
45
+ - Enhanced no-op error messages to distinguish between literally identical replacements and content normalized back by heuristics
46
+ - Reverted hash algorithm from 3-character base-36 back to 2-character hexadecimal for line references
47
+ - Enhanced range validation during hashline edits to detect and reject relocations that change the scope of affected lines
48
+ - Improved wrapped-line restoration logic to only attempt merging when source lines exhibit continuation patterns
49
+ - Updated hashline tool documentation to emphasize direction-locking mutations and clarify recovery procedures for hash mismatches
50
+ - Changed `applyHashlineEdits` return type to include optional `warnings` array for reporting suspicious edit patterns
51
+ - Improved hash relocation logic to recompute touched lines after hash-based line number adjustments, preventing incorrect merge heuristics
52
+ - Enhanced error messages for no-op edits to include preview of target lines with their current hashes and content
53
+ - Changed hashline edit format from `src`/`dst` object structure to direct operation schemas (`replaceLine`, `replaceLines`, `insertAfter`)
54
+ - Changed hash algorithm from 2-character hexadecimal to 3-character base-36 alphanumeric for improved readability and collision resistance
55
+ - Improved hash mismatch handling to automatically relocate stale line references when the hash uniquely identifies a moved line
56
+ - Changed `HashlineEdit` from `src`/`dst` format to direct operation schemas: `replaceLine`, `replaceLines`, `insertAfter`
57
+ - Changed hash algorithm from hexadecimal (base-16) to base-36 alphanumeric for shorter, more readable line references
58
+ - Increased maximum wrapped-line restoration from 6 to 10 lines to handle longer reflowed statements
59
+ - Updated prompt examples to use `{{hashline}}` Handlebars helper for generating correct line references in tool instructions
60
+
61
+ ### Removed
62
+
63
+ - Removed `insertBefore` hashline edit operation for inserting content before a line
64
+ - Removed `substr` hashline edit operation for substring-based line replacement
65
+ - Removed `insertBefore` and `substr` hashline edit variants
66
+
67
+ ### Fixed
68
+
69
+ - Fixed `parseLineRef` to handle both legacy pipe-separator format (`LINE:HASH| content`) and new two-space format (`LINE:HASH content`) for backward compatibility
70
+ - Fixed resource leak in browser query handler by properly disposing owned proxy elements for non-winning candidates
71
+ - Fixed script evaluation to support async functions and await expressions in browser evaluate operations
72
+ - Fixed `range` edits with missing `end` field to gracefully degrade to single-line edits instead of crashing
73
+ - Fixed `insertAfter` operations to accept both `content` and `replacement` field names for consistency with other edit types
74
+ - Fixed deduplication logic to correctly identify and remove identical hashline edits targeting the same line(s) in a single call
75
+ - Fixed range-based edits to prevent invalid mutations when hash relocation changes the number of lines in the target range
76
+ - Fixed multi-edit application to use original file state for all anchor references, preventing incorrect line numbers when earlier edits change file length
77
+
5
78
  ## [11.10.4] - 2026-02-10
6
79
 
7
80
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oh-my-pi/pi-coding-agent",
3
- "version": "11.10.4",
3
+ "version": "11.12.0",
4
4
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
5
5
  "type": "module",
6
6
  "ompConfig": {
@@ -84,12 +84,12 @@
84
84
  },
85
85
  "dependencies": {
86
86
  "@mozilla/readability": "0.6.0",
87
- "@oh-my-pi/omp-stats": "11.10.4",
88
- "@oh-my-pi/pi-agent-core": "11.10.4",
89
- "@oh-my-pi/pi-ai": "11.10.4",
90
- "@oh-my-pi/pi-natives": "11.10.4",
91
- "@oh-my-pi/pi-tui": "11.10.4",
92
- "@oh-my-pi/pi-utils": "11.10.4",
87
+ "@oh-my-pi/omp-stats": "11.12.0",
88
+ "@oh-my-pi/pi-agent-core": "11.12.0",
89
+ "@oh-my-pi/pi-ai": "11.12.0",
90
+ "@oh-my-pi/pi-natives": "11.12.0",
91
+ "@oh-my-pi/pi-tui": "11.12.0",
92
+ "@oh-my-pi/pi-utils": "11.12.0",
93
93
  "@sinclair/typebox": "^0.34.48",
94
94
  "ajv": "^8.17.1",
95
95
  "chalk": "^5.6.2",
@@ -107,7 +107,7 @@
107
107
  },
108
108
  "devDependencies": {
109
109
  "@types/ms": "^2.1.0",
110
- "@types/bun": "^1.3.8",
110
+ "@types/bun": "^1.3.9",
111
111
  "ms": "^2.1.3",
112
112
  "@types/jsdom": "27.0.0"
113
113
  },
@@ -29,6 +29,8 @@ export const defaultModelPerProvider: Record<KnownProvider, string> = {
29
29
  zai: "glm-4.6",
30
30
  mistral: "devstral-medium-latest",
31
31
  minimax: "MiniMax-M2.1",
32
+ "minimax-code": "MiniMax-M2.1",
33
+ "minimax-code-cn": "MiniMax-M2.1",
32
34
  opencode: "claude-opus-4-6",
33
35
  "kimi-code": "kimi-k2.5",
34
36
  };
@@ -3,6 +3,7 @@ import * as path from "node:path";
3
3
  import { logger } from "@oh-my-pi/pi-utils";
4
4
  import Handlebars from "handlebars";
5
5
  import { CONFIG_DIR_NAME, getPromptsDir } from "../config";
6
+ import { computeLineHash } from "../patch/hashline";
6
7
  import { jtdToTypeScript } from "../tools/jtd-to-typescript";
7
8
  import { parseFrontmatter } from "../utils/frontmatter";
8
9
 
@@ -228,6 +229,16 @@ handlebars.registerHelper("jtdToTypeScript", (schema: unknown): string => jtdToT
228
229
 
229
230
  handlebars.registerHelper("jsonStringify", (value: unknown): string => JSON.stringify(value));
230
231
 
232
+ /**
233
+ * {{hashline lineNum "content"}} — compute a real hashline ref for prompt examples.
234
+ * Returns `"lineNum:hash"` using the actual hash algorithm.
235
+ */
236
+ handlebars.registerHelper("hashline", (lineNum: unknown, content: unknown): string => {
237
+ const num = typeof lineNum === "number" ? lineNum : Number.parseInt(String(lineNum), 10);
238
+ const str = typeof content === "string" ? content : String(content ?? "");
239
+ return `${num}:${computeLineHash(num, str)}`;
240
+ });
241
+
231
242
  export function renderPromptTemplate(template: string, context: TemplateContext = {}): string {
232
243
  const compiled = handlebars.compile(template, { noEscape: true, strict: false });
233
244
  const rendered = compiled(context ?? {});
@@ -253,7 +253,7 @@ export const SETTINGS_SCHEMA = {
253
253
  ui: {
254
254
  tab: "config",
255
255
  label: "Read hash lines",
256
- description: "Include line hashes in read output for hashline edit mode (LINE:HASH| content)",
256
+ description: "Include line hashes in read output for hashline edit mode (LINE:HASH|content)",
257
257
  },
258
258
  },
259
259
  showHardwareCursor: {
@@ -22,6 +22,21 @@ export interface SystemInfo {
22
22
  terminal: string | undefined;
23
23
  }
24
24
 
25
+ /** Map Darwin kernel major version to macOS marketing name. */
26
+ function macosMarketingName(release: string): string | undefined {
27
+ const major = Number.parseInt(release.split(".")[0] ?? "", 10);
28
+ if (Number.isNaN(major)) return undefined;
29
+ const names: Record<number, string> = {
30
+ 25: "Tahoe",
31
+ 24: "Sequoia",
32
+ 23: "Sonoma",
33
+ 22: "Ventura",
34
+ 21: "Monterey",
35
+ 20: "Big Sur",
36
+ };
37
+ return names[major];
38
+ }
39
+
25
40
  /** Collect system information */
26
41
  export async function collectSystemInfo(): Promise<SystemInfo> {
27
42
  const cpus = os.cpus();
@@ -31,8 +46,14 @@ export async function collectSystemInfo(): Promise<SystemInfo> {
31
46
  const shell = Bun.env.SHELL ?? Bun.env.ComSpec ?? "unknown";
32
47
  const terminal = Bun.env.TERM_PROGRAM ?? Bun.env.TERM ?? undefined;
33
48
 
49
+ let osStr = `${os.type()} ${os.release()} (${os.platform()})`;
50
+ if (os.platform() === "darwin") {
51
+ const name = macosMarketingName(os.release());
52
+ if (name) osStr = `${osStr} ${name}`;
53
+ }
54
+
34
55
  return {
35
- os: `${os.type()} ${os.release()} (${os.platform()})`,
56
+ os: osStr,
36
57
  arch: os.arch(),
37
58
  cpu: cpuModel,
38
59
  memory: {
@@ -53,10 +53,15 @@ export interface MCPToolDetails {
53
53
  /**
54
54
  * Convert JSON Schema from MCP to TypeBox-compatible schema.
55
55
  * MCP uses standard JSON Schema, TypeBox uses a compatible subset.
56
+ *
57
+ * Also normalizes schemas to work around common issues:
58
+ * - Adds `properties: {}` to object schemas missing it (some LLM providers require this)
56
59
  */
57
60
  function convertSchema(mcpSchema: MCPToolDefinition["inputSchema"]): TSchema {
58
- // MCP schemas are JSON Schema objects, TypeBox can use them directly
59
- // as long as we ensure the structure is correct
61
+ // Normalize: object schemas must have properties field for some providers
62
+ if (mcpSchema.type === "object" && !("properties" in mcpSchema)) {
63
+ return { ...mcpSchema, properties: {} } as unknown as TSchema;
64
+ }
60
65
  return mcpSchema as unknown as TSchema;
61
66
  }
62
67
 
package/src/patch/diff.ts CHANGED
@@ -9,8 +9,9 @@ import { resolveToCwd } from "../tools/path-utils";
9
9
  import { previewPatch } from "./applicator";
10
10
  import { DEFAULT_FUZZY_THRESHOLD, findMatch } from "./fuzzy";
11
11
  import { applyHashlineEdits } from "./hashline";
12
+ import type { HashlineEdit } from "./index";
12
13
  import { adjustIndentation, normalizeToLF, stripBom } from "./normalize";
13
- import type { DiffError, DiffResult, HashlineEdit, PatchInput } from "./types";
14
+ import type { DiffError, DiffResult, PatchInput } from "./types";
14
15
  import { EditMatchError } from "./types";
15
16
 
16
17
  // ═══════════════════════════════════════════════════════════════════════════