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 +7 -0
- package/dist/{api-q7uQTUHx.js → api-DgvJRqr3.js} +80 -7
- package/dist/api-DgvJRqr3.js.map +1 -0
- package/dist/api.js +2 -2
- package/dist/index.js +65 -22
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
- package/src/extensions/filter-output.test.ts +105 -207
- package/src/extensions/filter-output.ts +137 -13
- package/src/extensions/mcp.ts +5 -0
- package/src/extensions/working-indicator.ts +1 -0
- package/dist/api-q7uQTUHx.js.map +0 -1
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
|
-
|
|
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
|
|
844
|
-
const { redacted, count } =
|
|
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,
|
|
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-
|
|
5418
|
+
//# sourceMappingURL=api-DgvJRqr3.js.map
|