my-pi 0.1.0 → 0.1.1

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 CHANGED
@@ -321,6 +321,8 @@ In interactive mode:
321
321
  - `/extensions` — open the built-in extensions manager
322
322
  - `/extensions list` — print built-in extensions with saved/effective
323
323
  state
324
+ - `/extensions enable|disable|toggle` — without a key, open the
325
+ interactive toggle list
324
326
  - `/extensions enable <key>` / `/extensions disable <key>` — toggle a
325
327
  built-in extension
326
328
  - `/skills` — open the interactive skills manager (unified list with
@@ -420,6 +420,20 @@ const BUILTIN_EXTENSIONS = [
420
420
  "session",
421
421
  "auto-name"
422
422
  ]
423
+ },
424
+ {
425
+ key: "confirm-destructive",
426
+ label: "Confirm destructive",
427
+ description: "Prompt before destructive session actions like clear, switch, and fork",
428
+ cli_flag: "--no-confirm-destructive",
429
+ aliases: ["confirm-destructive", "confirm"]
430
+ },
431
+ {
432
+ key: "hooks-resolution",
433
+ label: "Hooks resolution",
434
+ description: "Claude Code style PostToolUse hook compatibility from .claude, .rulesync, and .pi configs",
435
+ cli_flag: "--no-hooks",
436
+ aliases: ["hooks-resolution", "hooks"]
423
437
  }
424
438
  ];
425
439
  function get_builtin_extensions_config_path() {
@@ -483,6 +497,33 @@ function find_builtin_extension(query) {
483
497
  ].some((value) => value.toLowerCase() === normalized));
484
498
  }
485
499
  //#endregion
500
+ //#region src/extensions/confirm-destructive.ts
501
+ async function confirm_destructive(pi) {
502
+ pi.on("session_before_switch", async (event, ctx) => {
503
+ if (!ctx.hasUI) return;
504
+ if (event.reason === "new") {
505
+ if (!await ctx.ui.confirm("Clear session?", "This will delete all messages in the current session.")) {
506
+ ctx.ui.notify("Clear cancelled", "info");
507
+ return { cancel: true };
508
+ }
509
+ return;
510
+ }
511
+ if (ctx.sessionManager.getEntries().some((e) => e.type === "message" && e.message.role === "user")) {
512
+ if (!await ctx.ui.confirm("Switch session?", "You have messages in the current session. Switch anyway?")) {
513
+ ctx.ui.notify("Switch cancelled", "info");
514
+ return { cancel: true };
515
+ }
516
+ }
517
+ });
518
+ pi.on("session_before_fork", async (event, ctx) => {
519
+ if (!ctx.hasUI) return;
520
+ if (await ctx.ui.select(`Fork from entry ${event.entryId.slice(0, 8)}?`, ["Yes, create fork", "No, stay in current session"]) !== "Yes, create fork") {
521
+ ctx.ui.notify("Fork cancelled", "info");
522
+ return { cancel: true };
523
+ }
524
+ });
525
+ }
526
+ //#endregion
486
527
  //#region src/extensions/extensions.ts
487
528
  const ENABLED$2 = "[x]";
488
529
  const DISABLED$2 = "[ ]";
@@ -546,6 +587,66 @@ function save_extension_enabled(key, enabled) {
546
587
  }
547
588
  function create_extensions_extension(options = {}) {
548
589
  const force_disabled = to_force_disabled_set(options.force_disabled);
590
+ async function show_manager(ctx) {
591
+ if (!ctx.hasUI) return false;
592
+ const states = resolve_builtin_extension_states(force_disabled);
593
+ const initial_enabled = new Set(states.filter((state) => state.saved_enabled).map((state) => state.key));
594
+ const current_enabled = new Set(initial_enabled);
595
+ await ctx.ui.custom((tui, theme, _kb, done) => {
596
+ const items = states.map(to_setting_item$1);
597
+ const container = new Container();
598
+ container.addChild({
599
+ render: () => {
600
+ const saved_enabled = current_enabled.size;
601
+ const saved_disabled = states.length - saved_enabled;
602
+ const enabled_now = [...current_enabled].filter((key) => !force_disabled.has(key)).length;
603
+ const disabled_now = states.length - enabled_now;
604
+ return [
605
+ theme.fg("accent", theme.bold("Built-in extensions")),
606
+ theme.fg("muted", `${saved_enabled} saved enabled • ${saved_disabled} saved disabled • ${enabled_now} enabled now • ${disabled_now} disabled now`),
607
+ ""
608
+ ];
609
+ },
610
+ invalidate: () => {}
611
+ });
612
+ const settings_list = new SettingsList(items, Math.min(Math.max(items.length + 4, 8), 16), {
613
+ cursor: theme.fg("accent", "›"),
614
+ label: (text, selected) => selected ? theme.fg("accent", text) : text,
615
+ value: (text, selected) => {
616
+ const color = text === ENABLED$2 ? "success" : "dim";
617
+ const rendered = theme.fg(color, text);
618
+ return selected ? theme.bold(theme.fg("accent", rendered)) : rendered;
619
+ },
620
+ description: (text) => theme.fg("muted", text),
621
+ hint: (text) => theme.fg("dim", text)
622
+ }, (id, new_value) => {
623
+ const key = id;
624
+ const enabled = new_value === ENABLED$2;
625
+ if (enabled) current_enabled.add(key);
626
+ else current_enabled.delete(key);
627
+ save_extension_enabled(key, enabled);
628
+ }, () => done(void 0), { enableSearch: true });
629
+ container.addChild(settings_list);
630
+ container.addChild(new Text(theme.fg("dim", "esc close • search filters • changes save immediately • CLI --no-* flags still win in this process"), 0, 1));
631
+ return {
632
+ render(width) {
633
+ return container.render(width);
634
+ },
635
+ invalidate() {
636
+ container.invalidate();
637
+ },
638
+ handleInput(data) {
639
+ settings_list.handleInput(data);
640
+ tui.requestRender();
641
+ }
642
+ };
643
+ });
644
+ if (!sets_equal$2(initial_enabled, current_enabled)) {
645
+ ctx.ui.notify(force_disabled.size > 0 ? "Reloading to apply updated built-in extensions. CLI --no-* flags still force-disable some extensions in this process." : "Reloading to apply updated built-in extensions...", "info");
646
+ await ctx.reload();
647
+ }
648
+ return true;
649
+ }
549
650
  return async function extensions(pi) {
550
651
  const subs = [
551
652
  "list",
@@ -577,65 +678,8 @@ function create_extensions_extension(options = {}) {
577
678
  },
578
679
  handler: async (args, ctx) => {
579
680
  const trimmed = args.trim();
580
- if (!trimmed && ctx.hasUI) {
581
- const states = resolve_builtin_extension_states(force_disabled);
582
- const initial_enabled = new Set(states.filter((state) => state.saved_enabled).map((state) => state.key));
583
- const current_enabled = new Set(initial_enabled);
584
- await ctx.ui.custom((tui, theme, _kb, done) => {
585
- const items = states.map(to_setting_item$1);
586
- const container = new Container();
587
- container.addChild({
588
- render: () => {
589
- const saved_enabled = current_enabled.size;
590
- const saved_disabled = states.length - saved_enabled;
591
- const enabled_now = [...current_enabled].filter((key) => !force_disabled.has(key)).length;
592
- const disabled_now = states.length - enabled_now;
593
- return [
594
- theme.fg("accent", theme.bold("Built-in extensions")),
595
- theme.fg("muted", `${saved_enabled} saved enabled • ${saved_disabled} saved disabled • ${enabled_now} enabled now • ${disabled_now} disabled now`),
596
- ""
597
- ];
598
- },
599
- invalidate: () => {}
600
- });
601
- const settings_list = new SettingsList(items, Math.min(Math.max(items.length + 4, 8), 16), {
602
- cursor: theme.fg("accent", "›"),
603
- label: (text, selected) => selected ? theme.fg("accent", text) : text,
604
- value: (text, selected) => {
605
- const color = text === ENABLED$2 ? "success" : "dim";
606
- const rendered = theme.fg(color, text);
607
- return selected ? theme.bold(theme.fg("accent", rendered)) : rendered;
608
- },
609
- description: (text) => theme.fg("muted", text),
610
- hint: (text) => theme.fg("dim", text)
611
- }, (id, new_value) => {
612
- const key = id;
613
- const enabled = new_value === ENABLED$2;
614
- if (enabled) current_enabled.add(key);
615
- else current_enabled.delete(key);
616
- save_extension_enabled(key, enabled);
617
- }, () => done(void 0), { enableSearch: true });
618
- container.addChild(settings_list);
619
- container.addChild(new Text(theme.fg("dim", "esc close • search filters • changes save immediately • CLI --no-* flags still win in this process"), 0, 1));
620
- return {
621
- render(width) {
622
- return container.render(width);
623
- },
624
- invalidate() {
625
- container.invalidate();
626
- },
627
- handleInput(data) {
628
- settings_list.handleInput(data);
629
- tui.requestRender();
630
- }
631
- };
632
- });
633
- if (!sets_equal$2(initial_enabled, current_enabled)) {
634
- ctx.ui.notify(force_disabled.size > 0 ? "Reloading to apply updated built-in extensions. CLI --no-* flags still force-disable some extensions in this process." : "Reloading to apply updated built-in extensions...", "info");
635
- await ctx.reload();
636
- return;
637
- }
638
- return;
681
+ if (!trimmed) {
682
+ if (await show_manager(ctx)) return;
639
683
  }
640
684
  const [sub, ...rest] = (trimmed || "list").split(/\s+/);
641
685
  const arg = rest.join(" ");
@@ -648,6 +692,7 @@ function create_extensions_extension(options = {}) {
648
692
  case "disable":
649
693
  case "toggle": {
650
694
  if (!arg) {
695
+ if (await show_manager(ctx)) return;
651
696
  ctx.ui.notify(`Usage: /extensions ${sub} <key>`, "warning");
652
697
  return;
653
698
  }
@@ -896,6 +941,312 @@ async function handoff(pi) {
896
941
  });
897
942
  }
898
943
  //#endregion
944
+ //#region src/extensions/hooks-resolution.ts
945
+ const HOOK_TIMEOUT_MS = 600 * 1e3;
946
+ function is_file(path) {
947
+ try {
948
+ return statSync(path).isFile();
949
+ } catch {
950
+ return false;
951
+ }
952
+ }
953
+ function as_record(value) {
954
+ if (typeof value !== "object" || value === null) return void 0;
955
+ return value;
956
+ }
957
+ function walk_up_directories(start_dir, stop_dir) {
958
+ const directories = [];
959
+ const has_stop_dir = stop_dir !== void 0;
960
+ let current = resolve(start_dir);
961
+ let parent = dirname(current);
962
+ let reached_stop_dir = has_stop_dir && current === stop_dir;
963
+ let reached_filesystem_root = parent === current;
964
+ directories.push(current);
965
+ while (!reached_stop_dir && !reached_filesystem_root) {
966
+ current = parent;
967
+ parent = dirname(current);
968
+ reached_stop_dir = has_stop_dir && current === stop_dir;
969
+ reached_filesystem_root = parent === current;
970
+ directories.push(current);
971
+ }
972
+ return directories;
973
+ }
974
+ function find_nearest_git_root(start_dir) {
975
+ for (const directory of walk_up_directories(start_dir)) if (existsSync(join(directory, ".git"))) return directory;
976
+ }
977
+ function has_hooks_config(directory) {
978
+ return is_file(join(directory, ".claude", "settings.json")) || is_file(join(directory, ".rulesync", "hooks.json")) || is_file(join(directory, ".pi", "hooks.json"));
979
+ }
980
+ function find_project_dir(cwd) {
981
+ const git_root = find_nearest_git_root(cwd);
982
+ for (const directory of walk_up_directories(cwd, git_root)) if (has_hooks_config(directory)) return directory;
983
+ return git_root ?? resolve(cwd);
984
+ }
985
+ function read_json_file(path) {
986
+ if (!is_file(path)) return void 0;
987
+ try {
988
+ return JSON.parse(readFileSync(path, "utf8"));
989
+ } catch {
990
+ return;
991
+ }
992
+ }
993
+ function resolve_hook_command(command, project_dir) {
994
+ return command.replace(/\$CLAUDE_PROJECT_DIR\b/g, project_dir);
995
+ }
996
+ function compile_matcher(matcher_text) {
997
+ if (matcher_text === void 0) return void 0;
998
+ try {
999
+ return new RegExp(matcher_text);
1000
+ } catch {
1001
+ return;
1002
+ }
1003
+ }
1004
+ function create_hook(event_name, matcher_text, command, source, project_dir) {
1005
+ const matcher = compile_matcher(matcher_text);
1006
+ if (matcher_text !== void 0 && matcher === void 0) return void 0;
1007
+ return {
1008
+ event_name,
1009
+ matcher,
1010
+ matcher_text,
1011
+ command: resolve_hook_command(command, project_dir),
1012
+ source
1013
+ };
1014
+ }
1015
+ function get_hook_entries(hooks_record, event_name) {
1016
+ const keys = event_name === "PostToolUse" ? ["PostToolUse", "postToolUse"] : ["PostToolUseFailure", "postToolUseFailure"];
1017
+ for (const key of keys) {
1018
+ const value = hooks_record[key];
1019
+ if (Array.isArray(value)) return value;
1020
+ }
1021
+ return [];
1022
+ }
1023
+ function parse_claude_settings_hooks(config, source, project_dir) {
1024
+ const root = as_record(config);
1025
+ const hooks_root = root ? as_record(root.hooks) : void 0;
1026
+ if (!hooks_root) return [];
1027
+ const hooks = [];
1028
+ for (const event_name of ["PostToolUse", "PostToolUseFailure"]) {
1029
+ const entries = get_hook_entries(hooks_root, event_name);
1030
+ for (const entry of entries) {
1031
+ const entry_record = as_record(entry);
1032
+ if (!entry_record || !Array.isArray(entry_record.hooks)) continue;
1033
+ const matcher_text = typeof entry_record.matcher === "string" ? entry_record.matcher : void 0;
1034
+ for (const nested_hook of entry_record.hooks) {
1035
+ const nested_record = as_record(nested_hook);
1036
+ if (!nested_record) continue;
1037
+ if (nested_record.type !== "command") continue;
1038
+ if (typeof nested_record.command !== "string") continue;
1039
+ const hook = create_hook(event_name, matcher_text, nested_record.command, source, project_dir);
1040
+ if (hook) hooks.push(hook);
1041
+ }
1042
+ }
1043
+ }
1044
+ return hooks;
1045
+ }
1046
+ function parse_simple_hooks_file(config, source, project_dir) {
1047
+ const root = as_record(config);
1048
+ const hooks_root = root ? as_record(root.hooks) : void 0;
1049
+ if (!hooks_root) return [];
1050
+ const hooks = [];
1051
+ for (const event_name of ["PostToolUse", "PostToolUseFailure"]) {
1052
+ const entries = get_hook_entries(hooks_root, event_name);
1053
+ for (const entry of entries) {
1054
+ const entry_record = as_record(entry);
1055
+ if (!entry_record || typeof entry_record.command !== "string") continue;
1056
+ const hook = create_hook(event_name, typeof entry_record.matcher === "string" ? entry_record.matcher : void 0, entry_record.command, source, project_dir);
1057
+ if (hook) hooks.push(hook);
1058
+ }
1059
+ }
1060
+ return hooks;
1061
+ }
1062
+ function load_hooks(cwd) {
1063
+ const project_dir = find_project_dir(cwd);
1064
+ const hooks = [];
1065
+ const claude_settings_path = join(project_dir, ".claude", "settings.json");
1066
+ const rulesync_hooks_path = join(project_dir, ".rulesync", "hooks.json");
1067
+ const pi_hooks_path = join(project_dir, ".pi", "hooks.json");
1068
+ const claude_settings = read_json_file(claude_settings_path);
1069
+ if (claude_settings !== void 0) hooks.push(...parse_claude_settings_hooks(claude_settings, claude_settings_path, project_dir));
1070
+ const rulesync_hooks = read_json_file(rulesync_hooks_path);
1071
+ if (rulesync_hooks !== void 0) hooks.push(...parse_simple_hooks_file(rulesync_hooks, rulesync_hooks_path, project_dir));
1072
+ const pi_hooks = read_json_file(pi_hooks_path);
1073
+ if (pi_hooks !== void 0) hooks.push(...parse_simple_hooks_file(pi_hooks, pi_hooks_path, project_dir));
1074
+ return {
1075
+ project_dir,
1076
+ hooks
1077
+ };
1078
+ }
1079
+ function to_claude_tool_name(tool_name) {
1080
+ if (tool_name === "ls") return "LS";
1081
+ if (tool_name.length === 0) return tool_name;
1082
+ return tool_name[0].toUpperCase() + tool_name.slice(1);
1083
+ }
1084
+ function matches_hook(hook, tool_name) {
1085
+ if (!hook.matcher) return true;
1086
+ const claude_tool_name = to_claude_tool_name(tool_name);
1087
+ hook.matcher.lastIndex = 0;
1088
+ if (hook.matcher.test(tool_name)) return true;
1089
+ hook.matcher.lastIndex = 0;
1090
+ return hook.matcher.test(claude_tool_name);
1091
+ }
1092
+ function extract_text_content(content) {
1093
+ if (!Array.isArray(content)) return "";
1094
+ const parts = [];
1095
+ for (const item of content) {
1096
+ if (!item || typeof item !== "object") continue;
1097
+ const item_record = item;
1098
+ if (item_record.type === "text" && typeof item_record.text === "string") parts.push(item_record.text);
1099
+ }
1100
+ return parts.join("\n");
1101
+ }
1102
+ function normalize_tool_input(input) {
1103
+ const normalized = { ...input };
1104
+ const path_value = typeof input.path === "string" ? input.path : void 0;
1105
+ if (path_value !== void 0) {
1106
+ normalized.file_path = path_value;
1107
+ normalized.filePath = path_value;
1108
+ }
1109
+ return normalized;
1110
+ }
1111
+ function build_tool_response(event, normalized_input) {
1112
+ const response = {
1113
+ is_error: event.isError,
1114
+ isError: event.isError,
1115
+ content: event.content,
1116
+ text: extract_text_content(event.content),
1117
+ details: event.details ?? null
1118
+ };
1119
+ const file_path = typeof normalized_input.file_path === "string" ? normalized_input.file_path : void 0;
1120
+ if (file_path !== void 0) {
1121
+ response.file_path = file_path;
1122
+ response.filePath = file_path;
1123
+ }
1124
+ return response;
1125
+ }
1126
+ function build_hook_payload(event, event_name, ctx, project_dir) {
1127
+ const normalized_input = normalize_tool_input(event.input);
1128
+ return {
1129
+ session_id: ctx.sessionManager.getSessionFile() ?? "ephemeral",
1130
+ cwd: ctx.cwd,
1131
+ claude_project_dir: project_dir,
1132
+ hook_event_name: event_name,
1133
+ tool_name: to_claude_tool_name(event.toolName),
1134
+ tool_call_id: event.toolCallId,
1135
+ tool_input: normalized_input,
1136
+ tool_response: build_tool_response(event, normalized_input)
1137
+ };
1138
+ }
1139
+ async function run_command_hook(command, cwd, payload) {
1140
+ return await new Promise((resolve) => {
1141
+ const started_at = Date.now();
1142
+ const child = spawn("bash", ["-lc", command], {
1143
+ cwd,
1144
+ env: {
1145
+ ...process.env,
1146
+ CLAUDE_PROJECT_DIR: cwd
1147
+ },
1148
+ stdio: [
1149
+ "pipe",
1150
+ "pipe",
1151
+ "pipe"
1152
+ ]
1153
+ });
1154
+ let stdout = "";
1155
+ let stderr = "";
1156
+ let timed_out = false;
1157
+ let resolved = false;
1158
+ const finish = (code) => {
1159
+ if (resolved) return;
1160
+ resolved = true;
1161
+ resolve({
1162
+ code,
1163
+ stdout,
1164
+ stderr,
1165
+ elapsed_ms: Date.now() - started_at,
1166
+ timed_out
1167
+ });
1168
+ };
1169
+ const timeout = setTimeout(() => {
1170
+ timed_out = true;
1171
+ child.kill("SIGTERM");
1172
+ setTimeout(() => {
1173
+ child.kill("SIGKILL");
1174
+ }, 1e3).unref?.();
1175
+ }, HOOK_TIMEOUT_MS);
1176
+ timeout.unref?.();
1177
+ child.stdout.on("data", (chunk) => {
1178
+ stdout += chunk.toString("utf8");
1179
+ });
1180
+ child.stderr.on("data", (chunk) => {
1181
+ stderr += chunk.toString("utf8");
1182
+ });
1183
+ child.on("error", (error) => {
1184
+ clearTimeout(timeout);
1185
+ stderr += `${error.message}\n`;
1186
+ finish(-1);
1187
+ });
1188
+ child.on("close", (code) => {
1189
+ clearTimeout(timeout);
1190
+ finish(code ?? -1);
1191
+ });
1192
+ try {
1193
+ child.stdin.write(JSON.stringify(payload));
1194
+ child.stdin.end();
1195
+ } catch (error) {
1196
+ stderr += `${error instanceof Error ? error.message : String(error)}\n`;
1197
+ }
1198
+ });
1199
+ }
1200
+ function hook_event_name_for_result(event) {
1201
+ return event.isError ? "PostToolUseFailure" : "PostToolUse";
1202
+ }
1203
+ function format_duration$1(elapsed_ms) {
1204
+ if (elapsed_ms < 1e3) return `${elapsed_ms}ms`;
1205
+ return `${(elapsed_ms / 1e3).toFixed(1)}s`;
1206
+ }
1207
+ function hook_name(command) {
1208
+ const sh_path_match = command.match(/[^\s|;&]+\.sh\b/);
1209
+ if (sh_path_match) return basename(sh_path_match[0]);
1210
+ return basename(command.trim().split(/\s+/)[0] ?? "hook");
1211
+ }
1212
+ function create_hooks_resolution_extension(options = {}) {
1213
+ const load_hooks_impl = options.load_hooks ?? load_hooks;
1214
+ const run_command_hook_impl = options.run_command_hook ?? run_command_hook;
1215
+ return async function hooks_resolution(pi) {
1216
+ let state = {
1217
+ project_dir: process.cwd(),
1218
+ hooks: []
1219
+ };
1220
+ const refresh_hooks = (cwd) => {
1221
+ state = load_hooks_impl(cwd);
1222
+ };
1223
+ pi.on("session_start", (_event, ctx) => {
1224
+ refresh_hooks(ctx.cwd);
1225
+ });
1226
+ pi.on("tool_result", async (event, ctx) => {
1227
+ if (state.hooks.length === 0) return;
1228
+ const event_name = hook_event_name_for_result(event);
1229
+ const matching_hooks = state.hooks.filter((hook) => hook.event_name === event_name && matches_hook(hook, event.toolName));
1230
+ if (matching_hooks.length === 0) return;
1231
+ const payload = build_hook_payload(event, event_name, ctx, state.project_dir);
1232
+ const executed_commands = /* @__PURE__ */ new Set();
1233
+ for (const hook of matching_hooks) {
1234
+ if (executed_commands.has(hook.command)) continue;
1235
+ executed_commands.add(hook.command);
1236
+ const result = await run_command_hook_impl(hook.command, state.project_dir, payload);
1237
+ const name = hook_name(hook.command);
1238
+ const duration = format_duration$1(result.elapsed_ms);
1239
+ if (ctx.hasUI) if (result.code === 0) ctx.ui.notify(`Hook \`${name}\` ran (${duration})`, "info");
1240
+ else {
1241
+ const error_line = result.stderr.trim() || result.stdout.trim() || `exit code ${result.code}`;
1242
+ ctx.ui.notify(`Hook \`${name}\` failed (${duration}): ${error_line}`, "warning");
1243
+ }
1244
+ }
1245
+ });
1246
+ };
1247
+ }
1248
+ var hooks_resolution_default = create_hooks_resolution_extension();
1249
+ //#endregion
899
1250
  //#region src/lsp/client.ts
900
1251
  var LspClientStartError = class extends Error {
901
1252
  command;
@@ -4658,7 +5009,9 @@ const BUILTIN_EXTENSION_FACTORIES = {
4658
5009
  recall,
4659
5010
  "prompt-presets": prompt_presets,
4660
5011
  lsp: lsp_default,
4661
- "session-name": session_name
5012
+ "session-name": session_name,
5013
+ "confirm-destructive": confirm_destructive,
5014
+ "hooks-resolution": hooks_resolution_default
4662
5015
  };
4663
5016
  const PACKAGE_THEME_DIR = resolve(dirname(fileURLToPath(import.meta.url)), "..", "themes");
4664
5017
  const PI_AGENT_DIR_ENV = "PI_CODING_AGENT_DIR";
@@ -4676,6 +5029,8 @@ function get_force_disabled_builtins(options) {
4676
5029
  if (!options.prompt_presets) force_disabled.add("prompt-presets");
4677
5030
  if (!options.lsp) force_disabled.add("lsp");
4678
5031
  if (!options.session_name) force_disabled.add("session-name");
5032
+ if (!options.confirm_destructive) force_disabled.add("confirm-destructive");
5033
+ if (!options.hooks_resolution) force_disabled.add("hooks-resolution");
4679
5034
  return force_disabled;
4680
5035
  }
4681
5036
  function create_builtin_extension_factory(key, extension, force_disabled) {
@@ -4697,7 +5052,7 @@ function create_extensions_override(managed_inline_paths) {
4697
5052
  };
4698
5053
  }
4699
5054
  async function create_my_pi(options = {}) {
4700
- const { cwd = process.cwd(), agent_dir, extensions = [], extensionFactories: user_factories = [], mcp = true, skills = true, chain = true, filter_output = true, handoff = true, recall = true, prompt_presets = true, lsp = true, session_name = true, telemetry, telemetry_db_path, model, system_prompt, append_system_prompt } = options;
5055
+ const { cwd = process.cwd(), agent_dir, extensions = [], extensionFactories: user_factories = [], mcp = true, skills = true, chain = true, filter_output = true, handoff = true, recall = 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;
4701
5056
  const effective_agent_dir = resolve_agent_dir(cwd, agent_dir);
4702
5057
  if (agent_dir) process.env[PI_AGENT_DIR_ENV] = effective_agent_dir;
4703
5058
  const resolved_extensions = extensions.map((p) => resolve(cwd, p));
@@ -4710,7 +5065,9 @@ async function create_my_pi(options = {}) {
4710
5065
  recall,
4711
5066
  prompt_presets,
4712
5067
  lsp,
4713
- session_name
5068
+ session_name,
5069
+ confirm_destructive,
5070
+ hooks_resolution
4714
5071
  });
4715
5072
  const managed_extension_factories = [
4716
5073
  create_telemetry_extension({
@@ -4768,4 +5125,4 @@ async function create_my_pi(options = {}) {
4768
5125
  //#endregion
4769
5126
  export { create_my_pi as n, runPrintMode$1 as r, InteractiveMode$1 as t };
4770
5127
 
4771
- //# sourceMappingURL=api-1ZXLxSgP.js.map
5128
+ //# sourceMappingURL=api-Dxi4curf.js.map