@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.
- package/CHANGELOG.md +23 -0
- package/dist/types/config/settings-schema.d.ts +3 -3
- package/dist/types/hashline/constants.d.ts +23 -0
- package/dist/types/hashline/executor.d.ts +7 -3
- package/dist/types/hashline/hash.d.ts +9 -7
- package/dist/types/hashline/tokenizer.d.ts +3 -0
- package/dist/types/tools/approval.d.ts +2 -2
- package/dist/types/tools/bash.d.ts +4 -4
- package/package.json +7 -7
- package/src/config/prompt-templates.ts +0 -125
- package/src/config/settings-schema.ts +4 -4
- package/src/edit/streaming.ts +3 -4
- package/src/extensibility/extensions/wrapper.ts +2 -3
- package/src/hashline/anchors.ts +1 -1
- package/src/hashline/apply.ts +66 -56
- package/src/hashline/constants.ts +29 -0
- package/src/hashline/execute.ts +5 -3
- package/src/hashline/executor.ts +125 -30
- package/src/hashline/grammar.lark +1 -1
- package/src/hashline/hash.ts +9 -6
- package/src/hashline/recovery.ts +35 -1
- package/src/hashline/tokenizer.ts +10 -4
- package/src/internal-urls/docs-index.generated.ts +2 -2
- package/src/prompts/tools/hashline.md +47 -94
- package/src/task/executor.ts +2 -2
- package/src/tools/approval.ts +6 -2
- package/src/tools/bash.ts +4 -4
|
@@ -1,110 +1,63 @@
|
|
|
1
1
|
Your patch language is a compact, line-anchored edit format.
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
|
-
-
|
|
26
|
-
- **
|
|
27
|
-
- **
|
|
28
|
-
-
|
|
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
|
|
34
|
-
- **
|
|
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
|
-
<
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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 —
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
const
|
|
93
|
-
|
|
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>
|
package/src/task/executor.ts
CHANGED
|
@@ -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
|
|
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
|
}
|
package/src/tools/approval.ts
CHANGED
|
@@ -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
|
-
*
|
|
91
|
-
*
|
|
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
|
|
45
|
+
* Bash patterns flagged as safety critical for approval policy.
|
|
46
46
|
*
|
|
47
|
-
* Kept intentionally tight — the cost of a false
|
|
48
|
-
*
|
|
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.
|