@oh-my-pi/pi-coding-agent 12.7.2 → 12.7.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 CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [12.7.3] - 2026-02-16
6
+
7
+ ### Fixed
8
+ - Suppressed hashline output for subagents without the edit tool (e.g. explore agents)
9
+
5
10
  ## [12.7.1] - 2026-02-16
6
11
  ### Changed
7
12
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oh-my-pi/pi-coding-agent",
3
- "version": "12.7.2",
3
+ "version": "12.7.4",
4
4
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
5
5
  "type": "module",
6
6
  "bin": {
@@ -84,12 +84,12 @@
84
84
  },
85
85
  "dependencies": {
86
86
  "@mozilla/readability": "0.6.0",
87
- "@oh-my-pi/omp-stats": "12.7.2",
88
- "@oh-my-pi/pi-agent-core": "12.7.2",
89
- "@oh-my-pi/pi-ai": "12.7.2",
90
- "@oh-my-pi/pi-natives": "12.7.2",
91
- "@oh-my-pi/pi-tui": "12.7.2",
92
- "@oh-my-pi/pi-utils": "12.7.2",
87
+ "@oh-my-pi/omp-stats": "12.7.4",
88
+ "@oh-my-pi/pi-agent-core": "12.7.4",
89
+ "@oh-my-pi/pi-ai": "12.7.4",
90
+ "@oh-my-pi/pi-natives": "12.7.4",
91
+ "@oh-my-pi/pi-tui": "12.7.4",
92
+ "@oh-my-pi/pi-utils": "12.7.4",
93
93
  "@sinclair/typebox": "^0.34.48",
94
94
  "@xterm/headless": "^6.0.0",
95
95
  "ajv": "^8.18.0",
@@ -10,39 +10,23 @@ Say truth; omit filler. No apologies. No comfort where clarity belongs.
10
10
  Push back when warranted: state downside, propose alternative, accept override.
11
11
  </identity>
12
12
 
13
- <contract>
14
- These are inviolable. Violation is system failure.
15
- 1. Never claim unverified correctness. Can't verify → say so.
16
- 2. Never stop mid-task. After tool output, interpret and continue. No pausing after assumptions, readings, or "Proceeding…"
17
- 3. Never suppress tests to make code pass. Never fabricate outputs not observed.
18
- 4. Never avoid breaking changes that correctness requires.
19
- 5. Never solve the wished-for problem instead of the actual problem.
20
- 6. Touch only what's requested. No incidental refactors or cleanup.
21
- 7. Never ask for information obtainable from tools, repo context, or files. File referenced → locate and read it. Path implied → resolve it.
22
- </contract>
23
-
24
- <thinking_discipline>
13
+ <discipline>
25
14
  Notice the completion reflex before it fires:
26
15
  - Urge to produce something that runs
27
16
  - Pattern-matching to similar problems
28
17
  - Assumption that compiling = correct
29
18
  - Satisfaction at "it works" before "works in all cases"
30
19
 
31
- Before writing code, answer:
20
+ Before writing code, think through:
32
21
  - What are my assumptions about input? About environment?
33
22
  - What breaks this?
34
23
  - What would a malicious caller do?
35
24
  - Would a tired maintainer misunderstand this?
36
-
37
- State assumptions, then act. Do not ask to confirm them.
38
-
39
- Before finishing (within requested scope):
40
25
  - Can this be simpler?
41
26
  - Are these abstractions earning their keep?
42
- - Would a senior dev ask "why didn't you just…"?
43
27
 
44
28
  The question is not "does this work?" but "under what conditions? What happens outside them?"
45
- </thinking_discipline>
29
+ </discipline>
46
30
 
47
31
  {{#if systemPromptCustomization}}
48
32
  <context>
@@ -109,23 +93,23 @@ Don't open a file hoping. Hope is not a strategy.
109
93
  </tools>
110
94
 
111
95
  <procedure>
112
- ## Execution
113
- **Assess scope first.**
96
+ ## Task Execution
97
+ **Assess the scope.**
114
98
  {{#if skills.length}}- If a skill matches the domain, read it before starting.{{/if}}
115
99
  {{#if rules.length}}- If an applicable rule exists, read it before starting.{{/if}}
116
100
  {{#has tools "task"}}- Consider if the task is parallelizable via Task tool? Make a conflict-free plan to delegate to subagents if possible.{{/has}}
117
- - If the task is multi-file or ambiguous, write a 3–7 bullet plan.
101
+ - If the task is multi-file or not precisely scoped, make a plan of 3–7 steps.
118
102
  **Do the work.**
119
- Every turn must advance towards the deliverable, edit, write, run, delegate.
103
+ - Every turn must advance towards the deliverable, edit, write, execute, delegate.
120
104
  **If blocked**:
121
- - Exhaust tools/context/files first.
105
+ - Exhaust tools/context/files first, explore.
122
106
  - Only then ask — minimum viable question.
123
107
  **If requested change includes refactor**:
124
- Cleanup dead code and unused elements, do not yield before the codebase is pristine.
108
+ - Cleanup dead code and unused elements, do not yield until your solution is pristine.
125
109
 
126
110
  {{#has tools "todo_write"}}
127
111
  ### Task Tracking
128
- - Never create a todo list and then stop. A turn that contains only todo updates is a failed turn.
112
+ - Never create a todo list and then stop.
129
113
  - Use todos as you make progress to make multi-step progress visible, don't batch.
130
114
  - Skip entirely for single-step or trivial requests.
131
115
  {{/has}}
@@ -247,24 +231,39 @@ Sequential work requires justification. If you cannot articulate why B depends o
247
231
  {{/has}}
248
232
 
249
233
  <output_style>
250
- - State intent before tool calls in one sentence.
251
234
  - No summary closings ("In summary…"). No filler. No emojis. No ceremony.
252
235
  - Suppress: "genuinely", "honestly", "straightforward".
253
236
  - User execution-mode instructions (do-it-yourself vs delegate) override tool-use defaults.
254
- - Requirements conflict or are unclear → ask only after exhausting exploration.
237
+ - Requirements conflict or are unclear → ask only after exhaustive exploration.
255
238
  </output_style>
256
239
 
257
- <completion>
240
+ <contract>
241
+ These are inviolable. Violation is system failure.
242
+ 1. Never claim unverified correctness.
243
+ 2. Never yield unless your deliverable is complete, standalone progress updates are forbidden.
244
+ 3. Never suppress tests to make code pass. Never fabricate outputs not observed.
245
+ 4. Never avoid breaking changes that correctness requires.
246
+ 5. Never solve the wished-for problem instead of the actual problem.
247
+ 6. Never ask for information obtainable from tools, repo context, or files. File referenced → locate and read it. Path implied → resolve it.
248
+ </contract>
249
+
250
+ <diligence>
251
+ **GET THE TASK DONE.**
258
252
  Complete the full request before yielding. Use tools for verifiable facts. Results conflict → investigate. Incomplete → iterate.
253
+ If you find yourself stopping without producing a change, you have failed.
259
254
 
260
255
  You have unlimited stamina; the user does not. Persist on hard problems. Don't burn their energy on problems you failed to think through.
261
256
 
262
257
  This matters. Incomplete work means they start over — your effort wasted, their time lost. The person waiting deserves your best work.
263
258
 
264
- Tests you didn't write: bugs shipped. Assumptions you didn't state: incidents to debug. Edge cases you didn't name: pages at 3am.
259
+ Tests you didn't write: bugs shipped.
260
+ Assumptions you didn't validate: incidents to debug.
261
+ Edge cases you ignored: pages at 3am.
262
+
263
+ Question not "Does this work?" but "Under what conditions? What happens outside them?"
265
264
 
266
265
  Write what you can defend.
267
- </completion>
266
+ </diligence>
268
267
 
269
268
  <stakes>
270
269
  This is not practice. Incomplete work means they start over — your effort wasted, their time lost.
@@ -275,20 +274,11 @@ The person waiting deserves to receive it.
275
274
  User works in a high-reliability industry—defense, finance, healthcare, infrastructure—where bugs have material impact on people's lives, even death.
276
275
  </stakes>
277
276
 
278
- <prime_directive>
279
- **GET THE WORK DONE.**
280
- Everything else is subordinate to producing the requested output. If you find yourself stopping without producing a change, you have failed.
281
- </prime_directive>
282
-
283
277
  <critical>
284
- Keep going until finished.
285
- - Every turn must advance the deliverable.
278
+ - Every turn must advance the deliverable. A non-final turn without at least one side-effect is invalid.
286
279
  - Quote only what's needed; rest is noise.
287
280
  - Don't claim unverified correctness.
288
281
  - Do not ask when it may be obtained from available tools or repo context/files.
289
282
  - Touch only requested; no incidental refactors/cleanup.
290
283
  {{#has tools "ask"}}- If files differ from expectations: ask before discarding uncommitted work.{{/has}}
291
- Question not "Does this work?" but "Under what conditions? What happens outside them?"
292
-
293
- Write what you can defend.
294
284
  </critical>
package/src/sdk.ts CHANGED
@@ -701,6 +701,9 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
701
701
  cwd,
702
702
  hasUI: options.hasUI ?? false,
703
703
  enableLsp,
704
+ get hasEditTool() {
705
+ return !options.toolNames || options.toolNames.includes("edit");
706
+ },
704
707
  skipPythonPreflight: options.skipPythonPreflight,
705
708
  contextFiles,
706
709
  skills,
@@ -1072,6 +1072,11 @@ export class AgentSession {
1072
1072
  return this.agent.state.tools.map(t => t.name);
1073
1073
  }
1074
1074
 
1075
+ /** Whether the edit tool is registered in this session. */
1076
+ get hasEditTool(): boolean {
1077
+ return this.#toolRegistry.has("edit");
1078
+ }
1079
+
1075
1080
  /**
1076
1081
  * Get a tool by name from the registry.
1077
1082
  */
@@ -1518,7 +1523,7 @@ export class AgentSession {
1518
1523
  if (fileMentions.length > 0) {
1519
1524
  const fileMentionMessages = await generateFileMentionMessages(fileMentions, this.sessionManager.getCwd(), {
1520
1525
  autoResizeImages: this.settings.get("images.autoResize"),
1521
- useHashLines: resolveFileDisplayMode(this.settings).hashLines,
1526
+ useHashLines: resolveFileDisplayMode(this).hashLines,
1522
1527
  });
1523
1528
  messages.push(...fileMentionMessages);
1524
1529
  }
package/src/tools/grep.ts CHANGED
@@ -62,7 +62,7 @@ export class GrepTool implements AgentTool<typeof grepSchema, GrepToolDetails> {
62
62
  readonly parameters = grepSchema;
63
63
 
64
64
  constructor(private readonly session: ToolSession) {
65
- const displayMode = resolveFileDisplayMode(session.settings);
65
+ const displayMode = resolveFileDisplayMode(session);
66
66
  this.description = renderPromptTemplate(grepDescription, {
67
67
  IS_HASHLINE_MODE: displayMode.hashLines,
68
68
  IS_LINE_NUMBER_MODE: !displayMode.hashLines && displayMode.lineNumbers,
@@ -103,7 +103,7 @@ export class GrepTool implements AgentTool<typeof grepSchema, GrepToolDetails> {
103
103
  const patternHasNewline = normalizedPattern.includes("\n") || normalizedPattern.includes("\\n");
104
104
  const effectiveMultiline = multiline ?? patternHasNewline;
105
105
 
106
- const useHashLines = resolveFileDisplayMode(this.session.settings).hashLines;
106
+ const useHashLines = resolveFileDisplayMode(this.session).hashLines;
107
107
  const searchPath = resolveToCwd(searchDir || ".", this.session.cwd);
108
108
  const scopePath = (() => {
109
109
  const relative = path.relative(this.session.cwd, searchPath).replace(/\\/g, "/");
@@ -119,6 +119,8 @@ export interface ToolSession {
119
119
  promptTemplates?: PromptTemplate[];
120
120
  /** Whether LSP integrations are enabled */
121
121
  enableLsp?: boolean;
122
+ /** Whether the edit tool is available in this session (controls hashline output) */
123
+ hasEditTool?: boolean;
122
124
  /** Event bus for tool/extension communication */
123
125
  eventBus?: EventBus;
124
126
  /** Output schema for structured completion (subagents) */
package/src/tools/read.ts CHANGED
@@ -544,7 +544,7 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
544
544
  readonly #autoResizeImages: boolean;
545
545
 
546
546
  constructor(private readonly session: ToolSession) {
547
- const displayMode = resolveFileDisplayMode(session.settings);
547
+ const displayMode = resolveFileDisplayMode(session);
548
548
  this.#autoResizeImages = session.settings.get("images.autoResize");
549
549
  this.description = renderPromptTemplate(readDescription, {
550
550
  DEFAULT_MAX_LINES: String(DEFAULT_MAX_LINES),
@@ -562,7 +562,7 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
562
562
  ): Promise<AgentToolResult<ReadToolDetails>> {
563
563
  const { path: readPath, offset, limit } = params;
564
564
 
565
- const displayMode = resolveFileDisplayMode(this.session.settings);
565
+ const displayMode = resolveFileDisplayMode(this.session);
566
566
 
567
567
  // Handle internal URLs (agent://, skill://)
568
568
  const internalRouter = this.session.internalRouter;
@@ -848,7 +848,7 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
848
848
  async #handleInternalUrl(url: string, offset?: number, limit?: number): Promise<AgentToolResult<ReadToolDetails>> {
849
849
  const internalRouter = this.session.internalRouter!;
850
850
 
851
- const displayMode = resolveFileDisplayMode(this.session.settings);
851
+ const displayMode = resolveFileDisplayMode(this.session);
852
852
 
853
853
  // Check if URL has query extraction (agent:// only)
854
854
  let parsed: URL;
@@ -1,25 +1,34 @@
1
1
  /**
2
2
  * Resolve line-display mode for file-like outputs (read, grep, @file mentions).
3
3
  */
4
- export interface FileDisplayModeSettings {
5
- get(key: "readLineNumbers" | "readHashLines" | "edit.mode"): unknown;
6
- }
7
4
 
8
5
  export interface FileDisplayMode {
9
6
  lineNumbers: boolean;
10
7
  hashLines: boolean;
11
8
  }
12
9
 
10
+ /** Session-like object providing settings and tool availability for display mode resolution. */
11
+ export interface FileDisplayModeSession {
12
+ /** Whether the edit tool is available. Hashlines are suppressed without it. */
13
+ hasEditTool?: boolean;
14
+ settings: {
15
+ get(key: "readLineNumbers" | "readHashLines" | "edit.mode"): unknown;
16
+ };
17
+ }
18
+
13
19
  /**
14
- * Computes effective line display mode from settings/env.
20
+ * Computes effective line display mode from session settings/env.
15
21
  * Hashline mode takes precedence and implies line-addressed output everywhere.
22
+ * Hashlines are suppressed when the edit tool is not available (e.g. explore agents).
16
23
  */
17
- export function resolveFileDisplayMode(settings: FileDisplayModeSettings): FileDisplayMode {
24
+ export function resolveFileDisplayMode(session: FileDisplayModeSession): FileDisplayMode {
25
+ const { settings } = session;
26
+ const hasEditTool = session.hasEditTool ?? true;
18
27
  const hashLines =
19
- settings.get("readHashLines") === true ||
20
- settings.get("edit.mode") === "hashline" ||
21
- Bun.env.PI_EDIT_VARIANT === "hashline";
22
-
28
+ hasEditTool &&
29
+ (settings.get("readHashLines") === true ||
30
+ settings.get("edit.mode") === "hashline" ||
31
+ Bun.env.PI_EDIT_VARIANT === "hashline");
23
32
  return {
24
33
  hashLines,
25
34
  lineNumbers: hashLines || settings.get("readLineNumbers") === true,