@oh-my-pi/pi-coding-agent 15.7.3 → 15.7.5
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 +39 -0
- package/dist/types/config/settings-schema.d.ts +3 -22
- package/dist/types/extensibility/custom-tools/types.d.ts +2 -2
- package/dist/types/extensibility/shared-events.d.ts +2 -2
- package/dist/types/internal-urls/local-protocol.d.ts +19 -9
- package/dist/types/internal-urls/types.d.ts +14 -0
- package/dist/types/lsp/client.d.ts +3 -0
- package/dist/types/mcp/manager.d.ts +14 -5
- package/dist/types/modes/controllers/command-controller.d.ts +2 -3
- package/dist/types/session/agent-session.d.ts +2 -6
- package/dist/types/session/shake-types.d.ts +3 -3
- package/dist/types/task/repair-args.d.ts +52 -0
- package/dist/types/tiny/models.d.ts +0 -14
- package/dist/types/tiny/title-client.d.ts +28 -2
- package/dist/types/tiny/title-protocol.d.ts +8 -9
- package/dist/types/tools/find.d.ts +1 -1
- package/dist/types/tools/path-utils.d.ts +7 -0
- package/dist/types/tui/output-block.d.ts +7 -7
- package/package.json +9 -9
- package/scripts/build-binary.ts +0 -1
- package/src/cli.ts +59 -0
- package/src/config/settings-schema.ts +3 -24
- package/src/config/settings.ts +10 -0
- package/src/extensibility/custom-tools/types.ts +2 -2
- package/src/extensibility/shared-events.ts +2 -2
- package/src/internal-urls/docs-index.generated.ts +2 -2
- package/src/internal-urls/local-protocol.ts +23 -11
- package/src/internal-urls/types.ts +15 -0
- package/src/lsp/client.ts +28 -5
- package/src/mcp/manager.ts +87 -4
- package/src/modes/controllers/command-controller.ts +7 -39
- package/src/modes/controllers/event-controller.ts +33 -26
- package/src/modes/controllers/mcp-command-controller.ts +1 -1
- package/src/prompts/system/project-prompt.md +3 -2
- package/src/prompts/system/subagent-system-prompt.md +12 -8
- package/src/prompts/system/system-prompt.md +8 -6
- package/src/session/agent-session.ts +11 -93
- package/src/session/shake-types.ts +4 -5
- package/src/slash-commands/builtin-registry.ts +2 -4
- package/src/task/executor.ts +14 -4
- package/src/task/index.ts +3 -2
- package/src/task/repair-args.ts +117 -0
- package/src/tiny/models.ts +0 -28
- package/src/tiny/title-client.ts +133 -43
- package/src/tiny/title-protocol.ts +11 -16
- package/src/tiny/worker.ts +6 -61
- package/src/tools/ast-edit.ts +3 -0
- package/src/tools/ast-grep.ts +3 -0
- package/src/tools/find.ts +20 -6
- package/src/tools/gh.ts +1 -0
- package/src/tools/path-utils.ts +13 -2
- package/src/tools/read.ts +1 -0
- package/src/tools/search.ts +12 -1
- package/src/tui/output-block.ts +37 -75
- package/src/utils/git.ts +9 -3
package/src/tui/output-block.ts
CHANGED
|
@@ -20,10 +20,10 @@ export interface OutputBlockOptions {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
const BORDER_SHIMMER_TICK_MS = 50;
|
|
23
|
-
/** Duration of one full
|
|
24
|
-
*
|
|
25
|
-
* instead of teleporting it. */
|
|
26
|
-
const
|
|
23
|
+
/** Duration of one full left↔right↔left bounce of the bottom-edge segment, in
|
|
24
|
+
* ms. Position is derived from the wall clock against this fixed cycle so a
|
|
25
|
+
* resize only nudges the segment proportionally instead of teleporting it. */
|
|
26
|
+
const BORDER_BOUNCE_MS = 3000;
|
|
27
27
|
/** Length, in border cells, of the moving segment. */
|
|
28
28
|
const BORDER_SEGMENT_LEN = 8;
|
|
29
29
|
|
|
@@ -36,38 +36,25 @@ export function borderShimmerTick(): number {
|
|
|
36
36
|
return Math.floor(Date.now() / BORDER_SHIMMER_TICK_MS);
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
/** Ease-in-out so the segment decelerates into and accelerates out of
|
|
39
|
+
/** Ease-in-out so the segment decelerates into and accelerates out of each wall. */
|
|
40
40
|
function easeInOutQuad(t: number): number {
|
|
41
41
|
return t < 0.5 ? 2 * t * t : 1 - (-2 * t + 2) ** 2 / 2;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
/**
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
* from the wall clock against a fixed
|
|
50
|
-
*
|
|
45
|
+
* Column of the travelling segment's center on the bottom edge for a box of
|
|
46
|
+
* inner width `W` at time `now`. The segment bounces left → right → left across
|
|
47
|
+
* the bottom border: a triangle wave over one full there-and-back cycle, eased
|
|
48
|
+
* per leg so it slows as it nears each wall before reversing. Position is
|
|
49
|
+
* derived from the wall clock against a fixed cycle, so a resize shifts the
|
|
50
|
+
* center proportionally — no reset.
|
|
51
51
|
*/
|
|
52
|
-
export function
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
//
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
let acc = 0;
|
|
59
|
-
let start = 0;
|
|
60
|
-
for (let i = 0; i < 4; i++) {
|
|
61
|
-
const len = edgeLens[i]!;
|
|
62
|
-
const frac = len / P;
|
|
63
|
-
if (len > 0 && t < acc + frac) {
|
|
64
|
-
const lf = (t - acc) / frac;
|
|
65
|
-
return (start + Math.floor(easeInOutQuad(lf) * len)) % P;
|
|
66
|
-
}
|
|
67
|
-
acc += frac;
|
|
68
|
-
start += len;
|
|
69
|
-
}
|
|
70
|
-
return P - 1;
|
|
52
|
+
export function borderSegmentHeadCol(W: number, now: number): number {
|
|
53
|
+
if (W <= 1) return 0;
|
|
54
|
+
const phase = (((now % BORDER_BOUNCE_MS) + BORDER_BOUNCE_MS) % BORDER_BOUNCE_MS) / BORDER_BOUNCE_MS;
|
|
55
|
+
// Triangle: 0→1 rightward over the first half, 1→0 leftward over the second.
|
|
56
|
+
const leg = phase < 0.5 ? phase * 2 : 2 - phase * 2;
|
|
57
|
+
return easeInOutQuad(leg) * (W - 1);
|
|
71
58
|
}
|
|
72
59
|
|
|
73
60
|
/**
|
|
@@ -164,30 +151,26 @@ export function renderOutputBlock(options: OutputBlockOptions, theme: Theme): st
|
|
|
164
151
|
const W = lineWidth;
|
|
165
152
|
const animate = (options.animate ?? false) && (state === "running" || state === "pending") && W >= 2 && H >= 2;
|
|
166
153
|
|
|
167
|
-
// ── Segment geometry: one dark run
|
|
168
|
-
// top
|
|
169
|
-
|
|
170
|
-
const segLen = Math.min(BORDER_SEGMENT_LEN,
|
|
171
|
-
const head = animate ?
|
|
154
|
+
// ── Segment geometry: one dark run bounces left ↔ right along the bottom
|
|
155
|
+
// edge only. The top, interior separators, and side borders stay the flat
|
|
156
|
+
// accent color. ──
|
|
157
|
+
const segLen = animate ? Math.min(BORDER_SEGMENT_LEN, W) : 0;
|
|
158
|
+
const head = animate ? borderSegmentHeadCol(W, Date.now()) : 0;
|
|
159
|
+
const segHalf = segLen / 2;
|
|
172
160
|
const segAnsi = animate ? (darkenFgAnsi(theme.getFgAnsi(borderColor), 0.4) ?? theme.getFgAnsi("borderMuted")) : "";
|
|
173
161
|
const seg = (text: string) => `${segAnsi}${text}\x1b[39m`;
|
|
174
162
|
|
|
175
|
-
//
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
if (r === H - 1) return W - 1 + (H - 1) + (W - 1 - c);
|
|
180
|
-
return W - 1 + (H - 1) + (W - 1) + (H - 1 - r);
|
|
181
|
-
};
|
|
182
|
-
const isLit = (idx: number): boolean => (((idx - head) % P) + P) % P < segLen;
|
|
183
|
-
// Color a run of border glyphs starting at (row r, col startCol), grouping
|
|
163
|
+
// A bottom-edge column is lit when it lies within half a segment of the
|
|
164
|
+
// travelling center.
|
|
165
|
+
const isLit = (col: number): boolean => Math.abs(col - head) < segHalf;
|
|
166
|
+
// Color a run of bottom-edge glyphs starting at column `startCol`, grouping
|
|
184
167
|
// consecutive same-state cells so each run emits a single escape pair.
|
|
185
|
-
const colorEdge = (glyphs: string,
|
|
168
|
+
const colorEdge = (glyphs: string, startCol: number): string => {
|
|
186
169
|
let out = "";
|
|
187
170
|
let runLit: boolean | null = null;
|
|
188
171
|
let buf = "";
|
|
189
172
|
for (let i = 0; i < glyphs.length; i++) {
|
|
190
|
-
const lit = isLit(
|
|
173
|
+
const lit = isLit(startCol + i);
|
|
191
174
|
if (lit !== runLit) {
|
|
192
175
|
if (runLit !== null) out += (runLit ? seg : border)(buf);
|
|
193
176
|
buf = "";
|
|
@@ -199,10 +182,7 @@ export function renderOutputBlock(options: OutputBlockOptions, theme: Theme): st
|
|
|
199
182
|
return out;
|
|
200
183
|
};
|
|
201
184
|
|
|
202
|
-
const renderBar = (
|
|
203
|
-
row: { leftChar: string; rightChar: string; label?: string; meta?: string },
|
|
204
|
-
r: number,
|
|
205
|
-
): string => {
|
|
185
|
+
const renderBar = (row: { leftChar: string; rightChar: string; label?: string; meta?: string }): string => {
|
|
206
186
|
const leftGlyphs = `${row.leftChar}${cap}`;
|
|
207
187
|
const rightGlyph = row.rightChar;
|
|
208
188
|
if (lineWidth <= 0) return border(leftGlyphs) + border(rightGlyph);
|
|
@@ -215,36 +195,22 @@ export function renderOutputBlock(options: OutputBlockOptions, theme: Theme): st
|
|
|
215
195
|
const labelWidth = visibleWidth(trimmedLabel);
|
|
216
196
|
const fillCount = Math.max(0, lineWidth - leftWidth - labelWidth - rightWidth);
|
|
217
197
|
const fillGlyphs = h.repeat(fillCount);
|
|
218
|
-
|
|
219
|
-
return `${border(leftGlyphs)}${trimmedLabel}${border(fillGlyphs)}${border(rightGlyph)}`;
|
|
220
|
-
}
|
|
221
|
-
if (r === 0 || r === H - 1) {
|
|
222
|
-
// Top/bottom edge: the whole horizontal run lies on the perimeter.
|
|
223
|
-
const leftStr = colorEdge(leftGlyphs, r, 0);
|
|
224
|
-
const fillStr = colorEdge(fillGlyphs, r, leftWidth + labelWidth);
|
|
225
|
-
const rightStr = colorEdge(rightGlyph, r, lineWidth - rightWidth);
|
|
226
|
-
return `${leftStr}${trimmedLabel}${fillStr}${rightStr}`;
|
|
227
|
-
}
|
|
228
|
-
// Interior separator: only the first/last cell sit on the outer edge.
|
|
229
|
-
return `${colorEdge(row.leftChar, r, 0)}${border(cap)}${trimmedLabel}${border(fillGlyphs)}${colorEdge(rightGlyph, r, lineWidth - rightWidth)}`;
|
|
198
|
+
return `${border(leftGlyphs)}${trimmedLabel}${border(fillGlyphs)}${border(rightGlyph)}`;
|
|
230
199
|
};
|
|
231
200
|
|
|
232
|
-
const renderBottom = (row: { leftChar: string; rightChar: string }
|
|
201
|
+
const renderBottom = (row: { leftChar: string; rightChar: string }): string => {
|
|
233
202
|
const leftGlyphs = `${row.leftChar}${cap}`;
|
|
234
203
|
const rightGlyph = row.rightChar;
|
|
235
204
|
const fillCount = Math.max(0, lineWidth - visibleWidth(leftGlyphs) - visibleWidth(rightGlyph));
|
|
236
205
|
const fillGlyphs = h.repeat(fillCount);
|
|
237
206
|
if (!animate) return `${border(leftGlyphs)}${border(fillGlyphs)}${border(rightGlyph)}`;
|
|
238
|
-
const leftStr = colorEdge(leftGlyphs,
|
|
239
|
-
const fillStr = colorEdge(fillGlyphs,
|
|
240
|
-
const rightStr = colorEdge(rightGlyph,
|
|
207
|
+
const leftStr = colorEdge(leftGlyphs, 0);
|
|
208
|
+
const fillStr = colorEdge(fillGlyphs, visibleWidth(leftGlyphs));
|
|
209
|
+
const rightStr = colorEdge(rightGlyph, lineWidth - visibleWidth(rightGlyph));
|
|
241
210
|
return `${leftStr}${fillStr}${rightStr}`;
|
|
242
211
|
};
|
|
243
212
|
|
|
244
|
-
const renderContent = (inner: string
|
|
245
|
-
if (!animate) return `${border(`${v} `)}${inner}${border(v)}`;
|
|
246
|
-
return `${colorEdge(v, r, 0)} ${inner}${colorEdge(v, r, lineWidth - 1)}`;
|
|
247
|
-
};
|
|
213
|
+
const renderContent = (inner: string): string => `${border(`${v} `)}${inner}${border(v)}`;
|
|
248
214
|
|
|
249
215
|
const lines: string[] = [];
|
|
250
216
|
for (let r = 0; r < H; r++) {
|
|
@@ -254,11 +220,7 @@ export function renderOutputBlock(options: OutputBlockOptions, theme: Theme): st
|
|
|
254
220
|
continue;
|
|
255
221
|
}
|
|
256
222
|
const line =
|
|
257
|
-
row.kind === "bar"
|
|
258
|
-
? renderBar(row, r)
|
|
259
|
-
: row.kind === "bottom"
|
|
260
|
-
? renderBottom(row, r)
|
|
261
|
-
: renderContent(row.inner, r);
|
|
223
|
+
row.kind === "bar" ? renderBar(row) : row.kind === "bottom" ? renderBottom(row) : renderContent(row.inner);
|
|
262
224
|
lines.push(padToWidth(line, lineWidth, bgFn));
|
|
263
225
|
}
|
|
264
226
|
|
package/src/utils/git.ts
CHANGED
|
@@ -1261,9 +1261,15 @@ export async function clone(url: string, targetDir: string, options: CloneOption
|
|
|
1261
1261
|
const absoluteTarget = path.resolve(targetDir);
|
|
1262
1262
|
await fs.promises.mkdir(path.dirname(absoluteTarget), { recursive: true });
|
|
1263
1263
|
|
|
1264
|
-
|
|
1264
|
+
// `git clone --depth 1 --single-branch` only fetches the tip of the target
|
|
1265
|
+
// branch, so any subsequent `git checkout <sha>` for a non-tip commit fails
|
|
1266
|
+
// with "reference is not a tree". When the caller pinned a specific SHA we
|
|
1267
|
+
// fall back to a full clone so the object is guaranteed to be present.
|
|
1268
|
+
const shallow = !options.sha;
|
|
1269
|
+
const args = ["clone"];
|
|
1270
|
+
if (shallow) args.push("--depth", "1");
|
|
1265
1271
|
if (options.ref) args.push("--branch", options.ref, "--single-branch");
|
|
1266
|
-
else args.push("--single-branch");
|
|
1272
|
+
else if (shallow) args.push("--single-branch");
|
|
1267
1273
|
args.push(url, absoluteTarget);
|
|
1268
1274
|
|
|
1269
1275
|
try {
|
|
@@ -1273,7 +1279,7 @@ export async function clone(url: string, targetDir: string, options: CloneOption
|
|
|
1273
1279
|
await checkout(absoluteTarget, options.sha, options.signal);
|
|
1274
1280
|
} catch {
|
|
1275
1281
|
await fs.promises.rm(absoluteTarget, { force: true, recursive: true });
|
|
1276
|
-
throw new Error(`Failed to checkout SHA ${options.sha}
|
|
1282
|
+
throw new Error(`Failed to checkout SHA ${options.sha} in cloned repository ${url}`);
|
|
1277
1283
|
}
|
|
1278
1284
|
}
|
|
1279
1285
|
} catch (err) {
|