my-pi 0.1.11 → 0.1.13
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 +43 -3
- package/dist/{api-C7cSSbTg.js → api-Eq36fWnN.js} +238 -23
- package/dist/api-Eq36fWnN.js.map +1 -0
- package/dist/api.js +2 -2
- package/dist/index.js +10 -4
- package/dist/index.js.map +1 -1
- package/package.json +10 -10
- package/src/extensions/hooks-resolution/env.test.ts +41 -0
- package/src/extensions/hooks-resolution/env.ts +55 -0
- package/src/extensions/hooks-resolution/index.test.ts +99 -1
- package/src/extensions/hooks-resolution/index.ts +162 -47
- package/src/extensions/hooks-resolution/trust.test.ts +46 -0
- package/src/extensions/hooks-resolution/trust.ts +63 -0
- package/src/extensions/prompt-presets/index.test.ts +27 -0
- package/src/extensions/prompt-presets/index.ts +23 -8
- package/dist/api-C7cSSbTg.js.map +0 -1
package/README.md
CHANGED
|
@@ -195,9 +195,29 @@ A practical sandbox command looks like:
|
|
|
195
195
|
```bash
|
|
196
196
|
PI_CODING_AGENT_DIR=/work/pi-agent \
|
|
197
197
|
ANTHROPIC_API_KEY=... \
|
|
198
|
-
pnpx my-pi@latest --telemetry --json "run eval case"
|
|
198
|
+
pnpx my-pi@latest --untrusted --telemetry --json "run eval case"
|
|
199
199
|
```
|
|
200
200
|
|
|
201
|
+
### Untrusted repo safe mode
|
|
202
|
+
|
|
203
|
+
Use `--untrusted` in unknown repositories, evals, or sandboxes. It
|
|
204
|
+
keeps built-ins available but starts with conservative
|
|
205
|
+
project-resource defaults:
|
|
206
|
+
|
|
207
|
+
- skips project-local MCP config (`MY_PI_MCP_PROJECT_CONFIG=skip`)
|
|
208
|
+
- skips Claude-style project hooks (`MY_PI_HOOKS_CONFIG=skip`)
|
|
209
|
+
- uses global LSP binaries instead of project-local binaries
|
|
210
|
+
(`MY_PI_LSP_PROJECT_BINARY=global`)
|
|
211
|
+
- skips project prompt presets (`MY_PI_PROMPT_PRESETS_PROJECT=skip`)
|
|
212
|
+
- skips project-local `.pi/skills` and `.claude/skills`
|
|
213
|
+
(`MY_PI_PROJECT_SKILLS=skip`)
|
|
214
|
+
- clears optional child-process env allowlists unless they were set
|
|
215
|
+
explicitly
|
|
216
|
+
|
|
217
|
+
Set the listed environment variables to `allow` or `trust` where
|
|
218
|
+
supported to re-enable one feature intentionally while staying in safe
|
|
219
|
+
mode.
|
|
220
|
+
|
|
201
221
|
### Extension stacking
|
|
202
222
|
|
|
203
223
|
```bash
|
|
@@ -313,8 +333,28 @@ HTTP MCP servers are supported too:
|
|
|
313
333
|
Use `"type": "http"` or `"type": "streamable-http"` for remote MCP
|
|
314
334
|
servers. If `url` is present, my-pi treats the entry as HTTP.
|
|
315
335
|
|
|
316
|
-
|
|
317
|
-
|
|
336
|
+
Global MCP config is loaded automatically. Project-local `mcp.json` is
|
|
337
|
+
untrusted by default; interactive sessions prompt before loading it
|
|
338
|
+
and headless sessions skip it unless `MY_PI_MCP_PROJECT_CONFIG=allow`
|
|
339
|
+
or `MY_PI_MCP_PROJECT_CONFIG=trust` is set. If both configs define the
|
|
340
|
+
same server name, the trusted project config wins.
|
|
341
|
+
|
|
342
|
+
### Hooks
|
|
343
|
+
|
|
344
|
+
Claude-style hooks are discovered from `.claude/settings.json`,
|
|
345
|
+
`.rulesync/hooks.json`, and `.pi/hooks.json`. Because hook commands
|
|
346
|
+
run through `bash -lc`, project hook config is untrusted by default.
|
|
347
|
+
Interactive sessions show the hook source files and commands before
|
|
348
|
+
allowing execution; headless sessions skip hooks unless
|
|
349
|
+
`MY_PI_HOOKS_CONFIG=allow` or `MY_PI_HOOKS_CONFIG=trust` is set.
|
|
350
|
+
Trusted hook approvals are remembered per project directory and
|
|
351
|
+
hook-config hash.
|
|
352
|
+
|
|
353
|
+
Hook commands receive a restricted child-process environment by
|
|
354
|
+
default: baseline shell variables plus `CLAUDE_PROJECT_DIR`. Use
|
|
355
|
+
`MY_PI_HOOKS_ENV_ALLOWLIST=NAME,OTHER_NAME` or the shared
|
|
356
|
+
`MY_PI_CHILD_ENV_ALLOWLIST` to pass selected ambient variables
|
|
357
|
+
through.
|
|
318
358
|
|
|
319
359
|
### Commands
|
|
320
360
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { BorderedLoader, InteractiveMode as InteractiveMode$1, SessionManager, SettingsManager, convertToLlm, createAgentSessionFromServices, createAgentSessionRuntime, createAgentSessionServices, getAgentDir, runPrintMode as runPrintMode$1, serializeConversation } from "@mariozechner/pi-coding-agent";
|
|
2
2
|
import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
3
|
-
import { basename, dirname, join, resolve } from "node:path";
|
|
3
|
+
import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import confirm_destructive_extension from "@spences10/pi-confirm-destructive";
|
|
6
6
|
import lsp_extension from "@spences10/pi-lsp";
|
|
@@ -13,11 +13,81 @@ import skills_extension, { create_skills_manager } from "@spences10/pi-skills";
|
|
|
13
13
|
import sqlite_tools_extension from "@spences10/pi-sqlite-tools";
|
|
14
14
|
import { create_telemetry_extension } from "@spences10/pi-telemetry";
|
|
15
15
|
import { spawn } from "node:child_process";
|
|
16
|
+
import { createHash } from "node:crypto";
|
|
16
17
|
import { homedir } from "node:os";
|
|
17
18
|
import { Container, SettingsList, Text, truncateToWidth, visibleWidth } from "@mariozechner/pi-tui";
|
|
18
19
|
import { complete } from "@mariozechner/pi-ai";
|
|
20
|
+
//#region src/extensions/hooks-resolution/env.ts
|
|
21
|
+
const BASE_CHILD_ENV_KEYS = new Set([
|
|
22
|
+
"CI",
|
|
23
|
+
"COLORTERM",
|
|
24
|
+
"FORCE_COLOR",
|
|
25
|
+
"HOME",
|
|
26
|
+
"LANG",
|
|
27
|
+
"LOGNAME",
|
|
28
|
+
"NO_COLOR",
|
|
29
|
+
"PATH",
|
|
30
|
+
"SHELL",
|
|
31
|
+
"TEMP",
|
|
32
|
+
"TERM",
|
|
33
|
+
"TMP",
|
|
34
|
+
"TMPDIR",
|
|
35
|
+
"USER"
|
|
36
|
+
]);
|
|
37
|
+
const EXTRA_ENV_ALLOWLIST_KEYS = ["MY_PI_CHILD_ENV_ALLOWLIST", "MY_PI_HOOKS_ENV_ALLOWLIST"];
|
|
38
|
+
function create_child_process_env(explicit_env = {}, source_env = process.env) {
|
|
39
|
+
const env = {};
|
|
40
|
+
const allowed_keys = new Set(BASE_CHILD_ENV_KEYS);
|
|
41
|
+
for (const key of Object.keys(source_env)) if (key.startsWith("LC_")) allowed_keys.add(key);
|
|
42
|
+
for (const allowlist_key of EXTRA_ENV_ALLOWLIST_KEYS) for (const key of parse_env_allowlist(source_env[allowlist_key])) allowed_keys.add(key);
|
|
43
|
+
for (const key of allowed_keys) {
|
|
44
|
+
const value = source_env[key];
|
|
45
|
+
if (typeof value === "string") env[key] = value;
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
...env,
|
|
49
|
+
...explicit_env
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function parse_env_allowlist(value) {
|
|
53
|
+
if (!value) return [];
|
|
54
|
+
return value.split(",").map((key) => key.trim()).filter(Boolean);
|
|
55
|
+
}
|
|
56
|
+
//#endregion
|
|
57
|
+
//#region src/extensions/hooks-resolution/trust.ts
|
|
58
|
+
function default_hooks_trust_store_path() {
|
|
59
|
+
return join(homedir(), ".pi", "agent", "trusted-hooks.json");
|
|
60
|
+
}
|
|
61
|
+
function is_hooks_config_trusted(project_dir, hash, trust_store_path = default_hooks_trust_store_path()) {
|
|
62
|
+
return read_trusted_hooks(trust_store_path)[project_dir]?.hash === hash;
|
|
63
|
+
}
|
|
64
|
+
function trust_hooks_config(project_dir, hash, trust_store_path = default_hooks_trust_store_path()) {
|
|
65
|
+
const trusted_hooks = read_trusted_hooks(trust_store_path);
|
|
66
|
+
trusted_hooks[project_dir] = {
|
|
67
|
+
project_dir,
|
|
68
|
+
hash,
|
|
69
|
+
trusted_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
70
|
+
};
|
|
71
|
+
mkdirSync(dirname(trust_store_path), { recursive: true });
|
|
72
|
+
writeFileSync(trust_store_path, JSON.stringify(trusted_hooks, null, " ") + "\n", {
|
|
73
|
+
encoding: "utf8",
|
|
74
|
+
mode: 384
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
function read_trusted_hooks(trust_store_path) {
|
|
78
|
+
if (!existsSync(trust_store_path)) return {};
|
|
79
|
+
try {
|
|
80
|
+
const raw = readFileSync(trust_store_path, "utf-8");
|
|
81
|
+
const parsed = JSON.parse(raw);
|
|
82
|
+
return parsed && typeof parsed === "object" ? parsed : {};
|
|
83
|
+
} catch {
|
|
84
|
+
return {};
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
//#endregion
|
|
19
88
|
//#region src/extensions/hooks-resolution/index.ts
|
|
20
89
|
const HOOK_TIMEOUT_MS = 600 * 1e3;
|
|
90
|
+
const HOOKS_CONFIG_ENV = "MY_PI_HOOKS_CONFIG";
|
|
21
91
|
function is_file(path) {
|
|
22
92
|
try {
|
|
23
93
|
return statSync(path).isFile();
|
|
@@ -134,20 +204,47 @@ function parse_simple_hooks_file(config, source, project_dir) {
|
|
|
134
204
|
}
|
|
135
205
|
return hooks;
|
|
136
206
|
}
|
|
207
|
+
function hook_config_paths(project_dir) {
|
|
208
|
+
return [
|
|
209
|
+
join(project_dir, ".claude", "settings.json"),
|
|
210
|
+
join(project_dir, ".rulesync", "hooks.json"),
|
|
211
|
+
join(project_dir, ".pi", "hooks.json")
|
|
212
|
+
];
|
|
213
|
+
}
|
|
214
|
+
function parse_hooks_config_file(path, project_dir) {
|
|
215
|
+
const config = read_json_file(path);
|
|
216
|
+
if (config === void 0) return [];
|
|
217
|
+
if (path.endsWith(join(".claude", "settings.json"))) return parse_claude_settings_hooks(config, path, project_dir);
|
|
218
|
+
return parse_simple_hooks_file(config, path, project_dir);
|
|
219
|
+
}
|
|
137
220
|
function load_hooks(cwd) {
|
|
138
221
|
const project_dir = find_project_dir(cwd);
|
|
139
|
-
const hooks = [];
|
|
140
|
-
const claude_settings_path = join(project_dir, ".claude", "settings.json");
|
|
141
|
-
const rulesync_hooks_path = join(project_dir, ".rulesync", "hooks.json");
|
|
142
|
-
const pi_hooks_path = join(project_dir, ".pi", "hooks.json");
|
|
143
|
-
const claude_settings = read_json_file(claude_settings_path);
|
|
144
|
-
if (claude_settings !== void 0) hooks.push(...parse_claude_settings_hooks(claude_settings, claude_settings_path, project_dir));
|
|
145
|
-
const rulesync_hooks = read_json_file(rulesync_hooks_path);
|
|
146
|
-
if (rulesync_hooks !== void 0) hooks.push(...parse_simple_hooks_file(rulesync_hooks, rulesync_hooks_path, project_dir));
|
|
147
|
-
const pi_hooks = read_json_file(pi_hooks_path);
|
|
148
|
-
if (pi_hooks !== void 0) hooks.push(...parse_simple_hooks_file(pi_hooks, pi_hooks_path, project_dir));
|
|
149
222
|
return {
|
|
150
223
|
project_dir,
|
|
224
|
+
hooks: hook_config_paths(project_dir).flatMap((path) => parse_hooks_config_file(path, project_dir))
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
function get_hooks_config_info(cwd) {
|
|
228
|
+
const project_dir = find_project_dir(cwd);
|
|
229
|
+
const sources = hook_config_paths(project_dir).filter(is_file);
|
|
230
|
+
if (sources.length === 0) return void 0;
|
|
231
|
+
const hash = createHash("sha256");
|
|
232
|
+
for (const source of sources) {
|
|
233
|
+
hash.update(source);
|
|
234
|
+
hash.update("\0");
|
|
235
|
+
hash.update(readFileSync(source, "utf8"));
|
|
236
|
+
hash.update("\0");
|
|
237
|
+
}
|
|
238
|
+
const hooks = sources.flatMap((source) => parse_hooks_config_file(source, project_dir)).map((hook) => ({
|
|
239
|
+
event_name: hook.event_name,
|
|
240
|
+
matcher_text: hook.matcher_text,
|
|
241
|
+
command: hook.command,
|
|
242
|
+
source: hook.source
|
|
243
|
+
}));
|
|
244
|
+
return {
|
|
245
|
+
project_dir,
|
|
246
|
+
hash: hash.digest("hex"),
|
|
247
|
+
sources,
|
|
151
248
|
hooks
|
|
152
249
|
};
|
|
153
250
|
}
|
|
@@ -216,10 +313,7 @@ async function run_command_hook(command, cwd, payload) {
|
|
|
216
313
|
const started_at = Date.now();
|
|
217
314
|
const child = spawn("bash", ["-lc", command], {
|
|
218
315
|
cwd,
|
|
219
|
-
env: {
|
|
220
|
-
...process.env,
|
|
221
|
-
CLAUDE_PROJECT_DIR: cwd
|
|
222
|
-
},
|
|
316
|
+
env: create_child_process_env({ CLAUDE_PROJECT_DIR: cwd }),
|
|
223
317
|
stdio: [
|
|
224
318
|
"pipe",
|
|
225
319
|
"pipe",
|
|
@@ -284,6 +378,66 @@ function hook_name(command) {
|
|
|
284
378
|
if (sh_path_match) return basename(sh_path_match[0]);
|
|
285
379
|
return basename(command.trim().split(/\s+/)[0] ?? "hook");
|
|
286
380
|
}
|
|
381
|
+
function normalize_hooks_config_decision(value) {
|
|
382
|
+
const normalized = value?.trim().toLowerCase();
|
|
383
|
+
if (!normalized) return void 0;
|
|
384
|
+
if ([
|
|
385
|
+
"1",
|
|
386
|
+
"true",
|
|
387
|
+
"yes",
|
|
388
|
+
"allow"
|
|
389
|
+
].includes(normalized)) return "allow";
|
|
390
|
+
if (normalized === "trust") return "trust";
|
|
391
|
+
if ([
|
|
392
|
+
"0",
|
|
393
|
+
"false",
|
|
394
|
+
"no",
|
|
395
|
+
"skip",
|
|
396
|
+
"disable"
|
|
397
|
+
].includes(normalized)) return "skip";
|
|
398
|
+
}
|
|
399
|
+
function format_hooks_config_prompt(info) {
|
|
400
|
+
const source_lines = info.sources.map((source) => `- ${source}`);
|
|
401
|
+
const hook_lines = info.hooks.length === 0 ? ["- no valid command hooks detected"] : info.hooks.map((hook) => {
|
|
402
|
+
const matcher = hook.matcher_text ? ` matcher=${hook.matcher_text}` : "";
|
|
403
|
+
return `- ${hook.event_name}${matcher}: ${hook.command}`;
|
|
404
|
+
});
|
|
405
|
+
return [
|
|
406
|
+
"Project hook config can execute shell commands after tool use. Trust these hooks?",
|
|
407
|
+
`Project: ${info.project_dir}`,
|
|
408
|
+
`SHA-256: ${info.hash}`,
|
|
409
|
+
"Sources:",
|
|
410
|
+
...source_lines,
|
|
411
|
+
"Commands:",
|
|
412
|
+
...hook_lines
|
|
413
|
+
].join("\n");
|
|
414
|
+
}
|
|
415
|
+
async function should_load_hooks_config(cwd, ctx) {
|
|
416
|
+
const info = get_hooks_config_info(cwd);
|
|
417
|
+
if (!info) return true;
|
|
418
|
+
if (is_hooks_config_trusted(info.project_dir, info.hash)) return true;
|
|
419
|
+
const env_decision = normalize_hooks_config_decision(process.env[HOOKS_CONFIG_ENV]);
|
|
420
|
+
if (env_decision === "trust") {
|
|
421
|
+
trust_hooks_config(info.project_dir, info.hash);
|
|
422
|
+
return true;
|
|
423
|
+
}
|
|
424
|
+
if (env_decision === "allow") return true;
|
|
425
|
+
if (env_decision === "skip") return false;
|
|
426
|
+
if (!ctx?.hasUI) {
|
|
427
|
+
console.warn(`Skipping untrusted hook config in ${info.project_dir}. Set ${HOOKS_CONFIG_ENV}=allow to enable hooks for this run.`);
|
|
428
|
+
return false;
|
|
429
|
+
}
|
|
430
|
+
const choice = await ctx.ui.select(format_hooks_config_prompt(info), [
|
|
431
|
+
"Allow once for this session",
|
|
432
|
+
"Trust this repo until hook config changes",
|
|
433
|
+
"Skip project hooks"
|
|
434
|
+
]);
|
|
435
|
+
if (choice === "Trust this repo until hook config changes") {
|
|
436
|
+
trust_hooks_config(info.project_dir, info.hash);
|
|
437
|
+
return true;
|
|
438
|
+
}
|
|
439
|
+
return choice === "Allow once for this session";
|
|
440
|
+
}
|
|
287
441
|
function create_hooks_resolution_extension(options = {}) {
|
|
288
442
|
const load_hooks_impl = options.load_hooks ?? load_hooks;
|
|
289
443
|
const run_command_hook_impl = options.run_command_hook ?? run_command_hook;
|
|
@@ -292,11 +446,18 @@ function create_hooks_resolution_extension(options = {}) {
|
|
|
292
446
|
project_dir: process.cwd(),
|
|
293
447
|
hooks: []
|
|
294
448
|
};
|
|
295
|
-
const refresh_hooks = (cwd) => {
|
|
449
|
+
const refresh_hooks = async (cwd, ctx) => {
|
|
450
|
+
if (!await should_load_hooks_config(cwd, ctx)) {
|
|
451
|
+
state = {
|
|
452
|
+
project_dir: cwd,
|
|
453
|
+
hooks: []
|
|
454
|
+
};
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
296
457
|
state = load_hooks_impl(cwd);
|
|
297
458
|
};
|
|
298
|
-
pi.on("session_start", (_event, ctx) => {
|
|
299
|
-
refresh_hooks(ctx.cwd);
|
|
459
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
460
|
+
await refresh_hooks(ctx.cwd, ctx);
|
|
300
461
|
});
|
|
301
462
|
pi.on("tool_result", async (event, ctx) => {
|
|
302
463
|
if (state.hooks.length === 0) return;
|
|
@@ -706,6 +867,7 @@ function create_extensions_extension(options = {}) {
|
|
|
706
867
|
create_extensions_extension();
|
|
707
868
|
//#endregion
|
|
708
869
|
//#region src/extensions/prompt-presets/index.ts
|
|
870
|
+
const PROJECT_PROMPT_PRESETS_ENV = "MY_PI_PROMPT_PRESETS_PROJECT";
|
|
709
871
|
const PRESET_STATE_TYPE = "prompt-preset-state";
|
|
710
872
|
const ENABLED = "[x]";
|
|
711
873
|
const DISABLED = "[ ]";
|
|
@@ -891,8 +1053,18 @@ function save_project_prompt_preset_file(cwd, name, preset) {
|
|
|
891
1053
|
function save_global_prompt_preset_file(name, preset) {
|
|
892
1054
|
return save_prompt_preset_file(get_global_presets_dir(), name, preset);
|
|
893
1055
|
}
|
|
1056
|
+
function should_load_project_prompt_presets() {
|
|
1057
|
+
const normalized = process.env[PROJECT_PROMPT_PRESETS_ENV]?.trim().toLowerCase();
|
|
1058
|
+
return ![
|
|
1059
|
+
"0",
|
|
1060
|
+
"false",
|
|
1061
|
+
"no",
|
|
1062
|
+
"skip",
|
|
1063
|
+
"disable"
|
|
1064
|
+
].includes(normalized ?? "");
|
|
1065
|
+
}
|
|
894
1066
|
function load_prompt_presets(cwd) {
|
|
895
|
-
return Object.assign({}, to_loaded_prompt_presets(DEFAULT_PROMPT_PRESETS, "builtin"), to_loaded_prompt_presets(read_prompt_presets_file(get_global_presets_path()), "user"), to_loaded_prompt_presets(read_prompt_presets_dir(get_global_presets_dir()), "user"), to_loaded_prompt_presets(read_prompt_presets_file(get_project_presets_path(cwd)), "project"), to_loaded_prompt_presets(read_prompt_presets_dir(get_project_presets_dir(cwd)), "project"));
|
|
1067
|
+
return Object.assign({}, to_loaded_prompt_presets(DEFAULT_PROMPT_PRESETS, "builtin"), to_loaded_prompt_presets(read_prompt_presets_file(get_global_presets_path()), "user"), to_loaded_prompt_presets(read_prompt_presets_dir(get_global_presets_dir()), "user"), ...should_load_project_prompt_presets() ? [to_loaded_prompt_presets(read_prompt_presets_file(get_project_presets_path(cwd)), "project"), to_loaded_prompt_presets(read_prompt_presets_dir(get_project_presets_dir(cwd)), "project")] : []);
|
|
896
1068
|
}
|
|
897
1069
|
function sort_prompt_presets(presets) {
|
|
898
1070
|
return Object.fromEntries(Object.entries(presets).sort(([a], [b]) => a.localeCompare(b)));
|
|
@@ -1843,6 +2015,44 @@ const BUILTIN_EXTENSION_FACTORIES = {
|
|
|
1843
2015
|
};
|
|
1844
2016
|
const PACKAGE_THEME_DIR = resolve(dirname(fileURLToPath(import.meta.url)), "..", "themes");
|
|
1845
2017
|
const PI_AGENT_DIR_ENV = "PI_CODING_AGENT_DIR";
|
|
2018
|
+
const UNTRUSTED_REPO_ENV_DEFAULTS = {
|
|
2019
|
+
MY_PI_MCP_PROJECT_CONFIG: "skip",
|
|
2020
|
+
MY_PI_HOOKS_CONFIG: "skip",
|
|
2021
|
+
MY_PI_LSP_PROJECT_BINARY: "global",
|
|
2022
|
+
MY_PI_PROMPT_PRESETS_PROJECT: "skip",
|
|
2023
|
+
MY_PI_PROJECT_SKILLS: "skip",
|
|
2024
|
+
MY_PI_CHILD_ENV_ALLOWLIST: "",
|
|
2025
|
+
MY_PI_MCP_ENV_ALLOWLIST: "",
|
|
2026
|
+
MY_PI_HOOKS_ENV_ALLOWLIST: ""
|
|
2027
|
+
};
|
|
2028
|
+
function apply_untrusted_repo_defaults(env = process.env) {
|
|
2029
|
+
const applied = [];
|
|
2030
|
+
for (const [key, value] of Object.entries(UNTRUSTED_REPO_ENV_DEFAULTS)) {
|
|
2031
|
+
if (env[key] !== void 0) continue;
|
|
2032
|
+
env[key] = value;
|
|
2033
|
+
applied.push(key);
|
|
2034
|
+
}
|
|
2035
|
+
return applied;
|
|
2036
|
+
}
|
|
2037
|
+
function is_resource_enabled(value) {
|
|
2038
|
+
const normalized = value?.trim().toLowerCase();
|
|
2039
|
+
if (!normalized) return true;
|
|
2040
|
+
if ([
|
|
2041
|
+
"0",
|
|
2042
|
+
"false",
|
|
2043
|
+
"no",
|
|
2044
|
+
"skip",
|
|
2045
|
+
"disable"
|
|
2046
|
+
].includes(normalized)) return false;
|
|
2047
|
+
return true;
|
|
2048
|
+
}
|
|
2049
|
+
function is_project_local_skill_path(cwd, file_path) {
|
|
2050
|
+
if (!file_path) return false;
|
|
2051
|
+
const relative_path = relative(cwd, resolve(cwd, file_path));
|
|
2052
|
+
if (!relative_path || relative_path.startsWith("..") || isAbsolute(relative_path)) return false;
|
|
2053
|
+
const parts = relative_path.split(/[\\/]+/);
|
|
2054
|
+
return parts.some((part, index) => (part === ".pi" || part === ".claude") && parts[index + 1] === "skills");
|
|
2055
|
+
}
|
|
1846
2056
|
function resolve_agent_dir(cwd, agent_dir) {
|
|
1847
2057
|
return agent_dir ? resolve(cwd, agent_dir) : getAgentDir();
|
|
1848
2058
|
}
|
|
@@ -1883,7 +2093,8 @@ function create_extensions_override(managed_inline_paths) {
|
|
|
1883
2093
|
};
|
|
1884
2094
|
}
|
|
1885
2095
|
async function create_my_pi(options = {}) {
|
|
1886
|
-
const { cwd = process.cwd(), agent_dir, extensions = [], extensionFactories: user_factories = [], runtime_mode = "interactive", mcp = true, skills = true, filter_output = true, recall = true, nopeek = true, omnisearch = true, sqlite_tools = true, prompt_presets = true, lsp = true, session_name = true, confirm_destructive = true, hooks_resolution = true, telemetry, telemetry_db_path, model, system_prompt, append_system_prompt } = options;
|
|
2096
|
+
const { cwd = process.cwd(), agent_dir, extensions = [], extensionFactories: user_factories = [], runtime_mode = "interactive", mcp = true, skills = true, filter_output = true, recall = true, nopeek = true, omnisearch = true, sqlite_tools = true, prompt_presets = true, lsp = true, session_name = true, confirm_destructive = true, hooks_resolution = true, telemetry, telemetry_db_path, model, system_prompt, append_system_prompt, untrusted_repo = false } = options;
|
|
2097
|
+
if (untrusted_repo) apply_untrusted_repo_defaults();
|
|
1887
2098
|
const effective_agent_dir = resolve_agent_dir(cwd, agent_dir);
|
|
1888
2099
|
if (agent_dir) process.env[PI_AGENT_DIR_ENV] = effective_agent_dir;
|
|
1889
2100
|
const resolved_extensions = extensions.map((p) => resolve(cwd, p));
|
|
@@ -1931,10 +2142,14 @@ async function create_my_pi(options = {}) {
|
|
|
1931
2142
|
extensionsOverride: create_extensions_override(managed_inline_paths),
|
|
1932
2143
|
skillsOverride: (base) => {
|
|
1933
2144
|
if (!is_builtin_extension_active(load_builtin_extensions_config(), "skills", force_disabled)) return base;
|
|
2145
|
+
const include_project_skills = is_resource_enabled(process.env.MY_PI_PROJECT_SKILLS);
|
|
1934
2146
|
const skills_manager = create_skills_manager();
|
|
1935
2147
|
return {
|
|
1936
2148
|
...base,
|
|
1937
|
-
skills: base.skills.filter((skill) =>
|
|
2149
|
+
skills: base.skills.filter((skill) => {
|
|
2150
|
+
if (!include_project_skills && is_project_local_skill_path(runtime_cwd, skill.filePath)) return false;
|
|
2151
|
+
return skills_manager.is_enabled_by_skill(skill.name, skill.filePath);
|
|
2152
|
+
})
|
|
1938
2153
|
};
|
|
1939
2154
|
}
|
|
1940
2155
|
}
|
|
@@ -1956,6 +2171,6 @@ async function create_my_pi(options = {}) {
|
|
|
1956
2171
|
});
|
|
1957
2172
|
}
|
|
1958
2173
|
//#endregion
|
|
1959
|
-
export {
|
|
2174
|
+
export { is_project_local_skill_path as a, get_force_disabled_builtins as i, apply_untrusted_repo_defaults as n, runPrintMode$1 as o, create_my_pi as r, InteractiveMode$1 as t };
|
|
1960
2175
|
|
|
1961
|
-
//# sourceMappingURL=api-
|
|
2176
|
+
//# sourceMappingURL=api-Eq36fWnN.js.map
|