@oh-my-pi/pi-coding-agent 14.9.8 → 14.9.9
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 +19 -0
- package/package.json +7 -7
- package/scripts/build-binary.ts +11 -0
- package/src/cli/stats-cli.ts +2 -0
- package/src/cli.ts +23 -1
- package/src/config/settings-schema.ts +30 -9
- package/src/config/settings.ts +18 -1
- package/src/edit/streaming.ts +1 -1
- package/src/eval/js/context-manager.ts +9 -8
- package/src/hashline/grammar.lark +1 -1
- package/src/hashline/input.ts +11 -5
- package/src/internal-urls/docs-index.generated.ts +1 -1
- package/src/prompts/tools/hashline.md +15 -15
- package/src/task/index.ts +12 -50
- package/src/task/worktree.ts +170 -239
- package/src/tools/browser/tab-supervisor.ts +13 -13
- package/src/utils/git.ts +5 -0
- package/src/task/isolation-backend.ts +0 -94
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
Your patch language is a compact, line-anchored edit format.
|
|
2
2
|
|
|
3
|
-
A patch contains one or more file sections. The first non-blank line of every edit section **MUST** be
|
|
3
|
+
A patch contains one or more file sections. The first non-blank line of every edit section **MUST** be `@@ PATH`.
|
|
4
4
|
Operations reference lines in the file by their line number and hash, called "Anchors", e.g. `5th`, `123ab`.
|
|
5
5
|
You **MUST** copy them verbatim from the latest output for the file you're editing.
|
|
6
6
|
|
|
7
7
|
Purely textual format. The tool has NO awareness of language, indentation, brackets, fences, or table widths. Emit valid syntax in replacements/insertions.
|
|
8
8
|
|
|
9
9
|
<ops>
|
|
10
|
-
|
|
10
|
+
@@ PATH header: subsequent ops apply to PATH
|
|
11
11
|
+ ANCHOR insert lines AFTER the anchored line (or EOF); payload follows as `{{hsep}}TEXT` lines
|
|
12
12
|
< ANCHOR insert lines BEFORE the anchored line (or BOF); payload follows as `{{hsep}}TEXT` lines
|
|
13
13
|
- A..B delete the line range (inclusive).
|
|
@@ -64,18 +64,18 @@ When your edit involves brace boundaries (`{` / `}`), prefer these shapes:
|
|
|
64
64
|
|
|
65
65
|
<examples>
|
|
66
66
|
# Replace one line (preserve the leading tab from the original)
|
|
67
|
-
|
|
67
|
+
@@ a.ts
|
|
68
68
|
= {{hrefr 5}}..{{hrefr 5}}
|
|
69
69
|
{{hsep}} return clean.trim().toUpperCase();
|
|
70
70
|
|
|
71
71
|
# Replace a contiguous range with multiple lines
|
|
72
|
-
|
|
72
|
+
@@ a.ts
|
|
73
73
|
= {{hrefr 4}}..{{hrefr 5}}
|
|
74
74
|
{{hsep}} const clean = (name || DEF).trim();
|
|
75
75
|
{{hsep}} return clean.length === 0 ? DEF : clean.toUpperCase();
|
|
76
76
|
|
|
77
77
|
# Replace a full multiline destructuring/call statement
|
|
78
|
-
|
|
78
|
+
@@ b.ts
|
|
79
79
|
= {{hrefr 1}}..{{hrefr 8}}
|
|
80
80
|
{{hsep}}const {
|
|
81
81
|
{{hsep}} events,
|
|
@@ -88,32 +88,32 @@ When your edit involves brace boundaries (`{` / `}`), prefer these shapes:
|
|
|
88
88
|
{{hsep}});
|
|
89
89
|
|
|
90
90
|
# Insert BEFORE a line
|
|
91
|
-
|
|
91
|
+
@@ a.ts
|
|
92
92
|
< {{hrefr 5}}
|
|
93
93
|
{{hsep}} const debug = false;
|
|
94
94
|
|
|
95
95
|
# Insert AFTER a line
|
|
96
|
-
|
|
96
|
+
@@ a.ts
|
|
97
97
|
+ {{hrefr 4}}
|
|
98
98
|
{{hsep}} if (clean.length === 0) return DEF;
|
|
99
99
|
|
|
100
100
|
# Append to end of file
|
|
101
|
-
|
|
101
|
+
@@ a.ts
|
|
102
102
|
+ EOF
|
|
103
103
|
{{hsep}}export const done = true;
|
|
104
104
|
|
|
105
105
|
# Delete a single line
|
|
106
|
-
|
|
106
|
+
@@ a.ts
|
|
107
107
|
- {{hrefr 2}}..{{hrefr 2}}
|
|
108
108
|
|
|
109
109
|
# Blank a line in place (no payload required)
|
|
110
|
-
|
|
110
|
+
@@ a.ts
|
|
111
111
|
= {{hrefr 2}}..{{hrefr 2}}
|
|
112
112
|
</examples>
|
|
113
113
|
|
|
114
114
|
<anti-pattern>
|
|
115
115
|
# WRONG — replaces 5 lines just to add one. Use `+` at the boundary instead.
|
|
116
|
-
|
|
116
|
+
@@ a.ts
|
|
117
117
|
= {{hrefr 1}}..{{hrefr 5}}
|
|
118
118
|
{{hsep}}const DEF = "guest";
|
|
119
119
|
{{hsep}}const DEBUG = false;
|
|
@@ -123,12 +123,12 @@ When your edit involves brace boundaries (`{` / `}`), prefer these shapes:
|
|
|
123
123
|
{{hsep}} return clean.trim();
|
|
124
124
|
|
|
125
125
|
# RIGHT — same effect, one-line insert
|
|
126
|
-
|
|
126
|
+
@@ a.ts
|
|
127
127
|
+ {{hrefr 1}}
|
|
128
128
|
{{hsep}}const DEBUG = false;
|
|
129
129
|
|
|
130
130
|
# WRONG — continuation-fragment payload from the middle of a larger statement.
|
|
131
|
-
|
|
131
|
+
@@ b.ts
|
|
132
132
|
= {{hrefr 5}}..{{hrefr 7}}
|
|
133
133
|
{{hsep}}} = await getStreamResponse(
|
|
134
134
|
{{hsep}} request,
|
|
@@ -136,7 +136,7 @@ When your edit involves brace boundaries (`{` / `}`), prefer these shapes:
|
|
|
136
136
|
{{hsep}} onEvent,
|
|
137
137
|
|
|
138
138
|
# RIGHT — widen to the full statement so the payload starts at a self-contained boundary.
|
|
139
|
-
|
|
139
|
+
@@ b.ts
|
|
140
140
|
= {{hrefr 1}}..{{hrefr 8}}
|
|
141
141
|
{{hsep}}const {
|
|
142
142
|
{{hsep}} events,
|
|
@@ -154,7 +154,7 @@ If your replacement payload would render with even one unchanged line in the dif
|
|
|
154
154
|
<critical>
|
|
155
155
|
- Always copy anchors exactly from tool output, but **NEVER** include line content after the `{{hsep}}` separator in the op line.
|
|
156
156
|
- Every inserted/replacement content line **MUST** start with `{{hsep}}`; raw content lines are invalid.
|
|
157
|
-
- Do not write unified diff syntax (
|
|
157
|
+
- Do not write unified diff syntax (`@@ -X,Y +X,Y @@`, `-OLD`, `+NEW`). The header is `@@ PATH`; line ops are `<`/`+`/`-`/`=`.
|
|
158
158
|
- `= A..B` deletes the range; payload is what's written. If a payload edge line already exists immediately outside `A..B`, widen the range to cover it — otherwise it duplicates.
|
|
159
159
|
- Multiple ops in one patch are cheap. Prefer two narrow ops over one wide `=`.
|
|
160
160
|
- Before choosing a `= A..B` range, mentally delete lines A through B. If that would split an unclosed bracket, paren, brace, or string/template from a line above A, or orphan a closing delimiter that belongs to an opener inside the range, you are bisecting a syntactic construct. Widen the range to a self-contained boundary, or use `+`/`-` instead.
|
package/src/task/index.ts
CHANGED
|
@@ -36,7 +36,6 @@ import { generateCommitMessage } from "../utils/commit-message-generator";
|
|
|
36
36
|
import * as git from "../utils/git";
|
|
37
37
|
import { discoverAgents, getAgent } from "./discovery";
|
|
38
38
|
import { runSubprocess } from "./executor";
|
|
39
|
-
import { resolveIsolationBackendForTaskExecution } from "./isolation-backend";
|
|
40
39
|
import { AgentOutputManager } from "./output-manager";
|
|
41
40
|
import { mapWithConcurrencyLimit, Semaphore } from "./parallel";
|
|
42
41
|
import { renderResult, renderCall as renderTaskCall } from "./render";
|
|
@@ -50,20 +49,17 @@ import {
|
|
|
50
49
|
type TaskToolDetails,
|
|
51
50
|
} from "./types";
|
|
52
51
|
import {
|
|
53
|
-
applyBaseline,
|
|
54
52
|
applyNestedPatches,
|
|
55
53
|
captureBaseline,
|
|
56
54
|
captureDeltaPatch,
|
|
57
|
-
|
|
58
|
-
cleanupProjfsOverlay,
|
|
55
|
+
cleanupIsolation,
|
|
59
56
|
cleanupTaskBranches,
|
|
60
|
-
cleanupWorktree,
|
|
61
57
|
commitToBranch,
|
|
62
|
-
|
|
63
|
-
ensureProjfsOverlay,
|
|
64
|
-
ensureWorktree,
|
|
58
|
+
ensureIsolation,
|
|
65
59
|
getRepoRoot,
|
|
60
|
+
type IsolationHandle,
|
|
66
61
|
mergeTaskBranches,
|
|
62
|
+
parseIsolationMode,
|
|
67
63
|
type WorktreeBaseline,
|
|
68
64
|
} from "./worktree";
|
|
69
65
|
|
|
@@ -530,7 +526,7 @@ export class TaskTool implements AgentTool<TSchema, TaskToolDetails, Theme> {
|
|
|
530
526
|
content: [
|
|
531
527
|
{
|
|
532
528
|
type: "text",
|
|
533
|
-
text: "Task isolation is disabled.
|
|
529
|
+
text: "Task isolation is disabled.",
|
|
534
530
|
},
|
|
535
531
|
],
|
|
536
532
|
details: {
|
|
@@ -700,28 +696,7 @@ export class TaskTool implements AgentTool<TSchema, TaskToolDetails, Theme> {
|
|
|
700
696
|
}
|
|
701
697
|
}
|
|
702
698
|
|
|
703
|
-
|
|
704
|
-
let isolationBackendWarning = "";
|
|
705
|
-
try {
|
|
706
|
-
const resolvedIsolation = await resolveIsolationBackendForTaskExecution(isolationMode, isIsolated, repoRoot);
|
|
707
|
-
effectiveIsolationMode = resolvedIsolation.effectiveIsolationMode;
|
|
708
|
-
isolationBackendWarning = resolvedIsolation.warning;
|
|
709
|
-
} catch (err) {
|
|
710
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
711
|
-
return {
|
|
712
|
-
content: [
|
|
713
|
-
{
|
|
714
|
-
type: "text",
|
|
715
|
-
text: message,
|
|
716
|
-
},
|
|
717
|
-
],
|
|
718
|
-
details: {
|
|
719
|
-
projectAgentsDir,
|
|
720
|
-
results: [],
|
|
721
|
-
totalDurationMs: Date.now() - startTime,
|
|
722
|
-
},
|
|
723
|
-
};
|
|
724
|
-
}
|
|
699
|
+
const preferredIsolationBackend = parseIsolationMode(isolationMode);
|
|
725
700
|
|
|
726
701
|
// Derive artifacts directory
|
|
727
702
|
const sessionFile = this.session.getSessionFile();
|
|
@@ -891,21 +866,15 @@ export class TaskTool implements AgentTool<TSchema, TaskToolDetails, Theme> {
|
|
|
891
866
|
}
|
|
892
867
|
|
|
893
868
|
const taskStart = Date.now();
|
|
894
|
-
let
|
|
869
|
+
let isolationHandle: IsolationHandle | undefined;
|
|
895
870
|
try {
|
|
896
871
|
if (!repoRoot || !baseline) {
|
|
897
872
|
throw new Error("Isolated task execution not initialized.");
|
|
898
873
|
}
|
|
899
874
|
const taskBaseline = structuredClone(baseline);
|
|
900
875
|
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
} else if (effectiveIsolationMode === "fuse-projfs") {
|
|
904
|
-
isolationDir = await ensureProjfsOverlay(repoRoot, task.id);
|
|
905
|
-
} else {
|
|
906
|
-
isolationDir = await ensureWorktree(repoRoot, task.id);
|
|
907
|
-
await applyBaseline(isolationDir, taskBaseline);
|
|
908
|
-
}
|
|
876
|
+
isolationHandle = await ensureIsolation(repoRoot, task.id, preferredIsolationBackend);
|
|
877
|
+
const isolationDir = isolationHandle.mergedDir;
|
|
909
878
|
|
|
910
879
|
const result = await runSubprocess({
|
|
911
880
|
cwd: this.session.cwd,
|
|
@@ -1017,14 +986,8 @@ export class TaskTool implements AgentTool<TSchema, TaskToolDetails, Theme> {
|
|
|
1017
986
|
error: message,
|
|
1018
987
|
};
|
|
1019
988
|
} finally {
|
|
1020
|
-
if (
|
|
1021
|
-
|
|
1022
|
-
await cleanupFuseOverlay(isolationDir);
|
|
1023
|
-
} else if (effectiveIsolationMode === "fuse-projfs") {
|
|
1024
|
-
await cleanupProjfsOverlay(isolationDir);
|
|
1025
|
-
} else {
|
|
1026
|
-
await cleanupWorktree(isolationDir);
|
|
1027
|
-
}
|
|
989
|
+
if (isolationHandle) {
|
|
990
|
+
await cleanupIsolation(isolationHandle);
|
|
1028
991
|
}
|
|
1029
992
|
}
|
|
1030
993
|
};
|
|
@@ -1256,7 +1219,6 @@ export class TaskTool implements AgentTool<TSchema, TaskToolDetails, Theme> {
|
|
|
1256
1219
|
});
|
|
1257
1220
|
|
|
1258
1221
|
const outputIds = results.filter(r => !r.aborted || r.output.trim()).map(r => `agent://${r.id}`);
|
|
1259
|
-
const backendSummaryPrefix = isolationBackendWarning ? `\n\n${isolationBackendWarning}` : "";
|
|
1260
1222
|
const summary = prompt.render(taskSummaryTemplate, {
|
|
1261
1223
|
successCount,
|
|
1262
1224
|
totalCount: results.length,
|
|
@@ -1266,7 +1228,7 @@ export class TaskTool implements AgentTool<TSchema, TaskToolDetails, Theme> {
|
|
|
1266
1228
|
summaries,
|
|
1267
1229
|
outputIds,
|
|
1268
1230
|
agentName,
|
|
1269
|
-
mergeSummary
|
|
1231
|
+
mergeSummary,
|
|
1270
1232
|
});
|
|
1271
1233
|
|
|
1272
1234
|
// Cleanup temp directory if used
|