pi-orchestrator-config 4.2.0 → 4.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/README.md +76 -67
- package/agents/code-reviewer-docs.md +11 -1
- package/agents/code-reviewer-guidelines.md +11 -1
- package/agents/code-reviewer-quality.md +11 -1
- package/agents/code-reviewer-security.md +11 -1
- package/agents/code-reviewer-spec.md +11 -1
- package/agents/git-expert.md +42 -3
- package/agents/github-expert.md +11 -0
- package/extensions/acpx-provider/runtime-models.ts +18 -6
- package/extensions/cli-provider/agents/claude.ts +3 -2
- package/extensions/cli-provider/agents/cursor.ts +3 -5
- package/extensions/cli-provider/agents/gemini.ts +3 -2
- package/extensions/cli-provider/discover.ts +7 -7
- package/extensions/cli-provider/index.ts +5 -0
- package/extensions/cli-provider/runtime-models.ts +18 -6
- package/extensions/cli-provider/session-reaper.ts +5 -7
- package/extensions/cli-provider/sessions.ts +4 -0
- package/extensions/cli-provider/shared/discover-cache.ts +17 -176
- package/extensions/coms/coms-p2p.ts +1719 -423
- package/extensions/coms/coms-shared.ts +261 -39
- package/extensions/coms/coms-wrapper.ts +100 -62
- package/extensions/coms/index.ts +8 -4
- package/extensions/coms/mixed-turn.ts +26 -0
- package/extensions/coms/probe-socket.ts +42 -0
- package/extensions/coms/themeMap.ts +0 -1
- package/extensions/image-gen/image-gen.ts +19 -1
- package/extensions/orchestrator/async-agents.ts +563 -102
- package/extensions/orchestrator/async-capability.ts +8 -8
- package/extensions/orchestrator/cron.ts +15 -9
- package/extensions/orchestrator/dreaming.ts +32 -25
- package/extensions/orchestrator/enforcement-helpers.ts +459 -17
- package/extensions/orchestrator/enforcement-rules.ts +5 -4
- package/extensions/orchestrator/enforcement.ts +80 -27
- package/extensions/orchestrator/extended-autocomplete.ts +7 -0
- package/extensions/orchestrator/git-helpers.ts +2 -2
- package/extensions/orchestrator/index.ts +78 -10
- package/extensions/orchestrator/markdown-transformer.ts +313 -0
- package/extensions/orchestrator/memory-embeddings.ts +36 -34
- package/extensions/orchestrator/memory-provenance.ts +29 -25
- package/extensions/orchestrator/memory-scoring.ts +23 -18
- package/extensions/orchestrator/memory-tools.ts +10 -3
- package/extensions/orchestrator/overlay-dashboard.ts +17 -5
- package/extensions/orchestrator/parse-model-override.ts +29 -0
- package/extensions/orchestrator/pi-config-review-state.ts +57 -33
- package/extensions/orchestrator/project-settings.ts +333 -127
- package/extensions/orchestrator/resolve-agent-model.ts +24 -13
- package/extensions/orchestrator/review-porcelain.ts +4 -0
- package/extensions/orchestrator/review-ui.ts +63 -15
- package/extensions/orchestrator/rule-placeholders.ts +411 -2
- package/extensions/orchestrator/rules.ts +80 -132
- package/extensions/orchestrator/settings-tui-helpers.ts +380 -0
- package/extensions/orchestrator/settings-tui-submenus.ts +647 -0
- package/extensions/orchestrator/settings-tui.ts +636 -0
- package/extensions/orchestrator/state-jsonl.ts +431 -0
- package/extensions/orchestrator/subagent-tool.ts +157 -59
- package/extensions/orchestrator/sync-limit.ts +23 -0
- package/extensions/orchestrator/task-lifecycle.ts +77 -67
- package/extensions/orchestrator/utils.ts +8 -5
- package/extensions/pidash/pidash.ts +193 -156
- package/extensions/pidiff/pidiff.ts +96 -38
- package/extensions/pidiff/spawn-lock.ts +62 -0
- package/extensions/pitasks/index.ts +430 -0
- package/extensions/pitasks/reminders.ts +37 -0
- package/extensions/pitasks/task-store.ts +467 -0
- package/extensions/pitasks/task-tools.ts +375 -0
- package/extensions/pitasks/task-widget.ts +181 -0
- package/extensions/pitasks/types.ts +38 -0
- package/extensions/providers/acpx-driver.ts +12 -2
- package/extensions/providers/built-in-drivers.ts +6 -6
- package/extensions/providers/claude-driver.ts +1 -1
- package/extensions/providers/cursor-cli-driver.ts +1 -1
- package/extensions/providers/gemini-driver.ts +1 -1
- package/extensions/providers/index.ts +144 -26
- package/extensions/providers/initialized-guard.ts +27 -0
- package/extensions/providers/restore-default-model.ts +596 -0
- package/extensions/providers/session-shutdown.ts +39 -0
- package/extensions/shared/coms-active.ts +23 -0
- package/extensions/shared/create-runtime-provider.ts +2 -0
- package/extensions/shared/daemon-manager.ts +0 -8
- package/extensions/shared/file-logger.ts +132 -25
- package/extensions/shared/logger.ts +50 -0
- package/extensions/shared/models-dev.ts +421 -0
- package/extensions/shared/oneshot.ts +116 -0
- package/extensions/shared/resolve-binary.ts +191 -0
- package/extensions/shared/types.ts +3 -0
- package/package.json +9 -3
- package/prompts/coderabbit-rate-limit.md +2 -0
- package/rules/00-orchestrator-core.md +3 -0
- package/rules/10-agent-routing.md +12 -1
- package/rules/20-code-review-loop.md +52 -25
- package/rules/30-prompt-templates.md +4 -0
- package/rules/35-memory.md +3 -3
- package/rules/40-critical-rules.md +3 -0
- package/rules/55-coms-protocol.md +84 -18
- package/rules/60-task-tracking.md +2 -0
- package/settings-keys.json +563 -0
- package/templates/coms-feature-manager-prompt.md +4 -6
- package/extensions/coms/coms-net-server.ts +0 -1642
- package/extensions/coms/coms-net-wrapper.ts +0 -521
- package/extensions/coms/coms-net.ts +0 -1589
|
@@ -5,11 +5,13 @@
|
|
|
5
5
|
* IMPORTANT: These IDs are CLI `--model` values, NOT acpx model ids.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import {
|
|
8
|
+
import { createLogger } from "../shared/logger.js";
|
|
9
9
|
import { CLI_PROVIDERS, isCliAgentName, type CliAgentName } from "./providers.js";
|
|
10
10
|
import type { DiscoveredCliModel } from "./types.js";
|
|
11
11
|
import { modelIdToDisplayName, resolveBinary } from "./shared/discover-cache.js";
|
|
12
12
|
|
|
13
|
+
const log = createLogger("cli_provider");
|
|
14
|
+
|
|
13
15
|
export type { DiscoveredCliModel } from "./types.js";
|
|
14
16
|
export { modelIdToDisplayName } from "./shared/discover-cache.js";
|
|
15
17
|
export { parseAgentListModels } from "./agents/cursor.js";
|
|
@@ -33,9 +35,7 @@ export async function discoverCliModelsDetailed(
|
|
|
33
35
|
): Promise<DiscoveredCliModel[]> {
|
|
34
36
|
if (!isCliAgentName(agent)) return [];
|
|
35
37
|
if (!isCliBinaryAvailable(agent)) {
|
|
36
|
-
|
|
37
|
-
"warn",
|
|
38
|
-
`${agent}: binary not found (${CLI_PROVIDERS[agent].binary})`,
|
|
38
|
+
log.warn(`${agent}: binary not found (${CLI_PROVIDERS[agent].binary})`,
|
|
39
39
|
);
|
|
40
40
|
return [];
|
|
41
41
|
}
|
|
@@ -44,13 +44,13 @@ export async function discoverCliModelsDetailed(
|
|
|
44
44
|
try {
|
|
45
45
|
discovered = CLI_PROVIDERS[agent].discoverModels();
|
|
46
46
|
} catch (err) {
|
|
47
|
-
|
|
47
|
+
log.error(`${agent}: discovery error`, err);
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
if (discovered.length > 0) {
|
|
51
|
-
|
|
51
|
+
log.info(`${agent}: discovered ${discovered.length} model(s)`);
|
|
52
52
|
} else {
|
|
53
|
-
|
|
53
|
+
log.warn(`${agent}: discovery returned no models`);
|
|
54
54
|
}
|
|
55
55
|
return discovered;
|
|
56
56
|
}
|
|
@@ -14,6 +14,11 @@
|
|
|
14
14
|
* @module cli-provider (shim)
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
+
import { createLogger } from "../shared/logger.js";
|
|
18
|
+
|
|
19
|
+
const log = createLogger("cli_provider");
|
|
20
|
+
log.debug("cli-provider shim module loaded");
|
|
21
|
+
|
|
17
22
|
// Re-export discovery APIs (consumed by pi-sidecar via jiti)
|
|
18
23
|
export {
|
|
19
24
|
discoverCliModels,
|
|
@@ -4,11 +4,16 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { buildRuntimeModel } from "../shared/create-runtime-provider.js";
|
|
7
|
+
import {
|
|
8
|
+
fillRuntimeModelFromCatalog,
|
|
9
|
+
type ModelsDevCatalog,
|
|
10
|
+
} from "../shared/models-dev.js";
|
|
7
11
|
import type { DiscoveredCliModel } from "./discover.js";
|
|
8
12
|
|
|
9
13
|
export function mapCliDiscoveredModels(
|
|
10
14
|
agent: string,
|
|
11
15
|
discovered: readonly DiscoveredCliModel[],
|
|
16
|
+
catalog?: ModelsDevCatalog | null,
|
|
12
17
|
): ReturnType<typeof buildRuntimeModel>[] {
|
|
13
18
|
const provider = `cli-${agent}`;
|
|
14
19
|
if (discovered.length === 0) {
|
|
@@ -22,11 +27,18 @@ export function mapCliDiscoveredModels(
|
|
|
22
27
|
];
|
|
23
28
|
}
|
|
24
29
|
return discovered.map((m) =>
|
|
25
|
-
buildRuntimeModel(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
buildRuntimeModel(
|
|
31
|
+
fillRuntimeModelFromCatalog(
|
|
32
|
+
{
|
|
33
|
+
id: `${agent}:${m.id}`,
|
|
34
|
+
name: `${m.name} (${agent})`,
|
|
35
|
+
api: "cli",
|
|
36
|
+
provider,
|
|
37
|
+
},
|
|
38
|
+
catalog,
|
|
39
|
+
agent,
|
|
40
|
+
m.id,
|
|
41
|
+
),
|
|
42
|
+
),
|
|
31
43
|
);
|
|
32
44
|
}
|
|
@@ -5,9 +5,11 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { unlinkSync } from "node:fs";
|
|
8
|
-
import {
|
|
8
|
+
import { createLogger } from "../shared/logger.js";
|
|
9
9
|
import { listCliSessions } from "./sessions.js";
|
|
10
10
|
|
|
11
|
+
const log = createLogger("cli_provider");
|
|
12
|
+
|
|
11
13
|
export const DEFAULT_INACTIVITY_THRESHOLD_MS = 30 * 60 * 1000;
|
|
12
14
|
export const DEFAULT_SWEEP_INTERVAL_MS = 5 * 60 * 1000;
|
|
13
15
|
|
|
@@ -51,16 +53,12 @@ export function reapStaleCliSessions(options?: ReapOptions): number {
|
|
|
51
53
|
try {
|
|
52
54
|
unlinkSync(path);
|
|
53
55
|
reaped += 1;
|
|
54
|
-
|
|
55
|
-
"info",
|
|
56
|
-
`reaped session ${record.agent}/${record.model} ` +
|
|
56
|
+
log.info(`reaped session ${record.agent}/${record.model} ` +
|
|
57
57
|
`(status=${record.status}, piSessionId=${record.piSessionId}, ` +
|
|
58
58
|
`lastSeen=${record.lastSeenAt})`,
|
|
59
59
|
);
|
|
60
60
|
} catch (err) {
|
|
61
|
-
|
|
62
|
-
"error",
|
|
63
|
-
`failed to reap session ${record.agent}/${record.model} at ${path}`,
|
|
61
|
+
log.error(`failed to reap session ${record.agent}/${record.model} at ${path}`,
|
|
64
62
|
err,
|
|
65
63
|
);
|
|
66
64
|
}
|
|
@@ -11,11 +11,15 @@ import {
|
|
|
11
11
|
unlinkSync,
|
|
12
12
|
writeFileSync,
|
|
13
13
|
} from "node:fs";
|
|
14
|
+
import { createLogger } from "../shared/logger.js";
|
|
14
15
|
import { join } from "node:path";
|
|
15
16
|
import { homedir } from "node:os";
|
|
16
17
|
import { createHash, randomUUID } from "node:crypto";
|
|
17
18
|
import type { CliSessionKey, CliSessionRecord } from "./types.js";
|
|
18
19
|
|
|
20
|
+
const sessionLog = createLogger("cli_provider");
|
|
21
|
+
sessionLog.debug("cli-provider sessions module loaded");
|
|
22
|
+
|
|
19
23
|
export type { CliSessionKey, CliSessionRecord } from "./types.js";
|
|
20
24
|
|
|
21
25
|
/** Prefix for per-process ids used before the real pi session UUID is known. */
|
|
@@ -1,22 +1,35 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared helpers for CLI model discovery (cache + binary resolve).
|
|
3
|
+
*
|
|
4
|
+
* Binary resolution functions have been moved to `extensions/shared/resolve-binary.ts`
|
|
5
|
+
* and are re-exported here for backward compatibility with existing cli-provider consumers.
|
|
3
6
|
*/
|
|
4
7
|
|
|
5
8
|
import {
|
|
6
|
-
accessSync,
|
|
7
|
-
constants,
|
|
8
9
|
existsSync,
|
|
9
10
|
mkdirSync,
|
|
10
11
|
readFileSync,
|
|
11
|
-
realpathSync,
|
|
12
12
|
statSync,
|
|
13
13
|
writeFileSync,
|
|
14
14
|
} from "node:fs";
|
|
15
|
-
import {
|
|
15
|
+
import { join } from "node:path";
|
|
16
16
|
import { homedir } from "node:os";
|
|
17
17
|
import { createHash } from "node:crypto";
|
|
18
18
|
import type { DiscoveredCliModel } from "../types.js";
|
|
19
19
|
|
|
20
|
+
// Re-export binary resolution from shared location
|
|
21
|
+
export {
|
|
22
|
+
resolveBinary,
|
|
23
|
+
resolveBinaryForPlatform,
|
|
24
|
+
clearResolveBinaryCache,
|
|
25
|
+
parsePathext,
|
|
26
|
+
isLaunchableWin32,
|
|
27
|
+
candidateSuffixesFor,
|
|
28
|
+
pathDelimiterFor,
|
|
29
|
+
isExecutableForPlatform,
|
|
30
|
+
type ResolveBinaryEnv,
|
|
31
|
+
} from "../../shared/resolve-binary.js";
|
|
32
|
+
|
|
20
33
|
export function modelIdToDisplayName(modelId: string): string {
|
|
21
34
|
const bracketIdx = modelId.indexOf("[");
|
|
22
35
|
const baseName = bracketIdx >= 0 ? modelId.substring(0, bracketIdx) : modelId;
|
|
@@ -25,178 +38,6 @@ export function modelIdToDisplayName(modelId: string): string {
|
|
|
25
38
|
.replace(/\b\w/g, (c) => c.toUpperCase());
|
|
26
39
|
}
|
|
27
40
|
|
|
28
|
-
/** Cache keyed by `${platform}\0${binary}\0${PATH}\0${PATHEXT}` — successful resolves only. */
|
|
29
|
-
const resolveBinaryCache = new Map<string, string>();
|
|
30
|
-
|
|
31
|
-
export type ResolveBinaryEnv = {
|
|
32
|
-
PATH?: string;
|
|
33
|
-
PATHEXT?: string;
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
/** Parse PATHEXT into uppercase extensions (e.g. ".EXE"). Exported for tests. */
|
|
37
|
-
export function parsePathext(pathextEnv?: string): string[] {
|
|
38
|
-
const raw = pathextEnv ?? process.env.PATHEXT ?? ".EXE;.CMD;.BAT;.COM";
|
|
39
|
-
return raw
|
|
40
|
-
.split(";")
|
|
41
|
-
.map((s) => s.trim())
|
|
42
|
-
.filter(Boolean)
|
|
43
|
-
.map((s) => (s.startsWith(".") ? s : `.${s}`).toUpperCase());
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* True when filePath has an extension listed in PATHEXT (case-insensitive).
|
|
48
|
-
* Extensionless files are not CreateProcess-launchable on Windows.
|
|
49
|
-
*/
|
|
50
|
-
export function isLaunchableWin32(
|
|
51
|
-
filePath: string,
|
|
52
|
-
pathextEnv?: string,
|
|
53
|
-
): boolean {
|
|
54
|
-
const ext = extname(filePath);
|
|
55
|
-
if (!ext) return false;
|
|
56
|
-
return parsePathext(pathextEnv).includes(ext.toUpperCase());
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Suffixes to try when scanning PATH for `binary`.
|
|
61
|
-
* On win32: if `binary` already has a PATHEXT extension, try as-is only;
|
|
62
|
-
* otherwise try each PATHEXT suffix (no bare/empty suffix).
|
|
63
|
-
*/
|
|
64
|
-
export function candidateSuffixesFor(
|
|
65
|
-
binary: string,
|
|
66
|
-
platform: NodeJS.Platform = process.platform,
|
|
67
|
-
pathextEnv?: string,
|
|
68
|
-
): string[] {
|
|
69
|
-
if (platform !== "win32") return [""];
|
|
70
|
-
const ext = extname(binary);
|
|
71
|
-
if (ext && parsePathext(pathextEnv).includes(ext.toUpperCase())) {
|
|
72
|
-
return [""];
|
|
73
|
-
}
|
|
74
|
-
return parsePathext(pathextEnv);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* PATH list separator for the *resolved* platform (not the host OS).
|
|
79
|
-
* Needed so win32 simulation on Unix splits semicolon-separated PATH correctly.
|
|
80
|
-
*/
|
|
81
|
-
export function pathDelimiterFor(platform: NodeJS.Platform): string {
|
|
82
|
-
return platform === "win32" ? win32.delimiter : posix.delimiter;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/** Exported for tests — regular file + platform launchability rules. */
|
|
86
|
-
export function isExecutableForPlatform(
|
|
87
|
-
filePath: string,
|
|
88
|
-
platform: NodeJS.Platform,
|
|
89
|
-
pathextEnv?: string,
|
|
90
|
-
): boolean {
|
|
91
|
-
let st;
|
|
92
|
-
try {
|
|
93
|
-
st = statSync(filePath);
|
|
94
|
-
} catch {
|
|
95
|
-
return false;
|
|
96
|
-
}
|
|
97
|
-
// Directories are often X_OK (searchable); only regular files are binaries.
|
|
98
|
-
if (!st.isFile()) return false;
|
|
99
|
-
// Win32: never treat any regular file as executable — require PATHEXT.
|
|
100
|
-
if (platform === "win32") return isLaunchableWin32(filePath, pathextEnv);
|
|
101
|
-
try {
|
|
102
|
-
accessSync(filePath, constants.X_OK);
|
|
103
|
-
return true;
|
|
104
|
-
} catch {
|
|
105
|
-
return false;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function finalizeResolved(filePath: string): string {
|
|
110
|
-
try {
|
|
111
|
-
return realpathSync(filePath);
|
|
112
|
-
} catch {
|
|
113
|
-
return filePath;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function cacheKeyFor(
|
|
118
|
-
binary: string,
|
|
119
|
-
platform: NodeJS.Platform,
|
|
120
|
-
pathEnv: string,
|
|
121
|
-
pathextEnv: string,
|
|
122
|
-
): string {
|
|
123
|
-
return `${platform}\0${binary}\0${pathEnv}\0${pathextEnv}`;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Resolve a binary for an explicit platform (injectable for win32 tests on Unix).
|
|
128
|
-
* Absolute paths still require a launchable PATHEXT extension on win32.
|
|
129
|
-
*/
|
|
130
|
-
export function resolveBinaryForPlatform(
|
|
131
|
-
binary: string,
|
|
132
|
-
platform: NodeJS.Platform,
|
|
133
|
-
env: ResolveBinaryEnv = {},
|
|
134
|
-
): string | null {
|
|
135
|
-
if (!binary) return null;
|
|
136
|
-
|
|
137
|
-
const pathEnv = env.PATH ?? process.env.PATH ?? "";
|
|
138
|
-
const pathextEnv =
|
|
139
|
-
env.PATHEXT ?? process.env.PATHEXT ?? ".EXE;.CMD;.BAT;.COM";
|
|
140
|
-
const cacheKey = cacheKeyFor(binary, platform, pathEnv, pathextEnv);
|
|
141
|
-
const cached = resolveBinaryCache.get(cacheKey);
|
|
142
|
-
if (cached !== undefined) {
|
|
143
|
-
if (isExecutableForPlatform(cached, platform, pathextEnv)) return cached;
|
|
144
|
-
resolveBinaryCache.delete(cacheKey);
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
const isExec = (p: string) =>
|
|
148
|
-
isExecutableForPlatform(p, platform, pathextEnv);
|
|
149
|
-
|
|
150
|
-
// Absolute or explicit relative path — check directly (mirrors `which /path`).
|
|
151
|
-
if (isAbsolute(binary) || binary.includes("/") || binary.includes("\\")) {
|
|
152
|
-
if (!isExec(binary)) return null;
|
|
153
|
-
const resolved = finalizeResolved(binary);
|
|
154
|
-
resolveBinaryCache.set(cacheKey, resolved);
|
|
155
|
-
return resolved;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const suffixes = candidateSuffixesFor(binary, platform, pathextEnv);
|
|
159
|
-
const envDelimiter = pathDelimiterFor(platform);
|
|
160
|
-
for (const dir of pathEnv.split(envDelimiter)) {
|
|
161
|
-
if (!dir) continue;
|
|
162
|
-
for (const suffix of suffixes) {
|
|
163
|
-
// PATHEXT is typically uppercase; Windows FS is case-insensitive.
|
|
164
|
-
// On case-sensitive hosts (win32 simulation in tests), also try lowercase.
|
|
165
|
-
const variants =
|
|
166
|
-
platform === "win32" && suffix && suffix !== suffix.toLowerCase()
|
|
167
|
-
? [binary + suffix, binary + suffix.toLowerCase()]
|
|
168
|
-
: [binary + suffix];
|
|
169
|
-
for (const name of variants) {
|
|
170
|
-
const candidate = join(dir, name);
|
|
171
|
-
if (!isExec(candidate)) continue;
|
|
172
|
-
const resolved = finalizeResolved(candidate);
|
|
173
|
-
resolveBinaryCache.set(cacheKey, resolved);
|
|
174
|
-
return resolved;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
// Do not cache misses — mid-session install with same PATH must rediscover.
|
|
180
|
-
return null;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* Resolve a binary name (or absolute path) via an in-process PATH scan.
|
|
185
|
-
* Avoids spawnSync("which") on auth/filter hot paths.
|
|
186
|
-
* Returns realpath when possible, null if missing.
|
|
187
|
-
*/
|
|
188
|
-
export function resolveBinary(binary: string): string | null {
|
|
189
|
-
return resolveBinaryForPlatform(binary, process.platform, {
|
|
190
|
-
PATH: process.env.PATH,
|
|
191
|
-
PATHEXT: process.env.PATHEXT,
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
/** Clear PATH resolve cache (tests / PATH mutation). */
|
|
196
|
-
export function clearResolveBinaryCache(): void {
|
|
197
|
-
resolveBinaryCache.clear();
|
|
198
|
-
}
|
|
199
|
-
|
|
200
41
|
function cacheDir(): string {
|
|
201
42
|
return join(homedir(), ".pi", "cli-model-cache");
|
|
202
43
|
}
|