my-pi 0.1.3 → 0.1.5

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
@@ -81,6 +81,12 @@ echo "plan a login page" | pnpx my-pi@latest --json
81
81
  Outputs NDJSON events — one JSON object per line — for programmatic
82
82
  consumption by other agents or scripts.
83
83
 
84
+ In non-interactive modes (`"prompt"`, `-P`, `--json`), my-pi keeps
85
+ headless-capable built-ins like MCP, LSP, chains, prompt presets,
86
+ recall, hooks, and secret filtering enabled, while skipping UI-only
87
+ built-ins like handoff, confirm-destructive, session auto-naming, and
88
+ working-indicator customization.
89
+
84
90
  ### Local telemetry (SQLite)
85
91
 
86
92
  Telemetry is **disabled by default**. When enabled, my-pi records
@@ -238,6 +244,7 @@ import { create_my_pi, runPrintMode } from 'my-pi';
238
244
  const runtime = await create_my_pi({
239
245
  agent_dir: './tmp/pi-agent',
240
246
  extensions: ['./my-ext.ts'],
247
+ runtime_mode: 'json',
241
248
  telemetry: true,
242
249
  telemetry_db_path: './tmp/evals.db',
243
250
  });
@@ -819,7 +819,39 @@ const SECRET_PATTERNS = [
819
819
  pattern: /github_pat_[a-zA-Z0-9_]{20,}/g
820
820
  }
821
821
  ];
822
- function redact(text) {
822
+ const SSH_CONFIG_VALUE_DIRECTIVE_PATTERN = /^([ \t]*)(HostName|User|IdentityFile|CertificateFile|ProxyJump|ProxyCommand|LocalForward|RemoteForward|DynamicForward|HostKeyAlias)(\s+)(.+)$/gim;
823
+ const SSH_CONFIG_HOST_PATTERN = /^([ \t]*)(Host)(\s+)(.+)$/gim;
824
+ const SSH_CONFIG_MATCH_PATTERN = /^([ \t]*)(Match)(\s+)(.+)$/gim;
825
+ function looks_like_ssh_config(text) {
826
+ const has_scope_line = /^\s*(?:Host|Match)\b/m.test(text);
827
+ const has_sensitive_directive = /^\s*(?:HostName|User|IdentityFile|CertificateFile|ProxyJump|ProxyCommand|LocalForward|RemoteForward|DynamicForward|HostKeyAlias)\b/im.test(text);
828
+ return has_scope_line && has_sensitive_directive;
829
+ }
830
+ function redact_ssh_config_metadata(text) {
831
+ let count = 0;
832
+ const redact_directive_value = (match, indent, directive, spacing, value) => {
833
+ if (value.includes("[REDACTED:")) return match;
834
+ count++;
835
+ return `${indent}${directive}${spacing}[REDACTED:SSH ${directive}]`;
836
+ };
837
+ let result = text.replace(SSH_CONFIG_VALUE_DIRECTIVE_PATTERN, redact_directive_value);
838
+ result = result.replace(SSH_CONFIG_HOST_PATTERN, (match, indent, directive, spacing, value) => {
839
+ if (value.trim() === "*" || value.includes("[REDACTED:")) return match;
840
+ count++;
841
+ return `${indent}${directive}${spacing}[REDACTED:SSH Host]`;
842
+ });
843
+ result = result.replace(SSH_CONFIG_MATCH_PATTERN, (match, indent, directive, spacing, value) => {
844
+ if (value.trim().toLowerCase() === "all") return match;
845
+ if (value.includes("[REDACTED:")) return match;
846
+ count++;
847
+ return `${indent}${directive}${spacing}[REDACTED:SSH Match]`;
848
+ });
849
+ return {
850
+ redacted: result,
851
+ count
852
+ };
853
+ }
854
+ function redact_secret_patterns(text) {
823
855
  let count = 0;
824
856
  let result = text;
825
857
  for (const sp of SECRET_PATTERNS) {
@@ -834,14 +866,44 @@ function redact(text) {
834
866
  count
835
867
  };
836
868
  }
869
+ function is_ssh_config_path(path) {
870
+ if (typeof path !== "string") return false;
871
+ const normalized = path.replaceAll("\\", "/").toLowerCase();
872
+ return /(?:^|\/)(?:\.ssh\/(?:config|config\.d\/.+|conf\.d\/.+)|ssh_config)$/.test(normalized);
873
+ }
874
+ function should_force_ssh_config_redaction(event) {
875
+ if (event.toolName !== "read") return false;
876
+ if (!event.input || typeof event.input !== "object") return false;
877
+ return is_ssh_config_path(event.input.path);
878
+ }
879
+ function is_text_content(item) {
880
+ return item.type === "text";
881
+ }
882
+ function redact_text(text, options) {
883
+ let count = 0;
884
+ let result = text;
885
+ if (options?.force_ssh_config || looks_like_ssh_config(result)) {
886
+ const ssh_redaction = redact_ssh_config_metadata(result);
887
+ result = ssh_redaction.redacted;
888
+ count += ssh_redaction.count;
889
+ }
890
+ const secret_redaction = redact_secret_patterns(result);
891
+ result = secret_redaction.redacted;
892
+ count += secret_redaction.count;
893
+ return {
894
+ redacted: result,
895
+ count
896
+ };
897
+ }
837
898
  async function filter_output(pi) {
838
899
  let totalRedacted = 0;
839
900
  pi.on("tool_result", async (event) => {
840
901
  if (!event.content) return;
902
+ const force_ssh_config = should_force_ssh_config_redaction(event);
841
903
  let modified = false;
842
904
  const newContent = event.content.map((item) => {
843
- if (item.type !== "text" || !item.text) return item;
844
- const { redacted, count } = redact(item.text);
905
+ if (!is_text_content(item) || !item.text) return item;
906
+ const { redacted, count } = redact_text(item.text, { force_ssh_config });
845
907
  if (count > 0) {
846
908
  modified = true;
847
909
  totalRedacted += count;
@@ -2555,6 +2617,7 @@ function count_pending_enabled_servers(servers) {
2555
2617
  return Array.from(servers.values()).filter((state) => state.enabled && state.status !== "connected").length;
2556
2618
  }
2557
2619
  function update_mcp_status(ctx, servers) {
2620
+ if (!ctx.hasUI) return;
2558
2621
  if (servers.size === 0) {
2559
2622
  ctx.ui.setStatus("mcp", void 0);
2560
2623
  return;
@@ -2570,6 +2633,7 @@ function update_mcp_status(ctx, servers) {
2570
2633
  ctx.ui.setStatus("mcp", ctx.ui.theme.fg("dim", fragments.join(" · ")));
2571
2634
  }
2572
2635
  function set_connect_feedback(ctx, pending_server_count) {
2636
+ if (!ctx.hasUI) return () => {};
2573
2637
  const label = pending_server_count === 1 ? "Connecting 1 MCP server..." : `Connecting ${pending_server_count} MCP servers...`;
2574
2638
  ctx.ui.setWorkingMessage(label);
2575
2639
  ctx.ui.setWorkingIndicator({
@@ -5175,6 +5239,7 @@ function parse_working_indicator_mode(input) {
5175
5239
  return null;
5176
5240
  }
5177
5241
  function apply_working_indicator(ctx, mode) {
5242
+ if (!ctx.hasUI) return;
5178
5243
  ctx.ui.setWorkingIndicator(get_working_indicator(ctx, mode));
5179
5244
  }
5180
5245
  async function working_indicator(pi) {
@@ -5233,6 +5298,12 @@ const PI_AGENT_DIR_ENV = "PI_CODING_AGENT_DIR";
5233
5298
  function resolve_agent_dir(cwd, agent_dir) {
5234
5299
  return agent_dir ? resolve(cwd, agent_dir) : getAgentDir();
5235
5300
  }
5301
+ const NON_INTERACTIVE_UI_ONLY_BUILTINS = [
5302
+ "handoff",
5303
+ "session-name",
5304
+ "confirm-destructive",
5305
+ "working-indicator"
5306
+ ];
5236
5307
  function get_force_disabled_builtins(options) {
5237
5308
  const force_disabled = /* @__PURE__ */ new Set();
5238
5309
  if (!options.mcp) force_disabled.add("mcp");
@@ -5247,6 +5318,7 @@ function get_force_disabled_builtins(options) {
5247
5318
  if (!options.confirm_destructive) force_disabled.add("confirm-destructive");
5248
5319
  if (!options.hooks_resolution) force_disabled.add("hooks-resolution");
5249
5320
  if (!options.working_indicator) force_disabled.add("working-indicator");
5321
+ if (options.runtime_mode && options.runtime_mode !== "interactive") for (const key of NON_INTERACTIVE_UI_ONLY_BUILTINS) force_disabled.add(key);
5250
5322
  return force_disabled;
5251
5323
  }
5252
5324
  function create_builtin_extension_factory(key, extension, force_disabled) {
@@ -5268,11 +5340,12 @@ function create_extensions_override(managed_inline_paths) {
5268
5340
  };
5269
5341
  }
5270
5342
  async function create_my_pi(options = {}) {
5271
- 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, working_indicator = true, telemetry, telemetry_db_path, model, system_prompt, append_system_prompt } = options;
5343
+ const { cwd = process.cwd(), agent_dir, extensions = [], extensionFactories: user_factories = [], runtime_mode = "interactive", 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, working_indicator = true, telemetry, telemetry_db_path, model, system_prompt, append_system_prompt } = options;
5272
5344
  const effective_agent_dir = resolve_agent_dir(cwd, agent_dir);
5273
5345
  if (agent_dir) process.env[PI_AGENT_DIR_ENV] = effective_agent_dir;
5274
5346
  const resolved_extensions = extensions.map((p) => resolve(cwd, p));
5275
5347
  const force_disabled = get_force_disabled_builtins({
5348
+ runtime_mode,
5276
5349
  mcp,
5277
5350
  skills,
5278
5351
  chain,
@@ -5310,7 +5383,7 @@ async function create_my_pi(options = {}) {
5310
5383
  ...system_prompt !== void 0 ? { systemPromptOverride: () => system_prompt } : {},
5311
5384
  ...append_system_prompt !== void 0 ? { appendSystemPromptOverride: (base) => [...base, append_system_prompt] } : {},
5312
5385
  additionalExtensionPaths: [...resolved_extensions],
5313
- additionalThemePaths: [PACKAGE_THEME_DIR],
5386
+ ...runtime_mode === "interactive" ? { additionalThemePaths: [PACKAGE_THEME_DIR] } : {},
5314
5387
  extensionFactories: [...managed_extension_factories, ...user_factories],
5315
5388
  extensionsOverride: create_extensions_override(managed_inline_paths),
5316
5389
  skillsOverride: (base) => {
@@ -5340,6 +5413,6 @@ async function create_my_pi(options = {}) {
5340
5413
  });
5341
5414
  }
5342
5415
  //#endregion
5343
- export { create_my_pi as n, runPrintMode$1 as r, InteractiveMode$1 as t };
5416
+ export { runPrintMode$1 as i, create_my_pi as n, get_force_disabled_builtins as r, InteractiveMode$1 as t };
5344
5417
 
5345
- //# sourceMappingURL=api-q7uQTUHx.js.map
5418
+ //# sourceMappingURL=api-DgvJRqr3.js.map