@oh-my-pi/pi-coding-agent 17.1.2 → 17.1.3

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.
@@ -1,11 +1,13 @@
1
+ import { type Settings } from "../config/settings.js";
1
2
  /**
2
3
  * Check if a file is auto-generated by examining its content.
3
4
  * Throws ToolError if the file appears to be auto-generated.
4
5
  *
5
6
  * @param absolutePath - Absolute path to the file
6
7
  * @param displayPath - Path to show in error messages (relative or as provided)
8
+ * @param activeSettings - Session settings; falls back to global settings or the schema default
7
9
  */
8
- export declare function assertEditableFile(absolutePath: string, displayPath?: string): Promise<void>;
10
+ export declare function assertEditableFile(absolutePath: string, displayPath?: string, activeSettings?: Settings): Promise<void>;
9
11
  /**
10
12
  * Check if file content is auto-generated.
11
13
  * Uses only the first CHECK_BYTE_COUNT characters of the content.
@@ -13,5 +15,6 @@ export declare function assertEditableFile(absolutePath: string, displayPath?: s
13
15
  *
14
16
  * @param content - File content to check (can be full content or prefix)
15
17
  * @param displayPath - Path to show in error messages
18
+ * @param activeSettings - Session settings; falls back to global settings or the schema default
16
19
  */
17
- export declare function assertEditableFileContent(content: string, displayPath: string): void;
20
+ export declare function assertEditableFileContent(content: string, displayPath: string, activeSettings?: Settings): void;
@@ -13,10 +13,7 @@ import type { Component } from "@oh-my-pi/pi-tui";
13
13
  import type { RenderResultOptions } from "../extensibility/custom-tools/types.js";
14
14
  import type { Theme } from "../modes/theme/theme.js";
15
15
  interface RetainRenderArgs {
16
- items?: Array<{
17
- content?: string;
18
- context?: string;
19
- }>;
16
+ items?: unknown;
20
17
  }
21
18
  interface QueryRenderArgs {
22
19
  query?: string;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@oh-my-pi/pi-coding-agent",
4
- "version": "17.1.2",
4
+ "version": "17.1.3",
5
5
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
6
6
  "homepage": "https://omp.sh",
7
7
  "author": "Can Boluk",
@@ -53,17 +53,17 @@
53
53
  "@babel/parser": "^7.29.7",
54
54
  "@babel/traverse": "^7.29.7",
55
55
  "@mozilla/readability": "^0.6.0",
56
- "@oh-my-pi/hashline": "17.1.2",
57
- "@oh-my-pi/omp-stats": "17.1.2",
58
- "@oh-my-pi/pi-agent-core": "17.1.2",
59
- "@oh-my-pi/pi-ai": "17.1.2",
60
- "@oh-my-pi/pi-catalog": "17.1.2",
61
- "@oh-my-pi/pi-mnemopi": "17.1.2",
62
- "@oh-my-pi/pi-natives": "17.1.2",
63
- "@oh-my-pi/pi-tui": "17.1.2",
64
- "@oh-my-pi/pi-utils": "17.1.2",
65
- "@oh-my-pi/pi-wire": "17.1.2",
66
- "@oh-my-pi/snapcompact": "17.1.2",
56
+ "@oh-my-pi/hashline": "17.1.3",
57
+ "@oh-my-pi/omp-stats": "17.1.3",
58
+ "@oh-my-pi/pi-agent-core": "17.1.3",
59
+ "@oh-my-pi/pi-ai": "17.1.3",
60
+ "@oh-my-pi/pi-catalog": "17.1.3",
61
+ "@oh-my-pi/pi-mnemopi": "17.1.3",
62
+ "@oh-my-pi/pi-natives": "17.1.3",
63
+ "@oh-my-pi/pi-tui": "17.1.3",
64
+ "@oh-my-pi/pi-utils": "17.1.3",
65
+ "@oh-my-pi/pi-wire": "17.1.3",
66
+ "@oh-my-pi/snapcompact": "17.1.3",
67
67
  "@opentelemetry/api": "^1.9.1",
68
68
  "@opentelemetry/api-logs": "^0.220.0",
69
69
  "@opentelemetry/context-async-hooks": "^2.9.0",
@@ -121,7 +121,7 @@ export class HashlineFilesystem extends Filesystem {
121
121
  throw error;
122
122
  }
123
123
  // Refuse edits against generated files (lockfiles, models.json, …).
124
- assertEditableFileContent(content, relativePath);
124
+ assertEditableFileContent(content, relativePath, this.session.settings);
125
125
  return content;
126
126
  }
127
127
 
@@ -1816,7 +1816,7 @@ export async function executePatchSingle(
1816
1816
  const resolvedPath = resolvePlanPath(session, path);
1817
1817
  const resolvedRename = rename ? resolvePlanPath(session, rename) : undefined;
1818
1818
 
1819
- await assertEditableFile(resolvedPath, path);
1819
+ await assertEditableFile(resolvedPath, path, session.settings);
1820
1820
 
1821
1821
  // Capture pre-edit content so we can verify the write actually hit disk.
1822
1822
  // `LspFileSystem.writeFile` delegates to a writethrough callback that, in
@@ -1,4 +1,4 @@
1
- Structural AST-aware rewrites via ast-grep. Use for codemods where text replace is unsafe. Narrow each call to one language.
1
+ Structural AST-aware rewrites via ast-grep. Use for codemods where text replace is unsafe. Mixed-language paths are fine: each file is parsed in its own language, and a pattern only rewrites files it parses in.
2
2
 
3
3
  - Metavariables in `pat` (`$A`, `$$$ARGS`) substitute into `out`.
4
4
  - **Patterns match AST structure, not text.** `$NAME` = one node; `$_` = unbound; `$$$NAME` = zero-or-more.
@@ -185,7 +185,7 @@ export class StreamingEditGuard {
185
185
  #abortForAutoGeneratedPath(toolCall: ToolCall, filePath: string, resolvedPath: string): void {
186
186
  if (this.#lastToolCallId === toolCall.id) return;
187
187
  this.#lastToolCallId = toolCall.id;
188
- void assertEditableFile(resolvedPath, filePath).catch(error => {
188
+ void assertEditableFile(resolvedPath, filePath, this.#host.settings).catch(error => {
189
189
  if (!(error instanceof ToolError) || this.#lastToolCallId !== toolCall.id) return;
190
190
  if (!this.#abortTriggered) {
191
191
  this.#abortTriggered = true;
@@ -7,7 +7,8 @@
7
7
  import * as path from "node:path";
8
8
  import { isEnoent, peekFile } from "@oh-my-pi/pi-utils";
9
9
  import { LRUCache } from "lru-cache/raw";
10
- import { settings } from "../config/settings";
10
+ import { settings as globalSettings, isSettingsInitialized, type Settings } from "../config/settings";
11
+ import { getDefault } from "../config/settings-schema";
11
12
  import { ToolError } from "./tool-errors";
12
13
 
13
14
  /**
@@ -283,15 +284,26 @@ async function getAutoGeneratedMarker(filePath: string): Promise<string | undefi
283
284
  return marker;
284
285
  }
285
286
 
287
+ function shouldBlockAutoGeneratedFiles(activeSettings?: Settings): boolean {
288
+ if (activeSettings) return activeSettings.get("edit.blockAutoGenerated");
289
+ if (isSettingsInitialized()) return globalSettings.get("edit.blockAutoGenerated");
290
+ return getDefault("edit.blockAutoGenerated");
291
+ }
292
+
286
293
  /**
287
294
  * Check if a file is auto-generated by examining its content.
288
295
  * Throws ToolError if the file appears to be auto-generated.
289
296
  *
290
297
  * @param absolutePath - Absolute path to the file
291
298
  * @param displayPath - Path to show in error messages (relative or as provided)
299
+ * @param activeSettings - Session settings; falls back to global settings or the schema default
292
300
  */
293
- export async function assertEditableFile(absolutePath: string, displayPath?: string) {
294
- if (!settings.get("edit.blockAutoGenerated")) {
301
+ export async function assertEditableFile(
302
+ absolutePath: string,
303
+ displayPath?: string,
304
+ activeSettings?: Settings,
305
+ ): Promise<void> {
306
+ if (!shouldBlockAutoGeneratedFiles(activeSettings)) {
295
307
  return;
296
308
  }
297
309
  const pathForDisplay = displayPath ?? absolutePath;
@@ -308,9 +320,10 @@ export async function assertEditableFile(absolutePath: string, displayPath?: str
308
320
  *
309
321
  * @param content - File content to check (can be full content or prefix)
310
322
  * @param displayPath - Path to show in error messages
323
+ * @param activeSettings - Session settings; falls back to global settings or the schema default
311
324
  */
312
- export function assertEditableFileContent(content: string, displayPath: string): void {
313
- if (!settings.get("edit.blockAutoGenerated")) {
325
+ export function assertEditableFileContent(content: string, displayPath: string, activeSettings?: Settings): void {
326
+ if (!shouldBlockAutoGeneratedFiles(activeSettings)) {
314
327
  return;
315
328
  }
316
329
 
@@ -27,7 +27,7 @@ import {
27
27
  // from the active theme (`•` by default, a nerd-font dot under nerd themes).
28
28
 
29
29
  interface RetainRenderArgs {
30
- items?: Array<{ content?: string; context?: string }>;
30
+ items?: unknown;
31
31
  }
32
32
 
33
33
  interface QueryRenderArgs {
@@ -35,7 +35,16 @@ interface QueryRenderArgs {
35
35
  }
36
36
 
37
37
  function retainContents(args: RetainRenderArgs | undefined): string[] {
38
- return (args?.items ?? []).map(item => replaceTabs((item?.content ?? "").trim())).filter(line => line.length > 0);
38
+ const items = args?.items;
39
+ if (!Array.isArray(items)) return [];
40
+
41
+ const contents: string[] = [];
42
+ for (const item of items) {
43
+ if (!item || typeof item !== "object" || !("content" in item) || typeof item.content !== "string") continue;
44
+ const content = replaceTabs(item.content.trim());
45
+ if (content.length > 0) contents.push(content);
46
+ }
47
+ return contents;
39
48
  }
40
49
 
41
50
  function resultText(result: { content?: Array<{ type: string; text?: string }> }): string {
@@ -13,7 +13,8 @@ import type { Component } from "@oh-my-pi/pi-tui";
13
13
  import { getKeybindings, replaceTabs, truncateToWidth } from "@oh-my-pi/pi-tui";
14
14
  import { pluralize } from "@oh-my-pi/pi-utils";
15
15
  import { formatKeyHints, type KeyId } from "../config/keybindings";
16
- import { settings } from "../config/settings";
16
+ import { isSettingsInitialized, settings } from "../config/settings";
17
+ import { getDefault } from "../config/settings-schema";
17
18
  import type { Theme } from "../modes/theme/theme";
18
19
  import { Hasher } from "../tui/utils";
19
20
  import { formatDimensionNote, type ResizedImage } from "../utils/image-resize";
@@ -27,8 +28,12 @@ export { replaceTabs, truncateToWidth, wrapTextWithAnsi } from "@oh-my-pi/pi-tui
27
28
 
28
29
  /** Resolve inline image dimension caps from settings and viewport. */
29
30
  export function resolveImageOptions(): { maxWidthCells: number; maxHeightCells?: number } {
30
- const maxWidthCells = settings.get("tui.maxInlineImageColumns");
31
- const rowSetting = Math.max(0, settings.get("tui.maxInlineImageRows"));
31
+ const activeSettings = isSettingsInitialized() ? settings : undefined;
32
+ const maxWidthCells = activeSettings?.get("tui.maxInlineImageColumns") ?? getDefault("tui.maxInlineImageColumns");
33
+ const rowSetting = Math.max(
34
+ 0,
35
+ activeSettings?.get("tui.maxInlineImageRows") ?? getDefault("tui.maxInlineImageRows"),
36
+ );
32
37
  const viewportRows = process.stdout.rows;
33
38
  const viewportFraction = viewportRows ? Math.floor(viewportRows * 0.6) : 0;
34
39
  let maxHeightCells: number | undefined;
@@ -1215,7 +1215,7 @@ export class WriteTool implements AgentTool<typeof writeSchema, WriteToolDetails
1215
1215
 
1216
1216
  // Check if file exists and is auto-generated before overwriting
1217
1217
  if (await fs.exists(absolutePath)) {
1218
- await assertEditableFile(absolutePath, path);
1218
+ await assertEditableFile(absolutePath, path, this.session.settings);
1219
1219
  }
1220
1220
 
1221
1221
  const displayPath = formatPathRelativeToCwd(absolutePath, this.session.cwd);