@oh-my-pi/pi-coding-agent 15.5.0 → 15.5.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.
@@ -1,110 +1,63 @@
1
1
  Your patch language is a compact, line-anchored edit format.
2
2
 
3
- A patch contains one or more file sections. Each anchored section starts with `¶PATH#HASH`, copied verbatim from the latest `read`/`search` output. `HASH` is a 4-hex file hash; `¶PATH` without `#HASH` is allowed only for new-file / `BOF` / `EOF` boundary inserts.
4
-
5
- Operations reference lines by bare line number (`5`, `123`). Payload text is verbatim — NEVER escape unicode. The tool has NO awareness of language, indentation, brackets, fences, or table widths. Emit valid syntax in replacements/insertions.
3
+ <payload>
4
+ Patch payload is a series of hunks: `¶PATH#HASH` header followed by any number of operations. `HASH` should be copied as is from read/search. Missing? Re-`read`.
5
+ - No context rows, no gutters.
6
+ - NEVER restate unchanged lines "for context".
7
+ - Inline payload after an op is literal. Additional payload lines MUST start with `+`; that delimiter is stripped.
8
+ - Payload indentation after the op sigil or after `+` is literal.
9
+ </payload>
6
10
 
7
11
  <ops>
8
- ¶PATH#HASH header: subsequent anchored ops apply to PATH at file hash HASH
9
- ¶PATH unbound header: only BOF/EOF boundary inserts
10
- LINE↑PAYLOAD insert ABOVE the anchored line (or BOF)
11
- LINE↓PAYLOAD insert BELOW the anchored line (or EOF)
12
- A-B:PAYLOAD replace the inclusive range A..B with PAYLOAD
13
- A:PAYLOAD shorthand for A-A:PAYLOAD
14
- A-B! delete the inclusive range A..B (payload forbidden)
15
- A! shorthand for A-A!
12
+ LINE↑PAYLOAD insert before (or BOF↑)
13
+ LINE↓PAYLOAD insert after (or EOF↓)
14
+ A-B:PAYLOAD replace A..B (or A: == A..A)
15
+ A-B! delete A..B (or A! == A..A)
16
+ +PAYLOAD continuation payload line; leading `+` is not written
16
17
  </ops>
17
18
 
18
- <payload>
19
- - The first payload line is whatever follows the sigil on the op line. Additional payload lines follow on the next lines and append after the first.
20
- - An empty inline IS an empty first line. So bare `A↓` / `A↑` insert one blank line; bare `A:` / `A-B:` replace with one blank line. `A↓\nfoo` inserts blank-then-`foo`, NOT just `foo`.
21
- - Payload ends at the next op, next `¶PATH`, envelope marker, or EOF. Blank lines immediately before a next op or `¶PATH` are dropped; blank lines between content lines are preserved.
22
- </payload>
23
-
24
19
  <rules>
25
- - The sigil tells where content lands: `↑` above, `↓` below, `:` replaces, `!` deletes.
26
- - **Payload is only what's NEW relative to your range.** `:` replaces inside; `↑`/`↓` add at anchor. NEVER repeat the anchor line or neighbors — that duplicates them.
27
- - **Pick a self-contained unit.** Touching a multiline construct (return, array, brace block, JSX element)? Widen the range to span it. Don't bisect.
28
- - Smallest op wins: add with `↑`/`↓`; replace with `:`; delete with `!`.
29
- - Anchors reference the file as last read. ONE patch, ONE coordinate space — later ops still use original line numbers.
20
+ - **Payload is only what's NEW.** `:` replaces inside; `↑`/`↓` add at anchor. NEVER repeat anchor lines or neighbors.
21
+ - **Continuation lines require `+`.** Use `+` for a blank payload line; use `++text` to write a line starting with `+text`.
22
+ - **Go small.** Add `↑`/`↓`; replace `:`; delete `!`.
23
+ - **Line numbers are frozen references to what you have seen.** Later ops still use original line numbers.
30
24
  </rules>
31
25
 
32
26
  <common-failures>
33
- - **NEVER replay past your range.** Stop before B+1; extend B if it must go.
34
- - **NEVER duplicate chunks inside one payload.**
35
- - **Read lines look like replace ops.** `84:content` already means "make line 84 equal to content" — don't echo a context line before it.
27
+ - **NEVER replay past your range.** Stop before B+1; extend B if needed.
28
+ - **Read lines look like replace ops.** `84:content` = "make line 84 content" — don't echo context before it.
36
29
  - **NEVER fabricate file hashes.** Missing? Re-`read`.
37
- - **`A!` deletes silently.** Deleting a line that closes/opens a block (`}`, `} else {`, `})`, `*/`) breaks structure with no parse error.
38
- - **Pure removal uses `A-B!`, NEVER `A-B:something`.** If you have nothing to put in the range, use `!`. `A-B:X` where line `A-1` or `B+1` already reads `X` silently produces two copies of `X` — the tool trusts your payload literally. Before writing `A-B:payload`, glance at `A-1` and `B+1` and confirm payload doesn't echo either.
39
30
  </common-failures>
40
31
 
41
- <case file="mod.ts">
42
- ¶mod.ts#1a2b
43
- {{hline 1 'const TITLE = "Mr";'}}
44
- {{hline 2 'export function greet(name) {'}}
45
- {{hline 3 ' return ['}}
46
- {{hline 4 ' TITLE,'}}
47
- {{hline 5 ' name?.trim() || "guest",'}}
48
- {{hline 6 ' ].join(" ");'}}
49
- {{hline 7 "}"}}
50
- </case>
51
-
52
- <examples>
53
- # Replace one line (inline payload preserves original indentation)
54
- ¶mod.ts#1a2b
55
- {{hrefr 1}}:const TITLE = "Mrs";
56
-
57
- # Replace a multiline statement — first line inline, rest below
58
- ¶mod.ts#1a2b
59
- {{hrefr 3}}-{{hrefr 6}}: return [
60
- "Mrs",
61
- name?.trim() || "guest",
62
- ].join(" ");
63
-
64
- # Insert ABOVE / BELOW a line
65
- ¶mod.ts#1a2b
66
- {{hrefr 4}}↓ "Dr",
67
- {{hrefr 5}}↑ "Dr",
68
-
69
- # Delete one line / blank a line / insert a blank line
70
- ¶mod.ts#1a2b
71
- {{hrefr 5}}!
72
- {{hrefr 6}}:
73
- {{hrefr 7}}↑
74
-
75
- # Create a file / append to one (hash optional for boundary-only inserts)
76
- ¶new.ts
77
- BOF↓export const done = true;
78
- ¶mod.ts
79
- EOF↓export const done = true;
80
-
81
- # Multi-file patch
82
- ¶src/a.ts#1a2b
83
- 12:const enabled = true;
84
- ¶src/b.ts#3c4d
85
- 20!
86
- </examples>
32
+ <example>
33
+ ```a.ts#1a2b
34
+ 1:const X = "a";
35
+ 2:export function f() { return X; }
36
+ ```
37
+
38
+ # replace with a continuation line, insert after, delete
39
+ ```
40
+ ¶a.ts#1a2b
41
+ 1:const X = "b";
42
+ +export const Y = X;
43
+ 1↓const Z = Y;
44
+ 2!
45
+ ```
46
+ </example>
87
47
 
88
48
  <anti-pattern>
89
- # WRONG — replaces 2 lines just to add one.
90
- ¶mod.ts#1a2b
91
- {{hrefr 1}}-{{hrefr 2}}:const TITLE = "Mr";
92
- const DEBUG = false;
93
- export function greet(name) {
94
-
95
- # RIGHT — one-line insert
96
- ¶mod.ts#1a2b
97
- {{hrefr 1}}↓const DEBUG = false;
98
-
99
- # WRONG — bisects a multiline statement
100
- ¶mod.ts#1a2b
101
- {{hrefr 4}}-{{hrefr 5}}: "Dr",
102
- name?.trim() || "guest",
103
-
104
- # RIGHT — widen to the full statement
105
- ¶mod.ts#1a2b
106
- {{hrefr 3}}-{{hrefr 6}}: return [
107
- "Dr",
108
- name?.trim() || "guest",
109
- ].join(" ");
49
+ # WRONG — INSERT used to change a line (old line survives)
50
+ 1↓const X = "b";
51
+ # WRONG — echoing read-style lines as context before the real op
52
+ 1:const X = "a";
53
+ 1-2:const X = "b";
54
+ export const Y = X; # raw continuation line missing required `+`
110
55
  </anti-pattern>
56
+
57
+ <critical>
58
+ - One op per range, ever.
59
+ - Pick op precisely. Update: `:`, add: `↑`/`↓`, remove: `!`.
60
+ - Payload is only what's NEW; never repeat anchor lines or neighbors.
61
+ - Continuation payload lines after the op line must start with `+`.
62
+ - Anchor exactly; don't anchor neighbors.
63
+ </critical>
@@ -532,10 +532,10 @@ function createSubagentSettings(baseSettings: Settings): Settings {
532
532
  ...snapshot,
533
533
  "async.enabled": false,
534
534
  "bash.autoBackground.enabled": false,
535
+
535
536
  // Subagents run headless — there is no UI to confirm prompts against, so
536
537
  // the parent task approval is the authorization boundary. Use yolo mode
537
- // to preserve unattended subagent execution while still honoring any
538
- // tool-level safety override that can be handled before execution.
538
+ // to preserve unattended subagent execution. User `tools.approval` policies still apply.
539
539
  "tools.approvalMode": "yolo",
540
540
  });
541
541
  }
@@ -87,8 +87,8 @@ function modeApprovesTier(mode: ApprovalMode, tier: ToolTier): boolean {
87
87
  * 2. User per-tool override, if set and valid.
88
88
  * 3. Active mode tier comparison.
89
89
  *
90
- * Tool decisions with `override: true` force a prompt in every mode unless the
91
- * user explicitly denies the tool; deny remains the strongest policy.
90
+ * In yolo mode, override-based tool prompts are ignored; user `tools.approval`
91
+ * settings remain authoritative.
92
92
  */
93
93
  export function resolveApproval(
94
94
  tool: ApprovalSubject,
@@ -99,6 +99,10 @@ export function resolveApproval(
99
99
  const decision = getToolDecision(tool, args);
100
100
  const userPolicy = Object.hasOwn(userConfig, tool.name) ? normalizePolicy(userConfig[tool.name]) : undefined;
101
101
 
102
+ if (mode === "yolo") {
103
+ return { policy: userPolicy ?? "allow", tier: decision.tier, override: false };
104
+ }
105
+
102
106
  if (decision.override) {
103
107
  if (userPolicy === "deny") {
104
108
  return { policy: "deny", tier: decision.tier, override: true };
package/src/tools/bash.ts CHANGED
@@ -42,11 +42,11 @@ const BASH_ENV_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
42
42
  const DEFAULT_AUTO_BACKGROUND_THRESHOLD_MS = 60_000;
43
43
 
44
44
  /**
45
- * Bash patterns that force an approval prompt even in yolo mode.
45
+ * Bash patterns flagged as safety critical for approval policy.
46
46
  *
47
- * Kept intentionally tight — the cost of a false positive is one extra prompt;
48
- * the cost of a false negative is data loss or a compromised host. New patterns
49
- * should target shapes that are virtually never legitimate in automation.
47
+ * Kept intentionally tight — the cost of a false negative is data loss or a compromised host,
48
+ * while false positives remain actionable through user policy control.
49
+ * New patterns should target shapes that are virtually never legitimate in automation.
50
50
  */
51
51
  export const CRITICAL_BASH_PATTERNS = [
52
52
  // Recursive destruction.