@oh-my-pi/pi-coding-agent 17.3.1 → 17.3.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 +8 -0
- package/dist/{CHANGELOG-2swgsx9f.md → CHANGELOG-fr2awajz.md} +8 -0
- package/dist/cli.js +3311 -3311
- package/dist/docs-index.generated.txt +1 -1
- package/dist/types/cli/update-cli.d.ts +35 -1
- package/package.json +13 -13
- package/src/cli/update-cli.ts +121 -25
- package/src/session/agent-session.ts +23 -9
- package/src/task/executor.ts +2 -1
- package/src/tools/read-format.ts +11 -10
- package/src/tools/run-scope.ts +4 -2
- package/src/utils/external-editor.ts +10 -11
- package/src/web/search/providers/gemini.ts +4 -9
|
@@ -112,6 +112,8 @@ interface UpdateMethodResolutionOptions {
|
|
|
112
112
|
miseBinDirs?: readonly string[];
|
|
113
113
|
miseDataDir?: string;
|
|
114
114
|
npmBinDir?: string;
|
|
115
|
+
/** Bun's configured global package directory, independent of its bin directory. */
|
|
116
|
+
bunGlobalDir?: string;
|
|
115
117
|
/**
|
|
116
118
|
* Whether the resolved omp path is a plain file (the standalone binary)
|
|
117
119
|
* rather than a package-manager symlink. Stops a binary install from being
|
|
@@ -119,8 +121,34 @@ interface UpdateMethodResolutionOptions {
|
|
|
119
121
|
* target directory.
|
|
120
122
|
*/
|
|
121
123
|
ompIsRegularFile?: boolean;
|
|
124
|
+
/**
|
|
125
|
+
* Absolute path named by the bin entry's first symlink hop. This deliberately
|
|
126
|
+
* preserves a global package symlink instead of resolving into its checkout.
|
|
127
|
+
*/
|
|
128
|
+
ompLinkTarget?: string;
|
|
122
129
|
}
|
|
130
|
+
type UpdateTarget = {
|
|
131
|
+
method: "brew";
|
|
132
|
+
} | {
|
|
133
|
+
method: "mise";
|
|
134
|
+
} | {
|
|
135
|
+
method: "nix";
|
|
136
|
+
} | {
|
|
137
|
+
method: "bun";
|
|
138
|
+
path?: string;
|
|
139
|
+
} | {
|
|
140
|
+
method: "npm";
|
|
141
|
+
path?: string;
|
|
142
|
+
} | {
|
|
143
|
+
method: "binary";
|
|
144
|
+
path: string;
|
|
145
|
+
replacesSymlink: boolean;
|
|
146
|
+
};
|
|
123
147
|
export declare function resolveUpdateMethodForTest(ompPath: string, bunBinDir: string | undefined, options?: UpdateMethodResolutionOptions): UpdateMethod;
|
|
148
|
+
/** Resolve an update target from the concrete PATH entry selected by the shell. */
|
|
149
|
+
export declare function resolveUpdateTargetFromPath(ompPath: string, bunBinDir: string | undefined, options: UpdateMethodResolutionOptions & {
|
|
150
|
+
allowPackageManagers: boolean;
|
|
151
|
+
}): UpdateTarget;
|
|
124
152
|
/**
|
|
125
153
|
* Get the latest release info from the npm registry, following `omp.rename`
|
|
126
154
|
* pointers ({@link resolveReleaseRename}) when the package has moved to a new
|
|
@@ -145,7 +173,13 @@ interface BunInstallCachePruneResult {
|
|
|
145
173
|
* cache stays internally consistent.
|
|
146
174
|
*/
|
|
147
175
|
export declare function pruneBunInstallCache(cacheDir: string, packageNames?: Set<string>): Promise<BunInstallCachePruneResult>;
|
|
148
|
-
|
|
176
|
+
interface BunGlobalInstallLocations {
|
|
177
|
+
globalDir?: string;
|
|
178
|
+
globalBinDir?: string;
|
|
179
|
+
cacheDir?: string;
|
|
180
|
+
}
|
|
181
|
+
/** Resolve Bun's global node_modules root from explicit, default, or cache locations. */
|
|
182
|
+
export declare function resolveBunGlobalNodeModulesDirFromLocations({ globalDir, globalBinDir, cacheDir, }: BunGlobalInstallLocations): string | undefined;
|
|
149
183
|
/**
|
|
150
184
|
* Detect a musl-libc Linux host (Alpine, Void-musl) so self-update replaces a
|
|
151
185
|
* musl binary with the musl release asset instead of the glibc build, which
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/pi-coding-agent",
|
|
4
|
-
"version": "17.3.
|
|
4
|
+
"version": "17.3.2",
|
|
5
5
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
6
6
|
"homepage": "https://omp.sh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -50,18 +50,18 @@
|
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
52
|
"@babel/parser": "^7.29.7",
|
|
53
|
-
"@oh-my-pi/hashline": "17.3.
|
|
54
|
-
"@oh-my-pi/omp-stats": "17.3.
|
|
55
|
-
"@oh-my-pi/omptype": "17.3.
|
|
56
|
-
"@oh-my-pi/pi-agent-core": "17.3.
|
|
57
|
-
"@oh-my-pi/pi-ai": "17.3.
|
|
58
|
-
"@oh-my-pi/pi-catalog": "17.3.
|
|
59
|
-
"@oh-my-pi/pi-mnemopi": "17.3.
|
|
60
|
-
"@oh-my-pi/pi-natives": "17.3.
|
|
61
|
-
"@oh-my-pi/pi-tui": "17.3.
|
|
62
|
-
"@oh-my-pi/pi-utils": "17.3.
|
|
63
|
-
"@oh-my-pi/pi-wire": "17.3.
|
|
64
|
-
"@oh-my-pi/snapcompact": "17.3.
|
|
53
|
+
"@oh-my-pi/hashline": "17.3.2",
|
|
54
|
+
"@oh-my-pi/omp-stats": "17.3.2",
|
|
55
|
+
"@oh-my-pi/omptype": "17.3.2",
|
|
56
|
+
"@oh-my-pi/pi-agent-core": "17.3.2",
|
|
57
|
+
"@oh-my-pi/pi-ai": "17.3.2",
|
|
58
|
+
"@oh-my-pi/pi-catalog": "17.3.2",
|
|
59
|
+
"@oh-my-pi/pi-mnemopi": "17.3.2",
|
|
60
|
+
"@oh-my-pi/pi-natives": "17.3.2",
|
|
61
|
+
"@oh-my-pi/pi-tui": "17.3.2",
|
|
62
|
+
"@oh-my-pi/pi-utils": "17.3.2",
|
|
63
|
+
"@oh-my-pi/pi-wire": "17.3.2",
|
|
64
|
+
"@oh-my-pi/snapcompact": "17.3.2",
|
|
65
65
|
"@opentelemetry/api": "^1.9.1",
|
|
66
66
|
"@opentelemetry/api-logs": "^0.220.0",
|
|
67
67
|
"@opentelemetry/context-async-hooks": "^2.9.0",
|
package/src/cli/update-cli.ts
CHANGED
|
@@ -467,6 +467,27 @@ function isPathInDirectory(filePath: string, directoryPath: string): boolean {
|
|
|
467
467
|
return isPathInDirectoryLexical(resolvedFile, dirReal);
|
|
468
468
|
}
|
|
469
469
|
|
|
470
|
+
function isPathInManagerRoot(linkTarget: string, nodeModulesDir: string): boolean {
|
|
471
|
+
if (isPathInDirectoryLexical(linkTarget, nodeModulesDir)) return true;
|
|
472
|
+
// Resolve only the manager root. Resolving the link target itself would
|
|
473
|
+
// follow globally linked packages into their checkout and lose ownership.
|
|
474
|
+
const nodeModulesReal = tryRealpath(path.resolve(nodeModulesDir));
|
|
475
|
+
return nodeModulesReal !== undefined && isPathInDirectoryLexical(linkTarget, nodeModulesReal);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
function resolveNpmGlobalNodeModulesDir(globalBinDir: string | undefined): string | undefined {
|
|
479
|
+
if (!globalBinDir) return undefined;
|
|
480
|
+
if (process.platform === "win32") return path.join(globalBinDir, "node_modules");
|
|
481
|
+
return path.join(path.dirname(globalBinDir), "lib", "node_modules");
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
function isManagerOwnedBinEntry(linkTarget: string | undefined, nodeModulesDir: string | undefined): boolean {
|
|
485
|
+
// Non-symlink launchers and unreadable links retain the existing bin-dir
|
|
486
|
+
// classification. A readable link must point through the manager's exact
|
|
487
|
+
// global node_modules tree.
|
|
488
|
+
return linkTarget === undefined || (nodeModulesDir !== undefined && isPathInManagerRoot(linkTarget, nodeModulesDir));
|
|
489
|
+
}
|
|
490
|
+
|
|
470
491
|
type UpdateMethod = "brew" | "mise" | "nix" | "bun" | "npm" | "binary";
|
|
471
492
|
|
|
472
493
|
interface UpdateMethodResolutionOptions {
|
|
@@ -474,6 +495,8 @@ interface UpdateMethodResolutionOptions {
|
|
|
474
495
|
miseBinDirs?: readonly string[];
|
|
475
496
|
miseDataDir?: string;
|
|
476
497
|
npmBinDir?: string;
|
|
498
|
+
/** Bun's configured global package directory, independent of its bin directory. */
|
|
499
|
+
bunGlobalDir?: string;
|
|
477
500
|
/**
|
|
478
501
|
* Whether the resolved omp path is a plain file (the standalone binary)
|
|
479
502
|
* rather than a package-manager symlink. Stops a binary install from being
|
|
@@ -481,6 +504,11 @@ interface UpdateMethodResolutionOptions {
|
|
|
481
504
|
* target directory.
|
|
482
505
|
*/
|
|
483
506
|
ompIsRegularFile?: boolean;
|
|
507
|
+
/**
|
|
508
|
+
* Absolute path named by the bin entry's first symlink hop. This deliberately
|
|
509
|
+
* preserves a global package symlink instead of resolving into its checkout.
|
|
510
|
+
*/
|
|
511
|
+
ompLinkTarget?: string;
|
|
484
512
|
}
|
|
485
513
|
|
|
486
514
|
type UpdateTarget =
|
|
@@ -496,7 +524,15 @@ function resolveUpdateMethod(
|
|
|
496
524
|
bunBinDir: string | undefined,
|
|
497
525
|
options: UpdateMethodResolutionOptions = {},
|
|
498
526
|
): UpdateMethod {
|
|
499
|
-
const {
|
|
527
|
+
const {
|
|
528
|
+
bunGlobalDir,
|
|
529
|
+
homebrewPrefix,
|
|
530
|
+
miseBinDirs = [],
|
|
531
|
+
miseDataDir,
|
|
532
|
+
npmBinDir,
|
|
533
|
+
ompIsRegularFile = false,
|
|
534
|
+
ompLinkTarget,
|
|
535
|
+
} = options;
|
|
500
536
|
const launcherExtension = path.extname(ompPath).toLowerCase();
|
|
501
537
|
const isWindowsScriptLauncher =
|
|
502
538
|
launcherExtension === ".cmd" || launcherExtension === ".ps1" || launcherExtension === ".bat";
|
|
@@ -514,9 +550,28 @@ function resolveUpdateMethod(
|
|
|
514
550
|
// (bun's .exe launcher, npm's .cmd/.ps1), so a regular file is NOT evidence
|
|
515
551
|
// of a standalone install and the override would hijack managed installs.
|
|
516
552
|
const isStandaloneRegularFile = ompIsRegularFile && process.platform !== "win32";
|
|
517
|
-
|
|
518
|
-
|
|
553
|
+
const bunNodeModulesDir = resolveBunGlobalNodeModulesDirFromLocations({
|
|
554
|
+
globalDir: bunGlobalDir,
|
|
555
|
+
globalBinDir: bunBinDir,
|
|
556
|
+
});
|
|
557
|
+
if (
|
|
558
|
+
bunBinDir &&
|
|
559
|
+
isPathInDirectory(ompPath, bunBinDir) &&
|
|
560
|
+
!isStandaloneRegularFile &&
|
|
561
|
+
isManagerOwnedBinEntry(ompLinkTarget, bunNodeModulesDir)
|
|
562
|
+
) {
|
|
563
|
+
return "bun";
|
|
564
|
+
}
|
|
565
|
+
const npmNodeModulesDir = resolveNpmGlobalNodeModulesDir(npmBinDir);
|
|
566
|
+
if (
|
|
567
|
+
npmBinDir &&
|
|
568
|
+
isPathInDirectory(ompPath, npmBinDir) &&
|
|
569
|
+
!isStandaloneRegularFile &&
|
|
570
|
+
isManagerOwnedBinEntry(ompLinkTarget, npmNodeModulesDir)
|
|
571
|
+
) {
|
|
519
572
|
return "npm";
|
|
573
|
+
}
|
|
574
|
+
if (isWindowsScriptLauncher) return "npm";
|
|
520
575
|
return "binary";
|
|
521
576
|
}
|
|
522
577
|
|
|
@@ -527,6 +582,44 @@ export function resolveUpdateMethodForTest(
|
|
|
527
582
|
): UpdateMethod {
|
|
528
583
|
return resolveUpdateMethod(ompPath, bunBinDir, options);
|
|
529
584
|
}
|
|
585
|
+
|
|
586
|
+
/** Resolve an update target from the concrete PATH entry selected by the shell. */
|
|
587
|
+
export function resolveUpdateTargetFromPath(
|
|
588
|
+
ompPath: string,
|
|
589
|
+
bunBinDir: string | undefined,
|
|
590
|
+
options: UpdateMethodResolutionOptions & { allowPackageManagers: boolean },
|
|
591
|
+
): UpdateTarget {
|
|
592
|
+
let ompIsRegularFile = false;
|
|
593
|
+
let ompIsSymlink = false;
|
|
594
|
+
let ompLinkTarget: string | undefined;
|
|
595
|
+
let ompRealpath: string | undefined;
|
|
596
|
+
try {
|
|
597
|
+
const stat = fs.lstatSync(ompPath);
|
|
598
|
+
ompIsRegularFile = stat.isFile() && !stat.isSymbolicLink();
|
|
599
|
+
ompIsSymlink = stat.isSymbolicLink();
|
|
600
|
+
if (ompIsSymlink) {
|
|
601
|
+
const rawTarget = fs.readlinkSync(ompPath);
|
|
602
|
+
const linkDir = path.dirname(ompPath);
|
|
603
|
+
ompLinkTarget = path.resolve(tryRealpath(linkDir) ?? linkDir, rawTarget);
|
|
604
|
+
ompRealpath = tryRealpath(ompPath);
|
|
605
|
+
}
|
|
606
|
+
} catch {}
|
|
607
|
+
|
|
608
|
+
const method = resolveUpdateMethod(ompPath, bunBinDir, {
|
|
609
|
+
...options,
|
|
610
|
+
ompIsRegularFile,
|
|
611
|
+
ompLinkTarget,
|
|
612
|
+
});
|
|
613
|
+
if (method === "binary") {
|
|
614
|
+
// A package-manager-enabled update follows a foreign alias to replace
|
|
615
|
+
// its standalone binary. Binary-only releases intentionally replace the
|
|
616
|
+
// selected manager launcher in place.
|
|
617
|
+
const binaryPath = options.allowPackageManagers && ompIsSymlink ? (ompRealpath ?? ompPath) : ompPath;
|
|
618
|
+
return { method, path: binaryPath, replacesSymlink: ompIsSymlink && binaryPath === ompPath };
|
|
619
|
+
}
|
|
620
|
+
if (method === "bun" || method === "npm") return { method, path: ompPath };
|
|
621
|
+
return { method };
|
|
622
|
+
}
|
|
530
623
|
/**
|
|
531
624
|
* Resolve how the running install should be updated.
|
|
532
625
|
*
|
|
@@ -546,27 +639,14 @@ async function resolveUpdateTarget(options: { allowPackageManagers: boolean }):
|
|
|
546
639
|
const ompPath = resolveOmpPath();
|
|
547
640
|
|
|
548
641
|
if (ompPath) {
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
// directory containment — distinguishes a binary install from npm/bun.
|
|
553
|
-
let ompIsRegularFile = false;
|
|
554
|
-
let ompIsSymlink = false;
|
|
555
|
-
try {
|
|
556
|
-
const stat = fs.lstatSync(ompPath);
|
|
557
|
-
ompIsRegularFile = stat.isFile() && !stat.isSymbolicLink();
|
|
558
|
-
ompIsSymlink = stat.isSymbolicLink();
|
|
559
|
-
} catch {}
|
|
560
|
-
const method = resolveUpdateMethod(ompPath, bunBinDir, {
|
|
642
|
+
return resolveUpdateTargetFromPath(ompPath, bunBinDir, {
|
|
643
|
+
allowPackageManagers: options.allowPackageManagers,
|
|
644
|
+
bunGlobalDir: options.allowPackageManagers ? process.env.BUN_INSTALL_GLOBAL_DIR : undefined,
|
|
561
645
|
homebrewPrefix,
|
|
562
646
|
miseBinDirs,
|
|
563
647
|
miseDataDir,
|
|
564
648
|
npmBinDir,
|
|
565
|
-
ompIsRegularFile,
|
|
566
649
|
});
|
|
567
|
-
if (method === "binary") return { method, path: ompPath, replacesSymlink: ompIsSymlink };
|
|
568
|
-
if (method === "bun" || method === "npm") return { method, path: ompPath };
|
|
569
|
-
return { method };
|
|
570
650
|
}
|
|
571
651
|
|
|
572
652
|
if (bunBinDir) return { method: "bun" };
|
|
@@ -795,10 +875,19 @@ async function resolveBunInstallCacheDir(): Promise<string | undefined> {
|
|
|
795
875
|
}
|
|
796
876
|
}
|
|
797
877
|
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
878
|
+
interface BunGlobalInstallLocations {
|
|
879
|
+
globalDir?: string;
|
|
880
|
+
globalBinDir?: string;
|
|
881
|
+
cacheDir?: string;
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
/** Resolve Bun's global node_modules root from explicit, default, or cache locations. */
|
|
885
|
+
export function resolveBunGlobalNodeModulesDirFromLocations({
|
|
886
|
+
globalDir,
|
|
887
|
+
globalBinDir,
|
|
888
|
+
cacheDir,
|
|
889
|
+
}: BunGlobalInstallLocations): string | undefined {
|
|
890
|
+
if (globalDir && globalDir.length > 0) return path.join(globalDir, "node_modules");
|
|
802
891
|
if (globalBinDir && globalBinDir.length > 0) {
|
|
803
892
|
return path.join(path.dirname(globalBinDir), "install", "global", "node_modules");
|
|
804
893
|
}
|
|
@@ -812,9 +901,16 @@ async function resolveBunGlobalNodeModulesDir(cacheDir: string): Promise<string
|
|
|
812
901
|
try {
|
|
813
902
|
const result = await $`bun pm bin -g`.quiet().nothrow();
|
|
814
903
|
const globalBinDir = result.exitCode === 0 ? result.text().trim() : undefined;
|
|
815
|
-
return resolveBunGlobalNodeModulesDirFromLocations(
|
|
904
|
+
return resolveBunGlobalNodeModulesDirFromLocations({
|
|
905
|
+
globalDir: process.env.BUN_INSTALL_GLOBAL_DIR,
|
|
906
|
+
globalBinDir,
|
|
907
|
+
cacheDir,
|
|
908
|
+
});
|
|
816
909
|
} catch {
|
|
817
|
-
return resolveBunGlobalNodeModulesDirFromLocations(
|
|
910
|
+
return resolveBunGlobalNodeModulesDirFromLocations({
|
|
911
|
+
globalDir: process.env.BUN_INSTALL_GLOBAL_DIR,
|
|
912
|
+
cacheDir,
|
|
913
|
+
});
|
|
818
914
|
}
|
|
819
915
|
}
|
|
820
916
|
|
|
@@ -37,6 +37,7 @@ import {
|
|
|
37
37
|
type AsideMessage,
|
|
38
38
|
type BeforeToolCallContext,
|
|
39
39
|
type BeforeToolCallResult,
|
|
40
|
+
EventLoopKeepalive,
|
|
40
41
|
resolveTelemetry,
|
|
41
42
|
type StreamFn,
|
|
42
43
|
TERMINAL_TOOL_RESULT_ABORT_REASON,
|
|
@@ -1213,15 +1214,28 @@ export class AgentSession {
|
|
|
1213
1214
|
}
|
|
1214
1215
|
},
|
|
1215
1216
|
scheduleIdleFlush: run => {
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1217
|
+
const keepalive = new EventLoopKeepalive();
|
|
1218
|
+
try {
|
|
1219
|
+
this.#schedulePostPromptTask(
|
|
1220
|
+
async () => {
|
|
1221
|
+
try {
|
|
1222
|
+
await run();
|
|
1223
|
+
} finally {
|
|
1224
|
+
keepalive[Symbol.dispose]();
|
|
1225
|
+
}
|
|
1226
|
+
},
|
|
1227
|
+
{
|
|
1228
|
+
delayMs: 1,
|
|
1229
|
+
onSkip: () => {
|
|
1230
|
+
keepalive[Symbol.dispose]();
|
|
1231
|
+
this.yieldQueue.cancelIdleFlushScheduling();
|
|
1232
|
+
},
|
|
1233
|
+
},
|
|
1234
|
+
);
|
|
1235
|
+
} catch (error) {
|
|
1236
|
+
keepalive[Symbol.dispose]();
|
|
1237
|
+
throw error;
|
|
1238
|
+
}
|
|
1225
1239
|
},
|
|
1226
1240
|
});
|
|
1227
1241
|
this.yieldQueue.register<LaunchCompletionEntry>(LAUNCH_COMPLETION_MESSAGE_TYPE, {
|
package/src/task/executor.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import path from "node:path";
|
|
8
8
|
import type { AgentEvent, AgentIdentity, AgentMessage, AgentTelemetryConfig } from "@oh-my-pi/pi-agent-core";
|
|
9
|
-
import { recordHandoff, resolveTelemetry } from "@oh-my-pi/pi-agent-core";
|
|
9
|
+
import { EventLoopKeepalive, recordHandoff, resolveTelemetry } from "@oh-my-pi/pi-agent-core";
|
|
10
10
|
import type { Api, Model, ServiceTierByFamily, Usage } from "@oh-my-pi/pi-ai";
|
|
11
11
|
import { logger, popLoopPhase, prompt, pushLoopPhase, untilAborted } from "@oh-my-pi/pi-utils";
|
|
12
12
|
import { ASYNC_JOB_MANAGER_SHUTDOWN_REASON, AsyncJobManager } from "../async";
|
|
@@ -1868,6 +1868,7 @@ async function driveSessionToYield(
|
|
|
1868
1868
|
monitor: SubagentRunMonitor,
|
|
1869
1869
|
task: string,
|
|
1870
1870
|
): Promise<DriveOutcome> {
|
|
1871
|
+
using _keepalive = new EventLoopKeepalive();
|
|
1871
1872
|
const abortSignal = monitor.abortSignal;
|
|
1872
1873
|
let exitCode = 0;
|
|
1873
1874
|
let error: string | undefined;
|
package/src/tools/read-format.ts
CHANGED
|
@@ -37,16 +37,17 @@ export interface HashlineHeaderContext {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
export function formatReadHashlineHeader(displayPath: string, tag: string): string {
|
|
40
|
-
// In-workspace reads
|
|
41
|
-
//
|
|
42
|
-
//
|
|
43
|
-
//
|
|
44
|
-
//
|
|
45
|
-
//
|
|
46
|
-
//
|
|
47
|
-
//
|
|
48
|
-
//
|
|
49
|
-
|
|
40
|
+
// In-workspace reads keep their workspace-relative path (e.g.
|
|
41
|
+
// `src/settings.json`), not just the basename: collapsing to the bare name
|
|
42
|
+
// made a header ambiguous whenever another same-named file exists at cwd —
|
|
43
|
+
// the edit tool would resolve the bare name against cwd, hit the wrong
|
|
44
|
+
// file, and reject the valid edit via the snapshot-tag guard (the authored
|
|
45
|
+
// path exists, so Patcher's tag-path recovery never runs). The relative
|
|
46
|
+
// path stays directly resolvable against cwd and names the file uniquely.
|
|
47
|
+
// Out-of-workspace reads use an absolute displayPath; `shortenPath` keeps
|
|
48
|
+
// `~/.claude/...` (round-trips through resolveToCwd's ~ expansion) instead
|
|
49
|
+
// of leaking the full home path into the read output.
|
|
50
|
+
const anchor = path.isAbsolute(displayPath) ? shortenPath(displayPath) : displayPath;
|
|
50
51
|
return formatHashlineHeader(anchor, tag);
|
|
51
52
|
}
|
|
52
53
|
|
package/src/tools/run-scope.ts
CHANGED
|
@@ -38,7 +38,7 @@ interface ObservedPromiseState {
|
|
|
38
38
|
const observedBrowserPromises = new WeakMap<Promise<unknown>, ObservedPromiseState>();
|
|
39
39
|
const observedPromiseConstructor = { [Symbol.species]: Promise };
|
|
40
40
|
|
|
41
|
-
type PromiseCombinatorName = "all" | "race";
|
|
41
|
+
type PromiseCombinatorName = "all" | "race" | "allSettled" | "any";
|
|
42
42
|
type PromiseCombinator = (this: PromiseConstructor, values: Iterable<unknown>) => Promise<unknown>;
|
|
43
43
|
|
|
44
44
|
interface PromiseCombinatorTrackingContext {
|
|
@@ -46,11 +46,13 @@ interface PromiseCombinatorTrackingContext {
|
|
|
46
46
|
onFloatingRejection: FloatingRejectionHandler;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
const PROMISE_COMBINATORS: readonly PromiseCombinatorName[] = ["all", "race"];
|
|
49
|
+
const PROMISE_COMBINATORS: readonly PromiseCombinatorName[] = ["all", "race", "allSettled", "any"];
|
|
50
50
|
const NativePromise = Promise;
|
|
51
51
|
const nativePromiseCombinators: Record<PromiseCombinatorName, PromiseCombinator> = {
|
|
52
52
|
all: Promise.all,
|
|
53
53
|
race: Promise.race,
|
|
54
|
+
allSettled: Promise.allSettled,
|
|
55
|
+
any: Promise.any,
|
|
54
56
|
};
|
|
55
57
|
const promiseCombinatorTracking = new AsyncLocalStorage<PromiseCombinatorTrackingContext>();
|
|
56
58
|
let previousPromiseDescriptor: PropertyDescriptor | undefined;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Utilities for launching an external text editor ($VISUAL / $EDITOR).
|
|
3
3
|
*/
|
|
4
|
-
import { spawn } from "node:child_process";
|
|
5
4
|
import * as fs from "node:fs/promises";
|
|
6
5
|
import * as os from "node:os";
|
|
7
6
|
import * as path from "node:path";
|
|
@@ -51,17 +50,17 @@ export async function openInEditor(
|
|
|
51
50
|
try {
|
|
52
51
|
await Bun.write(tmpFile, content);
|
|
53
52
|
|
|
54
|
-
const [
|
|
55
|
-
const
|
|
56
|
-
const child =
|
|
53
|
+
const [stdin, stdout, stderr] = options?.stdio ?? ["inherit", "inherit", "inherit"];
|
|
54
|
+
const cmd =
|
|
57
55
|
process.platform === "win32"
|
|
58
|
-
?
|
|
59
|
-
:
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
56
|
+
? ["cmd", "/c", `${editorCmd} "${tmpFile}"`]
|
|
57
|
+
: [$which("sh") ?? "sh", "-c", `${editorCmd} "$1"`, "sh", tmpFile];
|
|
58
|
+
const child = Bun.spawn(cmd, {
|
|
59
|
+
stdin,
|
|
60
|
+
stdout,
|
|
61
|
+
stderr,
|
|
62
|
+
});
|
|
63
|
+
const exitCode = await child.exited;
|
|
65
64
|
if (exitCode === 0) {
|
|
66
65
|
const text = await Bun.file(tmpFile).text();
|
|
67
66
|
if (options?.trimTrailingNewline === false) {
|
|
@@ -9,11 +9,7 @@
|
|
|
9
9
|
* endpoint.
|
|
10
10
|
*/
|
|
11
11
|
import { type AuthStorage, type FetchImpl, type OAuthAccess, withOAuthAccess } from "@oh-my-pi/pi-ai";
|
|
12
|
-
import {
|
|
13
|
-
ANTIGRAVITY_SYSTEM_INSTRUCTION,
|
|
14
|
-
getAntigravityUserAgent,
|
|
15
|
-
getGeminiCliHeaders,
|
|
16
|
-
} from "@oh-my-pi/pi-catalog/wire/gemini-headers";
|
|
12
|
+
import { getAntigravityUserAgent, getGeminiCliHeaders } from "@oh-my-pi/pi-catalog/wire/gemini-headers";
|
|
17
13
|
import { fetchWithRetry, USER_AGENT } from "@oh-my-pi/pi-utils";
|
|
18
14
|
|
|
19
15
|
import type { SearchCitation, SearchResponse, SearchSource } from "../../../web/search/types";
|
|
@@ -441,10 +437,9 @@ async function callGeminiSearch(
|
|
|
441
437
|
};
|
|
442
438
|
|
|
443
439
|
const normalizedSystemPrompt = systemPrompt?.toWellFormed();
|
|
444
|
-
const systemInstructionParts: Array<{ text: string }> =
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
];
|
|
440
|
+
const systemInstructionParts: Array<{ text: string }> = normalizedSystemPrompt
|
|
441
|
+
? [{ text: normalizedSystemPrompt }]
|
|
442
|
+
: [];
|
|
448
443
|
|
|
449
444
|
const requestBody: Record<string, unknown> = {
|
|
450
445
|
project: auth.projectId,
|