my-pi 0.1.88 → 0.1.90
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 +11 -0
- package/dist/api.d.ts +26 -6
- package/dist/api.js +166 -328
- package/dist/api.js.map +1 -1
- package/dist/{builtin-registry-C7hkBDoD.js → builtin-registry-CYdEeqrp.js} +15 -2
- package/dist/builtin-registry-CYdEeqrp.js.map +1 -0
- package/dist/hooks-resolution-Ct3OPm5A.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/openrouter-fusion-config-D92_sO0Y.js +65 -0
- package/dist/openrouter-fusion-config-D92_sO0Y.js.map +1 -0
- package/dist/prompt-presets-BlCoIFYT.js.map +1 -1
- package/dist/{session-name-9TQGDvFX.js → session-name-arDf91uJ.js} +2 -2
- package/dist/{session-name-9TQGDvFX.js.map → session-name-arDf91uJ.js.map} +1 -1
- package/dist/settings-CTk0ws43.js +175 -0
- package/dist/settings-CTk0ws43.js.map +1 -0
- package/dist/startup-screen-DUeBWuAc.js.map +1 -1
- package/package.json +14 -14
- package/dist/builtin-registry-C7hkBDoD.js.map +0 -1
package/README.md
CHANGED
|
@@ -115,6 +115,17 @@ pnpx my-pi@latest observability
|
|
|
115
115
|
Pi handles model authentication natively. For provider-specific model
|
|
116
116
|
examples, see the Pi docs and the relevant extension/package README.
|
|
117
117
|
|
|
118
|
+
OpenRouter Fusion is configured by default: `my-pi` injects a
|
|
119
|
+
non-Anthropic Fusion panel/judge only for `openrouter/fusion`.
|
|
120
|
+
Configure it in `~/.pi/agent/my-pi-settings.json` under
|
|
121
|
+
`openRouterFusion`, e.g.
|
|
122
|
+
`{"openRouterFusion":{"analysisModels":["deepseek/deepseek-v3.2"],"judgeModel":"~openai/gpt-latest","force":false}}`.
|
|
123
|
+
Fusion is forced by default with `tool_choice: "required"`; set
|
|
124
|
+
`force: false` to let OpenRouter decide whether deliberation is
|
|
125
|
+
needed. Env vars `MY_PI_FUSION_ANALYSIS_MODELS`,
|
|
126
|
+
`MY_PI_FUSION_JUDGE_MODEL`, and `MY_PI_FUSION_FORCE` still work as
|
|
127
|
+
overrides. Disable with `--no-openrouter-fusion-config`.
|
|
128
|
+
|
|
118
129
|
## Reusable Pi packages
|
|
119
130
|
|
|
120
131
|
Install the full distribution with `pnpx my-pi@latest`, or install
|
package/dist/api.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Api, Model } from "@earendil-works/pi-ai";
|
|
2
1
|
import { AgentSessionRuntime, CreateAgentSessionFromServicesOptions, ExtensionAPI, ExtensionFactory, ExtensionFactory as ExtensionFactory$1, InteractiveMode, InteractiveModeOptions, PrintModeOptions, runPrintMode, runRpcMode } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { Api, Model } from "@earendil-works/pi-ai";
|
|
3
3
|
//#region src/extensions/startup-screen/index.d.ts
|
|
4
4
|
declare function startup_screen_extension(pi: ExtensionAPI): void;
|
|
5
5
|
//#endregion
|
|
@@ -39,6 +39,18 @@ declare const BUILTIN_EXTENSION_REGISTRY: readonly [{
|
|
|
39
39
|
readonly aliases: readonly ["mcp"];
|
|
40
40
|
readonly external_package_name: "@spences10/pi-mcp";
|
|
41
41
|
readonly load: () => Promise<typeof import("@spences10/pi-mcp").default>;
|
|
42
|
+
}, {
|
|
43
|
+
readonly key: "openrouter-fusion-config";
|
|
44
|
+
readonly label: "OpenRouter Fusion config";
|
|
45
|
+
readonly docs_label: "OpenRouter Fusion config guard";
|
|
46
|
+
readonly description: "Keeps OpenRouter Fusion off Anthropic by injecting a non-Anthropic panel and judge";
|
|
47
|
+
readonly default_enabled: true;
|
|
48
|
+
readonly option_name: "openrouter_fusion_config";
|
|
49
|
+
readonly cli_arg: "no-openrouter-fusion-config";
|
|
50
|
+
readonly cli_flag: "--no-openrouter-fusion-config";
|
|
51
|
+
readonly cli_description: "Disable OpenRouter Fusion non-Anthropic config";
|
|
52
|
+
readonly aliases: readonly ["openrouter-fusion-config", "fusion-budget"];
|
|
53
|
+
readonly load: () => Promise<ExtensionFactory$1>;
|
|
42
54
|
}, {
|
|
43
55
|
readonly key: "footer";
|
|
44
56
|
readonly label: "Footer";
|
|
@@ -313,7 +325,7 @@ declare const BUILTIN_EXTENSION_REGISTRY: readonly [{
|
|
|
313
325
|
type BuiltinExtensionKey = (typeof BUILTIN_EXTENSION_REGISTRY)[number]['key'];
|
|
314
326
|
type BuiltinExtensionOptionName = (typeof BUILTIN_EXTENSION_REGISTRY)[number]['option_name'];
|
|
315
327
|
//#endregion
|
|
316
|
-
//#region src/api.d.ts
|
|
328
|
+
//#region src/api/options.d.ts
|
|
317
329
|
type MyPiRuntimeMode = 'interactive' | 'print' | 'json' | 'rpc';
|
|
318
330
|
type MyPiThinkingLevel = NonNullable<CreateAgentSessionFromServicesOptions['thinkingLevel']>;
|
|
319
331
|
type BuiltinExtensionOptions = Partial<Record<BuiltinExtensionOptionName, boolean>>;
|
|
@@ -338,17 +350,25 @@ interface CreateMyPiOptions extends BuiltinExtensionOptions {
|
|
|
338
350
|
append_system_prompt?: string;
|
|
339
351
|
untrusted_repo?: boolean;
|
|
340
352
|
}
|
|
353
|
+
//#endregion
|
|
354
|
+
//#region src/api/builtin-extensions.d.ts
|
|
341
355
|
type BuiltinExtensionLoader = () => Promise<ExtensionFactory$1>;
|
|
356
|
+
declare function get_force_disabled_builtins(options: Pick<CreateMyPiOptions, 'runtime_mode'> & BuiltinExtensionOptions): Set<BuiltinExtensionKey>;
|
|
357
|
+
declare function get_externally_installed_builtin_extensions(agent_dir: string): Set<BuiltinExtensionKey>;
|
|
358
|
+
declare function create_lazy_builtin_extension_factory(key: BuiltinExtensionKey, load_extension: BuiltinExtensionLoader, force_disabled: ReadonlySet<BuiltinExtensionKey>): ExtensionFactory$1;
|
|
359
|
+
//#endregion
|
|
360
|
+
//#region src/api/env.d.ts
|
|
342
361
|
declare function apply_untrusted_repo_defaults(env?: NodeJS.ProcessEnv): string[];
|
|
362
|
+
//#endregion
|
|
363
|
+
//#region src/api/models.d.ts
|
|
343
364
|
interface ModelRegistryLike {
|
|
344
365
|
getAll(): Model<Api>[];
|
|
345
366
|
}
|
|
346
367
|
declare function resolve_model_reference(model_reference: string | undefined, model_registry: ModelRegistryLike): Model<Api> | undefined;
|
|
347
368
|
declare function resolve_effective_thinking_level(model: Model<Api> | undefined, thinking: MyPiThinkingLevel | undefined): MyPiThinkingLevel | undefined;
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
declare function create_lazy_builtin_extension_factory(key: BuiltinExtensionKey, load_extension: BuiltinExtensionLoader, force_disabled: ReadonlySet<BuiltinExtensionKey>): ExtensionFactory$1;
|
|
369
|
+
//#endregion
|
|
370
|
+
//#region src/api.d.ts
|
|
351
371
|
declare function create_my_pi(options?: CreateMyPiOptions): Promise<import("@earendil-works/pi-coding-agent").AgentSessionRuntime>;
|
|
352
372
|
//#endregion
|
|
353
|
-
export { type AgentSessionRuntime, CreateMyPiOptions, type ExtensionFactory, InteractiveMode, type InteractiveModeOptions, MyPiRuntimeMode, MyPiThinkingLevel, type PrintModeOptions, apply_untrusted_repo_defaults, create_lazy_builtin_extension_factory, create_my_pi, get_externally_installed_builtin_extensions, get_force_disabled_builtins, resolve_effective_thinking_level, resolve_model_reference, runPrintMode, runRpcMode };
|
|
373
|
+
export { type AgentSessionRuntime, type CreateMyPiOptions, type ExtensionFactory, InteractiveMode, type InteractiveModeOptions, type MyPiRuntimeMode, type MyPiThinkingLevel, type PrintModeOptions, apply_untrusted_repo_defaults, create_lazy_builtin_extension_factory, create_my_pi, get_externally_installed_builtin_extensions, get_force_disabled_builtins, resolve_effective_thinking_level, resolve_model_reference, runPrintMode, runRpcMode };
|
|
354
374
|
//# sourceMappingURL=api.d.ts.map
|
package/dist/api.js
CHANGED
|
@@ -1,180 +1,12 @@
|
|
|
1
|
-
import { n as BUILTIN_EXTENSION_REGISTRY, t as BUILTIN_EXTENSIONS } from "./builtin-registry-
|
|
1
|
+
import { n as BUILTIN_EXTENSION_REGISTRY, t as BUILTIN_EXTENSIONS } from "./builtin-registry-CYdEeqrp.js";
|
|
2
|
+
import { n as save_settings, t as load_settings } from "./settings-CTk0ws43.js";
|
|
2
3
|
import { createRequire } from "node:module";
|
|
3
|
-
import {
|
|
4
|
+
import { existsSync, readdirSync } from "node:fs";
|
|
4
5
|
import { basename, dirname, isAbsolute, join, resolve } from "node:path";
|
|
5
|
-
import { clampThinkingLevel } from "@earendil-works/pi-ai";
|
|
6
6
|
import { InteractiveMode, SessionManager, createAgentSessionFromServices, createAgentSessionRuntime, createAgentSessionServices, getAgentDir, runPrintMode, runRpcMode } from "@earendil-works/pi-coding-agent";
|
|
7
7
|
import { apply_project_trust_untrusted_defaults } from "@spences10/pi-project-trust";
|
|
8
|
-
import {
|
|
9
|
-
import { homedir } from "node:os";
|
|
8
|
+
import { clampThinkingLevel } from "@earendil-works/pi-ai";
|
|
10
9
|
import { show_settings_modal } from "@spences10/pi-tui-modal";
|
|
11
|
-
//#region src/settings/schema.ts
|
|
12
|
-
const DEFAULT_SETTINGS = {
|
|
13
|
-
version: 1,
|
|
14
|
-
extensions: { enabled: {} }
|
|
15
|
-
};
|
|
16
|
-
function normalize_settings(value) {
|
|
17
|
-
const raw = value;
|
|
18
|
-
const enabled = {};
|
|
19
|
-
const raw_enabled = raw?.extensions?.enabled;
|
|
20
|
-
if (raw_enabled && typeof raw_enabled === "object") {
|
|
21
|
-
for (const [key, state] of Object.entries(raw_enabled)) if (typeof state === "boolean") enabled[key] = state;
|
|
22
|
-
}
|
|
23
|
-
return {
|
|
24
|
-
...raw && typeof raw === "object" ? raw : {},
|
|
25
|
-
version: 1,
|
|
26
|
-
extensions: { enabled }
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
//#endregion
|
|
30
|
-
//#region src/settings/current.ts
|
|
31
|
-
function current_settings_exists() {
|
|
32
|
-
return existsSync(get_settings_path());
|
|
33
|
-
}
|
|
34
|
-
function read_current_settings() {
|
|
35
|
-
if (!current_settings_exists()) return { ...DEFAULT_SETTINGS };
|
|
36
|
-
return normalize_settings(read_settings());
|
|
37
|
-
}
|
|
38
|
-
function write_current_settings(settings) {
|
|
39
|
-
write_settings(settings);
|
|
40
|
-
}
|
|
41
|
-
function ensure_current_settings() {
|
|
42
|
-
if (!current_settings_exists()) write_current_settings(DEFAULT_SETTINGS);
|
|
43
|
-
return read_current_settings();
|
|
44
|
-
}
|
|
45
|
-
//#endregion
|
|
46
|
-
//#region src/settings/legacy.ts
|
|
47
|
-
function get_legacy_builtin_extensions_config_path() {
|
|
48
|
-
return join(process.env.XDG_CONFIG_HOME || join(homedir(), ".config"), "my-pi", "extensions.json");
|
|
49
|
-
}
|
|
50
|
-
function read_json_file(path) {
|
|
51
|
-
if (!existsSync(path)) return void 0;
|
|
52
|
-
return JSON.parse(readFileSync(path, "utf-8"));
|
|
53
|
-
}
|
|
54
|
-
function maybe_file(path) {
|
|
55
|
-
const config = read_json_file(path);
|
|
56
|
-
return config === void 0 ? void 0 : {
|
|
57
|
-
path,
|
|
58
|
-
config
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
function find_legacy_settings_files() {
|
|
62
|
-
const agent = getAgentDir();
|
|
63
|
-
const xdg = process.env.XDG_CONFIG_HOME || join(homedir(), ".config");
|
|
64
|
-
return {
|
|
65
|
-
extensions: maybe_file(get_legacy_builtin_extensions_config_path()),
|
|
66
|
-
mcpPolicy: maybe_file(join(agent, "mcp-policy.json")),
|
|
67
|
-
codingPreferences: maybe_file(join(agent, "coding-preferences.json")),
|
|
68
|
-
promptPresets: maybe_file(join(agent, "presets.json")),
|
|
69
|
-
promptPresetState: maybe_file(join(agent, "prompt-preset-state.json")),
|
|
70
|
-
trustedHooks: maybe_file(join(agent, "trusted-hooks.json")),
|
|
71
|
-
trustedMcpProjects: maybe_file(join(agent, "trusted-mcp-projects.json")),
|
|
72
|
-
trustedLspBinaries: maybe_file(join(agent, "trusted-lsp-binaries.json")),
|
|
73
|
-
telemetry: maybe_file(join(agent, "telemetry.json")),
|
|
74
|
-
footer: maybe_file(join(agent, "extensions", "pi-footer.json")),
|
|
75
|
-
skills: maybe_file(join(xdg, "my-pi", "skills.json")),
|
|
76
|
-
svelteGuardrails: maybe_file(join(xdg, "my-pi", "svelte-guardrails.json")),
|
|
77
|
-
context: maybe_file(join(xdg, "my-pi", "context.json"))
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
function has_legacy_settings_files() {
|
|
81
|
-
return Object.values(find_legacy_settings_files()).some(Boolean);
|
|
82
|
-
}
|
|
83
|
-
//#endregion
|
|
84
|
-
//#region src/settings/migrate.ts
|
|
85
|
-
function timestamp_for_filename(date = /* @__PURE__ */ new Date()) {
|
|
86
|
-
return date.toISOString().replace(/[:.]/g, "-");
|
|
87
|
-
}
|
|
88
|
-
function backup_path_for(original_path, backup_dir) {
|
|
89
|
-
return join(backup_dir, `${basename(dirname(original_path))}-${basename(original_path)}`);
|
|
90
|
-
}
|
|
91
|
-
function move_file_to_backup(source, target) {
|
|
92
|
-
try {
|
|
93
|
-
renameSync(source, target);
|
|
94
|
-
} catch (error) {
|
|
95
|
-
if (error instanceof Error && "code" in error && error.code === "EXDEV") {
|
|
96
|
-
copyFileSync(source, target);
|
|
97
|
-
unlinkSync(source);
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
throw error;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
function migrate_legacy_settings() {
|
|
104
|
-
const legacy = find_legacy_settings_files();
|
|
105
|
-
const entries = Object.values(legacy).filter((entry) => entry !== void 0);
|
|
106
|
-
const settings = read_settings();
|
|
107
|
-
if (legacy.extensions) settings.extensions = {
|
|
108
|
-
...settings.extensions,
|
|
109
|
-
enabled: {
|
|
110
|
-
...settings.extensions?.enabled,
|
|
111
|
-
...legacy.extensions.config.enabled
|
|
112
|
-
}
|
|
113
|
-
};
|
|
114
|
-
if (legacy.mcpPolicy) settings.mcp = {
|
|
115
|
-
...settings.mcp,
|
|
116
|
-
policy: legacy.mcpPolicy.config
|
|
117
|
-
};
|
|
118
|
-
if (legacy.codingPreferences) settings.codingPreferences = legacy.codingPreferences.config;
|
|
119
|
-
if (legacy.promptPresets || legacy.promptPresetState) settings.promptPresets = {
|
|
120
|
-
...settings.promptPresets,
|
|
121
|
-
...legacy.promptPresets && { global: legacy.promptPresets.config },
|
|
122
|
-
...legacy.promptPresetState && { state: legacy.promptPresetState.config }
|
|
123
|
-
};
|
|
124
|
-
settings.trust = {
|
|
125
|
-
...settings.trust,
|
|
126
|
-
...legacy.trustedHooks && { hooks: legacy.trustedHooks.config },
|
|
127
|
-
...legacy.trustedMcpProjects && { mcpProjects: legacy.trustedMcpProjects.config },
|
|
128
|
-
...legacy.trustedLspBinaries && { lspBinaries: legacy.trustedLspBinaries.config }
|
|
129
|
-
};
|
|
130
|
-
settings.packages = {
|
|
131
|
-
...settings.packages,
|
|
132
|
-
...legacy.telemetry && { telemetry: legacy.telemetry.config },
|
|
133
|
-
...legacy.footer && { footer: legacy.footer.config },
|
|
134
|
-
...legacy.skills && { skills: legacy.skills.config },
|
|
135
|
-
...legacy.svelteGuardrails && { svelteGuardrails: legacy.svelteGuardrails.config },
|
|
136
|
-
...legacy.context && { context: legacy.context.config }
|
|
137
|
-
};
|
|
138
|
-
write_settings(settings);
|
|
139
|
-
if (entries.length === 0) return {
|
|
140
|
-
migrated: false,
|
|
141
|
-
moved_files: [],
|
|
142
|
-
settings: normalize_settings(settings)
|
|
143
|
-
};
|
|
144
|
-
const backup_dir = join(getAgentDir(), `legacy-config-backup-${timestamp_for_filename()}`);
|
|
145
|
-
mkdirSync(backup_dir, {
|
|
146
|
-
recursive: true,
|
|
147
|
-
mode: 448
|
|
148
|
-
});
|
|
149
|
-
const moved_files = [];
|
|
150
|
-
for (const entry of entries) {
|
|
151
|
-
if (!existsSync(entry.path)) continue;
|
|
152
|
-
const target = backup_path_for(entry.path, backup_dir);
|
|
153
|
-
move_file_to_backup(entry.path, target);
|
|
154
|
-
moved_files.push(entry.path);
|
|
155
|
-
}
|
|
156
|
-
writeFileSync(join(backup_dir, "migration-report.json"), JSON.stringify({
|
|
157
|
-
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
158
|
-
settings_path: join(getAgentDir(), "my-pi-settings.json"),
|
|
159
|
-
moved_files
|
|
160
|
-
}, null, " ") + "\n", { mode: 384 });
|
|
161
|
-
return {
|
|
162
|
-
migrated: true,
|
|
163
|
-
backup_dir,
|
|
164
|
-
moved_files,
|
|
165
|
-
settings: normalize_settings(settings)
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
//#endregion
|
|
169
|
-
//#region src/settings/index.ts
|
|
170
|
-
function load_settings() {
|
|
171
|
-
if (has_legacy_settings_files()) return migrate_legacy_settings().settings;
|
|
172
|
-
return ensure_current_settings();
|
|
173
|
-
}
|
|
174
|
-
function save_settings(settings) {
|
|
175
|
-
write_current_settings(settings);
|
|
176
|
-
}
|
|
177
|
-
//#endregion
|
|
178
10
|
//#region src/extensions/manager/config.ts
|
|
179
11
|
function load_builtin_extensions_config() {
|
|
180
12
|
const settings = load_settings();
|
|
@@ -225,6 +57,168 @@ function find_builtin_extension(query) {
|
|
|
225
57
|
...extension.aliases
|
|
226
58
|
].some((value) => value.toLowerCase() === normalized));
|
|
227
59
|
}
|
|
60
|
+
const PACKAGE_THEME_DIR = resolve(dirname(createRequire(import.meta.url).resolve("@spences10/pi-themes/package.json")), "themes");
|
|
61
|
+
function get_force_disabled_builtins(options) {
|
|
62
|
+
const force_disabled = /* @__PURE__ */ new Set();
|
|
63
|
+
for (const extension of BUILTIN_EXTENSION_REGISTRY) {
|
|
64
|
+
if (!(options[extension.option_name] ?? extension.default_enabled)) force_disabled.add(extension.key);
|
|
65
|
+
const disabled_in = "mode_constraints" in extension ? extension.mode_constraints.disabled_in : void 0;
|
|
66
|
+
if (options.runtime_mode && disabled_in?.includes(options.runtime_mode)) force_disabled.add(extension.key);
|
|
67
|
+
}
|
|
68
|
+
return force_disabled;
|
|
69
|
+
}
|
|
70
|
+
function is_agent_dir_package_installed(agent_dir, package_name) {
|
|
71
|
+
return existsSync(join(agent_dir, "npm", "node_modules", package_name));
|
|
72
|
+
}
|
|
73
|
+
function get_externally_installed_builtin_extensions(agent_dir) {
|
|
74
|
+
const installed = /* @__PURE__ */ new Set();
|
|
75
|
+
for (const extension of BUILTIN_EXTENSION_REGISTRY) {
|
|
76
|
+
const external_package_name = extension.external_package_name;
|
|
77
|
+
if (external_package_name && is_agent_dir_package_installed(agent_dir, external_package_name)) installed.add(extension.key);
|
|
78
|
+
}
|
|
79
|
+
return installed;
|
|
80
|
+
}
|
|
81
|
+
function warn_builtin_extension_unavailable(key, error) {
|
|
82
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
83
|
+
process.emitWarning(`Built-in extension "${key}" is unavailable and was skipped: ${reason}`, { code: "MY_PI_BUILTIN_EXTENSION_UNAVAILABLE" });
|
|
84
|
+
}
|
|
85
|
+
function create_lazy_builtin_extension_factory(key, load_extension, force_disabled) {
|
|
86
|
+
return async (pi) => {
|
|
87
|
+
if (!is_builtin_extension_active(load_builtin_extensions_config(), key, force_disabled)) return;
|
|
88
|
+
try {
|
|
89
|
+
await (await load_extension())(pi);
|
|
90
|
+
} catch (error) {
|
|
91
|
+
warn_builtin_extension_unavailable(key, error);
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
function create_lazy_telemetry_extension(options) {
|
|
96
|
+
return async (pi) => {
|
|
97
|
+
try {
|
|
98
|
+
const { create_telemetry_extension } = await import("@spences10/pi-telemetry");
|
|
99
|
+
await create_telemetry_extension(options)(pi);
|
|
100
|
+
} catch (error) {
|
|
101
|
+
warn_builtin_extension_unavailable("telemetry", error);
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
function create_extensions_override(managed_inline_paths) {
|
|
106
|
+
const managed_paths = new Set(managed_inline_paths);
|
|
107
|
+
return (base) => {
|
|
108
|
+
const managed = new Map(base.extensions.map((extension) => [extension.path, extension]));
|
|
109
|
+
const ordered_managed = managed_inline_paths.map((path) => managed.get(path)).filter((extension) => Boolean(extension));
|
|
110
|
+
const others = base.extensions.filter((extension) => !managed_paths.has(extension.path));
|
|
111
|
+
return {
|
|
112
|
+
...base,
|
|
113
|
+
extensions: [...ordered_managed, ...others]
|
|
114
|
+
};
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
//#endregion
|
|
118
|
+
//#region src/api/env.ts
|
|
119
|
+
const PI_AGENT_DIR_ENV = "PI_CODING_AGENT_DIR";
|
|
120
|
+
const MY_PI_RUNTIME_MODE_ENV = "MY_PI_RUNTIME_MODE";
|
|
121
|
+
function snapshot_env(env, keys) {
|
|
122
|
+
return new Map(Array.from(keys, (key) => [key, env[key]]));
|
|
123
|
+
}
|
|
124
|
+
function restore_env(env, snapshot) {
|
|
125
|
+
for (const [key, value] of snapshot) if (value === void 0) delete env[key];
|
|
126
|
+
else env[key] = value;
|
|
127
|
+
}
|
|
128
|
+
function wrap_runtime_env_restore(runtime, restore) {
|
|
129
|
+
const dispose = runtime.dispose.bind(runtime);
|
|
130
|
+
let restored = false;
|
|
131
|
+
const restore_once = () => {
|
|
132
|
+
if (restored) return;
|
|
133
|
+
restored = true;
|
|
134
|
+
restore();
|
|
135
|
+
};
|
|
136
|
+
runtime.dispose = (async () => {
|
|
137
|
+
try {
|
|
138
|
+
await dispose();
|
|
139
|
+
} finally {
|
|
140
|
+
restore_once();
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
return runtime;
|
|
144
|
+
}
|
|
145
|
+
const UNTRUSTED_CHILD_ENV_DEFAULTS = {
|
|
146
|
+
MY_PI_CHILD_ENV_ALLOWLIST: "",
|
|
147
|
+
MY_PI_MCP_ENV_ALLOWLIST: "",
|
|
148
|
+
MY_PI_LSP_ENV_ALLOWLIST: "",
|
|
149
|
+
MY_PI_HOOKS_ENV_ALLOWLIST: "",
|
|
150
|
+
MY_PI_TEAM_MODE_ENV_ALLOWLIST: ""
|
|
151
|
+
};
|
|
152
|
+
function apply_untrusted_repo_defaults(env = process.env) {
|
|
153
|
+
const applied = apply_project_trust_untrusted_defaults(env);
|
|
154
|
+
for (const [key, value] of Object.entries(UNTRUSTED_CHILD_ENV_DEFAULTS)) {
|
|
155
|
+
if (env[key] !== void 0) continue;
|
|
156
|
+
env[key] = value;
|
|
157
|
+
applied.push(key);
|
|
158
|
+
}
|
|
159
|
+
return applied;
|
|
160
|
+
}
|
|
161
|
+
function is_resource_enabled(value) {
|
|
162
|
+
const normalized = value?.trim().toLowerCase();
|
|
163
|
+
if (!normalized) return true;
|
|
164
|
+
if ([
|
|
165
|
+
"0",
|
|
166
|
+
"false",
|
|
167
|
+
"no",
|
|
168
|
+
"skip",
|
|
169
|
+
"disable"
|
|
170
|
+
].includes(normalized)) return false;
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
173
|
+
function resolve_agent_dir(cwd, agent_dir) {
|
|
174
|
+
return agent_dir ? resolve(cwd, agent_dir) : getAgentDir();
|
|
175
|
+
}
|
|
176
|
+
//#endregion
|
|
177
|
+
//#region src/api/models.ts
|
|
178
|
+
function resolve_model_reference(model_reference, model_registry) {
|
|
179
|
+
if (!model_reference) return void 0;
|
|
180
|
+
const models = model_registry.getAll();
|
|
181
|
+
const lower_reference = model_reference.toLowerCase();
|
|
182
|
+
const slash_index = model_reference.indexOf("/");
|
|
183
|
+
if (slash_index !== -1) {
|
|
184
|
+
const maybe_provider = model_reference.slice(0, slash_index);
|
|
185
|
+
const model_id = model_reference.slice(slash_index + 1);
|
|
186
|
+
const provider = models.find((model) => model.provider.toLowerCase() === maybe_provider.toLowerCase())?.provider;
|
|
187
|
+
if (provider) {
|
|
188
|
+
const provider_match = models.find((model) => model.provider === provider && model.id.toLowerCase() === model_id.toLowerCase());
|
|
189
|
+
if (provider_match) return provider_match;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return models.find((model) => {
|
|
193
|
+
const id = model.id.toLowerCase();
|
|
194
|
+
const full_id = `${model.provider}/${model.id}`.toLowerCase();
|
|
195
|
+
return id === lower_reference || full_id === lower_reference;
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
function resolve_effective_thinking_level(model, thinking) {
|
|
199
|
+
if (!thinking || !model) return thinking;
|
|
200
|
+
return clampThinkingLevel(model, thinking);
|
|
201
|
+
}
|
|
202
|
+
//#endregion
|
|
203
|
+
//#region src/api/session.ts
|
|
204
|
+
function resolve_session_file(cwd, session_dir, session_ref) {
|
|
205
|
+
if (!session_ref) return void 0;
|
|
206
|
+
const explicit_path = isAbsolute(session_ref) ? session_ref : resolve(cwd, session_ref);
|
|
207
|
+
if (existsSync(explicit_path)) return explicit_path;
|
|
208
|
+
if (session_ref.endsWith(".jsonl")) return explicit_path;
|
|
209
|
+
const dir = session_dir ? resolve(cwd, session_dir) : void 0;
|
|
210
|
+
if (!dir || !existsSync(dir)) return void 0;
|
|
211
|
+
const match = readdirSync(dir).filter((file) => file.endsWith(".jsonl") && (basename(file, ".jsonl").endsWith(session_ref) || file.includes(session_ref))).sort().at(-1);
|
|
212
|
+
return match ? join(dir, match) : void 0;
|
|
213
|
+
}
|
|
214
|
+
function create_session_manager(options) {
|
|
215
|
+
const resolved_session_dir = options.session_dir ? resolve(options.cwd, options.session_dir) : SessionManager.create(options.cwd).getSessionDir();
|
|
216
|
+
const session_ref = options.session ?? options.session_id;
|
|
217
|
+
const session_file = resolve_session_file(options.cwd, resolved_session_dir, session_ref);
|
|
218
|
+
const session_manager = session_file ? SessionManager.open(session_file, resolved_session_dir, options.cwd) : SessionManager.create(options.cwd, resolved_session_dir, options.session_id ? { id: options.session_id } : {});
|
|
219
|
+
if (options.startup_session_name && session_manager.getSessionName() !== options.startup_session_name) session_manager.appendSessionInfo(options.startup_session_name);
|
|
220
|
+
return session_manager;
|
|
221
|
+
}
|
|
228
222
|
//#endregion
|
|
229
223
|
//#region src/extensions/manager/index.ts
|
|
230
224
|
const ENABLED = "● enabled";
|
|
@@ -401,162 +395,6 @@ function create_extensions_extension(options = {}) {
|
|
|
401
395
|
create_extensions_extension();
|
|
402
396
|
//#endregion
|
|
403
397
|
//#region src/api.ts
|
|
404
|
-
const PACKAGE_THEME_DIR = resolve(dirname(createRequire(import.meta.url).resolve("@spences10/pi-themes/package.json")), "themes");
|
|
405
|
-
const PI_AGENT_DIR_ENV = "PI_CODING_AGENT_DIR";
|
|
406
|
-
const MY_PI_RUNTIME_MODE_ENV = "MY_PI_RUNTIME_MODE";
|
|
407
|
-
function snapshot_env(env, keys) {
|
|
408
|
-
return new Map(Array.from(keys, (key) => [key, env[key]]));
|
|
409
|
-
}
|
|
410
|
-
function restore_env(env, snapshot) {
|
|
411
|
-
for (const [key, value] of snapshot) if (value === void 0) delete env[key];
|
|
412
|
-
else env[key] = value;
|
|
413
|
-
}
|
|
414
|
-
function wrap_runtime_env_restore(runtime, restore) {
|
|
415
|
-
const dispose = runtime.dispose.bind(runtime);
|
|
416
|
-
let restored = false;
|
|
417
|
-
const restore_once = () => {
|
|
418
|
-
if (restored) return;
|
|
419
|
-
restored = true;
|
|
420
|
-
restore();
|
|
421
|
-
};
|
|
422
|
-
runtime.dispose = (async () => {
|
|
423
|
-
try {
|
|
424
|
-
await dispose();
|
|
425
|
-
} finally {
|
|
426
|
-
restore_once();
|
|
427
|
-
}
|
|
428
|
-
});
|
|
429
|
-
return runtime;
|
|
430
|
-
}
|
|
431
|
-
const UNTRUSTED_CHILD_ENV_DEFAULTS = {
|
|
432
|
-
MY_PI_CHILD_ENV_ALLOWLIST: "",
|
|
433
|
-
MY_PI_MCP_ENV_ALLOWLIST: "",
|
|
434
|
-
MY_PI_LSP_ENV_ALLOWLIST: "",
|
|
435
|
-
MY_PI_HOOKS_ENV_ALLOWLIST: "",
|
|
436
|
-
MY_PI_TEAM_MODE_ENV_ALLOWLIST: ""
|
|
437
|
-
};
|
|
438
|
-
function apply_untrusted_repo_defaults(env = process.env) {
|
|
439
|
-
const applied = apply_project_trust_untrusted_defaults(env);
|
|
440
|
-
for (const [key, value] of Object.entries(UNTRUSTED_CHILD_ENV_DEFAULTS)) {
|
|
441
|
-
if (env[key] !== void 0) continue;
|
|
442
|
-
env[key] = value;
|
|
443
|
-
applied.push(key);
|
|
444
|
-
}
|
|
445
|
-
return applied;
|
|
446
|
-
}
|
|
447
|
-
function is_resource_enabled(value) {
|
|
448
|
-
const normalized = value?.trim().toLowerCase();
|
|
449
|
-
if (!normalized) return true;
|
|
450
|
-
if ([
|
|
451
|
-
"0",
|
|
452
|
-
"false",
|
|
453
|
-
"no",
|
|
454
|
-
"skip",
|
|
455
|
-
"disable"
|
|
456
|
-
].includes(normalized)) return false;
|
|
457
|
-
return true;
|
|
458
|
-
}
|
|
459
|
-
function resolve_agent_dir(cwd, agent_dir) {
|
|
460
|
-
return agent_dir ? resolve(cwd, agent_dir) : getAgentDir();
|
|
461
|
-
}
|
|
462
|
-
function resolve_session_file(cwd, session_dir, session_ref) {
|
|
463
|
-
if (!session_ref) return void 0;
|
|
464
|
-
const explicit_path = isAbsolute(session_ref) ? session_ref : resolve(cwd, session_ref);
|
|
465
|
-
if (existsSync(explicit_path)) return explicit_path;
|
|
466
|
-
if (session_ref.endsWith(".jsonl")) return explicit_path;
|
|
467
|
-
const dir = session_dir ? resolve(cwd, session_dir) : void 0;
|
|
468
|
-
if (!dir || !existsSync(dir)) return void 0;
|
|
469
|
-
const match = readdirSync(dir).filter((file) => file.endsWith(".jsonl") && (basename(file, ".jsonl").endsWith(session_ref) || file.includes(session_ref))).sort().at(-1);
|
|
470
|
-
return match ? join(dir, match) : void 0;
|
|
471
|
-
}
|
|
472
|
-
function create_session_manager(options) {
|
|
473
|
-
const resolved_session_dir = options.session_dir ? resolve(options.cwd, options.session_dir) : SessionManager.create(options.cwd).getSessionDir();
|
|
474
|
-
const session_ref = options.session ?? options.session_id;
|
|
475
|
-
const session_file = resolve_session_file(options.cwd, resolved_session_dir, session_ref);
|
|
476
|
-
const session_manager = session_file ? SessionManager.open(session_file, resolved_session_dir, options.cwd) : SessionManager.create(options.cwd, resolved_session_dir, options.session_id ? { id: options.session_id } : {});
|
|
477
|
-
if (options.startup_session_name && session_manager.getSessionName() !== options.startup_session_name) session_manager.appendSessionInfo(options.startup_session_name);
|
|
478
|
-
return session_manager;
|
|
479
|
-
}
|
|
480
|
-
function resolve_model_reference(model_reference, model_registry) {
|
|
481
|
-
if (!model_reference) return void 0;
|
|
482
|
-
const models = model_registry.getAll();
|
|
483
|
-
const lower_reference = model_reference.toLowerCase();
|
|
484
|
-
const slash_index = model_reference.indexOf("/");
|
|
485
|
-
if (slash_index !== -1) {
|
|
486
|
-
const maybe_provider = model_reference.slice(0, slash_index);
|
|
487
|
-
const model_id = model_reference.slice(slash_index + 1);
|
|
488
|
-
const provider = models.find((model) => model.provider.toLowerCase() === maybe_provider.toLowerCase())?.provider;
|
|
489
|
-
if (provider) {
|
|
490
|
-
const provider_match = models.find((model) => model.provider === provider && model.id.toLowerCase() === model_id.toLowerCase());
|
|
491
|
-
if (provider_match) return provider_match;
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
return models.find((model) => {
|
|
495
|
-
const id = model.id.toLowerCase();
|
|
496
|
-
const full_id = `${model.provider}/${model.id}`.toLowerCase();
|
|
497
|
-
return id === lower_reference || full_id === lower_reference;
|
|
498
|
-
});
|
|
499
|
-
}
|
|
500
|
-
function resolve_effective_thinking_level(model, thinking) {
|
|
501
|
-
if (!thinking || !model) return thinking;
|
|
502
|
-
return clampThinkingLevel(model, thinking);
|
|
503
|
-
}
|
|
504
|
-
function get_force_disabled_builtins(options) {
|
|
505
|
-
const force_disabled = /* @__PURE__ */ new Set();
|
|
506
|
-
for (const extension of BUILTIN_EXTENSION_REGISTRY) {
|
|
507
|
-
if (!(options[extension.option_name] ?? extension.default_enabled)) force_disabled.add(extension.key);
|
|
508
|
-
const disabled_in = "mode_constraints" in extension ? extension.mode_constraints.disabled_in : void 0;
|
|
509
|
-
if (options.runtime_mode && disabled_in?.includes(options.runtime_mode)) force_disabled.add(extension.key);
|
|
510
|
-
}
|
|
511
|
-
return force_disabled;
|
|
512
|
-
}
|
|
513
|
-
function is_agent_dir_package_installed(agent_dir, package_name) {
|
|
514
|
-
return existsSync(join(agent_dir, "npm", "node_modules", package_name));
|
|
515
|
-
}
|
|
516
|
-
function get_externally_installed_builtin_extensions(agent_dir) {
|
|
517
|
-
const installed = /* @__PURE__ */ new Set();
|
|
518
|
-
for (const extension of BUILTIN_EXTENSION_REGISTRY) {
|
|
519
|
-
const external_package_name = extension.external_package_name;
|
|
520
|
-
if (external_package_name && is_agent_dir_package_installed(agent_dir, external_package_name)) installed.add(extension.key);
|
|
521
|
-
}
|
|
522
|
-
return installed;
|
|
523
|
-
}
|
|
524
|
-
function warn_builtin_extension_unavailable(key, error) {
|
|
525
|
-
const reason = error instanceof Error ? error.message : String(error);
|
|
526
|
-
process.emitWarning(`Built-in extension "${key}" is unavailable and was skipped: ${reason}`, { code: "MY_PI_BUILTIN_EXTENSION_UNAVAILABLE" });
|
|
527
|
-
}
|
|
528
|
-
function create_lazy_builtin_extension_factory(key, load_extension, force_disabled) {
|
|
529
|
-
return async (pi) => {
|
|
530
|
-
if (!is_builtin_extension_active(load_builtin_extensions_config(), key, force_disabled)) return;
|
|
531
|
-
try {
|
|
532
|
-
await (await load_extension())(pi);
|
|
533
|
-
} catch (error) {
|
|
534
|
-
warn_builtin_extension_unavailable(key, error);
|
|
535
|
-
}
|
|
536
|
-
};
|
|
537
|
-
}
|
|
538
|
-
function create_lazy_telemetry_extension(options) {
|
|
539
|
-
return async (pi) => {
|
|
540
|
-
try {
|
|
541
|
-
const { create_telemetry_extension } = await import("@spences10/pi-telemetry");
|
|
542
|
-
await create_telemetry_extension(options)(pi);
|
|
543
|
-
} catch (error) {
|
|
544
|
-
warn_builtin_extension_unavailable("telemetry", error);
|
|
545
|
-
}
|
|
546
|
-
};
|
|
547
|
-
}
|
|
548
|
-
function create_extensions_override(managed_inline_paths) {
|
|
549
|
-
const managed_paths = new Set(managed_inline_paths);
|
|
550
|
-
return (base) => {
|
|
551
|
-
const managed = new Map(base.extensions.map((extension) => [extension.path, extension]));
|
|
552
|
-
const ordered_managed = managed_inline_paths.map((path) => managed.get(path)).filter((extension) => Boolean(extension));
|
|
553
|
-
const others = base.extensions.filter((extension) => !managed_paths.has(extension.path));
|
|
554
|
-
return {
|
|
555
|
-
...base,
|
|
556
|
-
extensions: [...ordered_managed, ...others]
|
|
557
|
-
};
|
|
558
|
-
};
|
|
559
|
-
}
|
|
560
398
|
async function create_my_pi(options = {}) {
|
|
561
399
|
const { cwd = process.cwd(), agent_dir, extensions = [], extensionFactories: user_factories = [], runtime_mode = "interactive", telemetry, telemetry_db_path, model, thinking, selected_tools, excluded_tools, selected_skills, session, session_id, startup_session_name, session_dir, system_prompt, append_system_prompt, untrusted_repo = false } = options;
|
|
562
400
|
const env_keys_to_restore = new Set([MY_PI_RUNTIME_MODE_ENV]);
|