@oh-my-pi/pi-coding-agent 17.2.10 → 17.2.11

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.
Files changed (120) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/dist/{CHANGELOG-rhwzpexa.md → CHANGELOG-d9xenpn9.md} +40 -0
  3. package/dist/cli.js +3025 -3016
  4. package/dist/types/capability/mcp.d.ts +11 -0
  5. package/dist/types/capability/skill.d.ts +6 -0
  6. package/dist/types/cli/command-help.d.ts +3 -0
  7. package/dist/types/commands/share.d.ts +25 -0
  8. package/dist/types/commit/agentic/index.d.ts +3 -1
  9. package/dist/types/commit/execute.d.ts +32 -0
  10. package/dist/types/commit/index.d.ts +2 -1
  11. package/dist/types/commit/pipeline.d.ts +7 -1
  12. package/dist/types/config/model-registry.d.ts +4 -0
  13. package/dist/types/config/settings-schema.d.ts +1 -34
  14. package/dist/types/discovery/agent-plugin-format.d.ts +143 -0
  15. package/dist/types/discovery/agent-plugins.d.ts +1 -0
  16. package/dist/types/discovery/contained-path.d.ts +34 -0
  17. package/dist/types/discovery/index.d.ts +1 -0
  18. package/dist/types/extensibility/custom-tools/types.d.ts +2 -2
  19. package/dist/types/extensibility/extensions/loader.d.ts +7 -0
  20. package/dist/types/extensibility/extensions/types.d.ts +11 -0
  21. package/dist/types/extensibility/shared-events.d.ts +3 -2
  22. package/dist/types/extensibility/skills.d.ts +5 -0
  23. package/dist/types/mcp/transports/header-policy.d.ts +45 -0
  24. package/dist/types/mcp/types.d.ts +15 -0
  25. package/dist/types/modes/components/agent-hub.d.ts +2 -0
  26. package/dist/types/modes/components/agent-transcript-viewer.d.ts +2 -0
  27. package/dist/types/modes/components/chat-transcript-builder.d.ts +2 -0
  28. package/dist/types/modes/components/custom-editor.d.ts +1 -2
  29. package/dist/types/modes/components/status-line/types.d.ts +2 -0
  30. package/dist/types/modes/components/tool-execution.d.ts +2 -0
  31. package/dist/types/modes/utils/transcript-render-helpers.d.ts +3 -2
  32. package/dist/types/secrets/index.d.ts +23 -1
  33. package/dist/types/session/agent-session-events.d.ts +2 -2
  34. package/dist/types/session/agent-session.d.ts +1 -1
  35. package/dist/types/session/messages.d.ts +1 -0
  36. package/dist/types/session/prewalk.d.ts +3 -1
  37. package/dist/types/session/session-tools.d.ts +8 -0
  38. package/dist/types/session/turn-recovery.d.ts +7 -2
  39. package/dist/types/task/index.d.ts +2 -0
  40. package/dist/types/tools/shell-tokenize.d.ts +16 -0
  41. package/package.json +13 -13
  42. package/scripts/legacy-pi-virtual-module.ts +4 -1
  43. package/src/capability/mcp.ts +11 -0
  44. package/src/capability/skill.ts +6 -0
  45. package/src/cli/command-help.ts +4 -0
  46. package/src/cli/gallery-cli.ts +1 -1
  47. package/src/cli-commands.ts +5 -0
  48. package/src/commands/commit.ts +16 -3
  49. package/src/commands/share.ts +71 -0
  50. package/src/commit/agentic/index.ts +39 -21
  51. package/src/commit/execute.ts +56 -0
  52. package/src/commit/index.ts +2 -1
  53. package/src/commit/pipeline.ts +20 -7
  54. package/src/config/model-discovery.ts +1 -1
  55. package/src/config/model-registry.ts +21 -1
  56. package/src/config/settings-schema.ts +2 -33
  57. package/src/config/settings.ts +46 -0
  58. package/src/discovery/agent-plugin-format.ts +551 -0
  59. package/src/discovery/agent-plugins.ts +341 -0
  60. package/src/discovery/claude-plugins.ts +21 -5
  61. package/src/discovery/contained-path.ts +78 -0
  62. package/src/discovery/helpers.ts +23 -9
  63. package/src/discovery/index.ts +1 -0
  64. package/src/discovery/omp-plugins.ts +20 -7
  65. package/src/exec/non-interactive-env.ts +1 -0
  66. package/src/extensibility/custom-tools/types.ts +2 -2
  67. package/src/extensibility/extensions/loader.ts +78 -14
  68. package/src/extensibility/extensions/runner.ts +6 -0
  69. package/src/extensibility/extensions/types.ts +12 -0
  70. package/src/extensibility/plugins/marketplace/manager.ts +2 -1
  71. package/src/extensibility/shared-events.ts +3 -2
  72. package/src/extensibility/skills.ts +9 -0
  73. package/src/internal-urls/skill-protocol.ts +14 -0
  74. package/src/internal-urls/vault-protocol.ts +2 -2
  75. package/src/launch/client.ts +11 -1
  76. package/src/launch/protocol.ts +7 -2
  77. package/src/main.ts +3 -2
  78. package/src/mcp/config.ts +3 -0
  79. package/src/mcp/manager.ts +12 -9
  80. package/src/mcp/transports/header-policy.ts +95 -0
  81. package/src/mcp/transports/http.ts +35 -52
  82. package/src/mcp/transports/sse.ts +20 -27
  83. package/src/mcp/types.ts +15 -0
  84. package/src/modes/acp/acp-agent.ts +15 -4
  85. package/src/modes/components/agent-dashboard.ts +2 -0
  86. package/src/modes/components/agent-hub.ts +5 -0
  87. package/src/modes/components/agent-transcript-viewer.ts +3 -0
  88. package/src/modes/components/chat-transcript-builder.ts +3 -0
  89. package/src/modes/components/custom-editor.ts +0 -9
  90. package/src/modes/components/status-line/component.ts +1 -0
  91. package/src/modes/components/status-line/segments.ts +6 -4
  92. package/src/modes/components/status-line/types.ts +2 -0
  93. package/src/modes/components/tool-execution.ts +13 -16
  94. package/src/modes/components/tree-selector.ts +62 -3
  95. package/src/modes/controllers/command-controller.ts +4 -1
  96. package/src/modes/controllers/event-controller.ts +15 -15
  97. package/src/modes/controllers/input-controller.ts +20 -2
  98. package/src/modes/controllers/selector-controller.ts +1 -0
  99. package/src/modes/utils/transcript-render-helpers.ts +4 -2
  100. package/src/modes/utils/ui-helpers.ts +1 -0
  101. package/src/sdk.ts +6 -49
  102. package/src/secrets/index.ts +52 -1
  103. package/src/session/agent-session-events.ts +2 -2
  104. package/src/session/agent-session.ts +33 -14
  105. package/src/session/messages.ts +1 -0
  106. package/src/session/prewalk.ts +57 -17
  107. package/src/session/session-context.ts +3 -5
  108. package/src/session/session-handoff.ts +5 -1
  109. package/src/session/session-tools.ts +37 -3
  110. package/src/session/todo-tracker.ts +11 -1
  111. package/src/session/turn-recovery.ts +94 -72
  112. package/src/slash-commands/builtin-registry.ts +12 -8
  113. package/src/task/index.ts +21 -6
  114. package/src/tools/bash-skill-urls.ts +15 -0
  115. package/src/tools/bash.ts +10 -11
  116. package/src/tools/debug.ts +1 -1
  117. package/src/tools/jtd-to-json-schema.ts +123 -21
  118. package/src/tools/read.ts +5 -4
  119. package/src/tools/shell-tokenize.ts +98 -0
  120. package/src/web/search/providers/exa.ts +1 -1
@@ -24,12 +24,23 @@ export interface MCPServer {
24
24
  args?: string[];
25
25
  /** Environment variables */
26
26
  env?: Record<string, string>;
27
+ /**
28
+ * `literal`: env values are opaque plugin package data (Agent Plugins
29
+ * §§4.1/9.2) — exempt from env-name lookup and `!command` resolution.
30
+ */
31
+ envPolicy?: "literal";
27
32
  /** Working directory for stdio transport */
28
33
  cwd?: string;
29
34
  /** URL (for HTTP/SSE transport) */
30
35
  url?: string;
31
36
  /** HTTP headers (for HTTP transport) */
32
37
  headers?: Record<string, string>;
38
+ /**
39
+ * `origin-locked`: configured headers are literal package data pinned to the
40
+ * configured URL's origin (Agent Plugins §7.2.1) — never expanded, never
41
+ * forwarded cross-origin, and client-generated headers win case-insensitively.
42
+ */
43
+ headerPolicy?: "origin-locked";
33
44
  /** Authentication configuration */
34
45
  auth?: {
35
46
  type: "oauth" | "apikey";
@@ -35,6 +35,12 @@ export interface Skill {
35
35
  content: string;
36
36
  /** Parsed frontmatter */
37
37
  frontmatter?: SkillFrontmatter;
38
+ /**
39
+ * Filesystem-resolved plugin root this skill was packaged in (Agent Plugins
40
+ * §4.1). When set, every `skill://` resource access must realpath-resolve
41
+ * within this directory; symlinks may target other files inside it.
42
+ */
43
+ containRoot?: string;
38
44
  /** Source level */
39
45
  level: "user" | "project";
40
46
  /** Source metadata */
@@ -67,6 +67,9 @@ export declare const sayHelp: {
67
67
  export declare const searchHelp: {
68
68
  description: string;
69
69
  };
70
+ export declare const shareHelp: {
71
+ description: string;
72
+ };
70
73
  export declare const setupHelp: {
71
74
  description: string;
72
75
  };
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Share a saved session as an encrypted link without launching the agent.
3
+ *
4
+ * `omp share <session>` accepts a session id (prefix) or a path to a session
5
+ * `.jsonl` and uploads the sealed snapshot exactly like the `/share` slash
6
+ * command, honoring `share.serverUrl`, `share.store`, and
7
+ * `share.redactSecrets`.
8
+ */
9
+ import { Command } from "@oh-my-pi/pi-utils/cli";
10
+ export default class Share extends Command {
11
+ static description: string;
12
+ static args: {
13
+ session: import("@oh-my-pi/pi-utils/cli").ArgDescriptor & {
14
+ description: string;
15
+ required: true;
16
+ };
17
+ };
18
+ static flags: {
19
+ gist: import("@oh-my-pi/pi-utils/cli").FlagDescriptor<"boolean"> & {
20
+ description: string;
21
+ default: boolean;
22
+ };
23
+ };
24
+ run(): Promise<void>;
25
+ }
@@ -1,2 +1,4 @@
1
1
  import type { CommitCommandArgs } from "../../commit/types.js";
2
- export declare function runAgenticCommit(args: CommitCommandArgs): Promise<void>;
2
+ export declare function runAgenticCommit(args: CommitCommandArgs): Promise<{
3
+ usedFallback: boolean;
4
+ }>;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Shared commit-execution helpers for the agentic and legacy `omp commit`
3
+ * pipelines: readable failure reporting for refusing git hooks and a push
4
+ * wrapper that keeps a requested `--push` honest.
5
+ */
6
+ import * as git from "../utils/git.js";
7
+ /**
8
+ * A commit or push failure that has already been reported to the user with a
9
+ * readable message. It is thrown so the CLI exits non-zero without the runtime
10
+ * dumping a stack trace — in a bundled build that trace is several kilobytes of
11
+ * minified source, which buries the one line the user needs (issue #7834).
12
+ *
13
+ * `runCommitCommand`'s caller (`commands/commit.ts`) maps this to exit code 1.
14
+ */
15
+ export declare class CommitAbortedError extends Error {
16
+ constructor();
17
+ }
18
+ /**
19
+ * Print a git-command failure — most often a `pre-commit`/`commit-msg` hook
20
+ * that exited non-zero — as an indented message under `context`, then abort.
21
+ *
22
+ * @param context Label for the failed step, e.g. `"Commit 1 of 2 failed"`.
23
+ * @param error The failure to surface; its captured stderr/stdout is shown.
24
+ * @param note Optional trailing status line (split-plan progress, recovery).
25
+ */
26
+ export declare function abortOnGitFailure(context: string, error: git.GitCommandError, note?: string): never;
27
+ /**
28
+ * Push the current branch, reporting a refused push (missing upstream, rejected
29
+ * ref) through {@link abortOnGitFailure} instead of letting the raw
30
+ * `GitCommandError` escape. Prints the success line on completion.
31
+ */
32
+ export declare function pushOrAbort(cwd: string): Promise<void>;
@@ -1,4 +1,5 @@
1
1
  /**
2
2
  * Entry points for the omp commit command.
3
3
  */
4
- export { runCommitCommand } from "./pipeline.js";
4
+ export * from "./execute.js";
5
+ export * from "./pipeline.js";
@@ -1,5 +1,11 @@
1
1
  import type { CommitCommandArgs } from "./types.js";
2
2
  /**
3
3
  * Execute the omp commit pipeline for staged changes.
4
+ *
5
+ * Returns whether the commit was generated by the mechanical fallback rather
6
+ * than by the commit agent, so callers can signal a degraded outcome (issue
7
+ * #7835). The legacy pipeline has no fallback: model failures throw.
4
8
  */
5
- export declare function runCommitCommand(args: CommitCommandArgs): Promise<void>;
9
+ export declare function runCommitCommand(args: CommitCommandArgs): Promise<{
10
+ usedFallback: boolean;
11
+ }>;
@@ -227,6 +227,10 @@ export declare class ModelRegistry {
227
227
  * Remove custom API/OAuth registrations for a specific extension source.
228
228
  */
229
229
  clearSourceRegistrations(sourceId: string): void;
230
+ /**
231
+ * Remove one extension-registered provider and restore its static models.
232
+ */
233
+ unregisterProvider(providerName: string): void;
230
234
  /**
231
235
  * Remove registrations for extension sources that are no longer active.
232
236
  */
@@ -5981,17 +5981,7 @@ export declare const SETTINGS_SCHEMA: {
5981
5981
  readonly tab: "providers";
5982
5982
  readonly group: "Services";
5983
5983
  readonly label: "Exa";
5984
- readonly description: "Master toggle for all Exa search tools";
5985
- };
5986
- };
5987
- readonly "exa.enableSearch": {
5988
- readonly type: "boolean";
5989
- readonly default: true;
5990
- readonly ui: {
5991
- readonly tab: "providers";
5992
- readonly group: "Services";
5993
- readonly label: "Exa Search";
5994
- readonly description: "Enable Exa basic search, deep search, code search, and crawl tools";
5984
+ readonly description: "Enable the Exa web search provider";
5995
5985
  };
5996
5986
  };
5997
5987
  readonly "exa.searchDelayMs": {
@@ -6004,26 +5994,6 @@ export declare const SETTINGS_SCHEMA: {
6004
5994
  readonly description: "Minimum delay between Exa web search requests in milliseconds; set 0 to disable pacing";
6005
5995
  };
6006
5996
  };
6007
- readonly "exa.enableResearcher": {
6008
- readonly type: "boolean";
6009
- readonly default: false;
6010
- readonly ui: {
6011
- readonly tab: "providers";
6012
- readonly group: "Services";
6013
- readonly label: "Exa Researcher";
6014
- readonly description: "Enable the Exa researcher tool for AI-powered deep research";
6015
- };
6016
- };
6017
- readonly "exa.enableWebsets": {
6018
- readonly type: "boolean";
6019
- readonly default: false;
6020
- readonly ui: {
6021
- readonly tab: "providers";
6022
- readonly group: "Services";
6023
- readonly label: "Exa Websets";
6024
- readonly description: "Enable Exa webset management and enrichment tools";
6025
- };
6026
- };
6027
5997
  readonly "searxng.endpoint": {
6028
5998
  readonly type: "string";
6029
5999
  readonly default: undefined;
@@ -6329,10 +6299,7 @@ export interface TtsrSettings {
6329
6299
  }
6330
6300
  export interface ExaSettings {
6331
6301
  enabled: boolean;
6332
- enableSearch: boolean;
6333
6302
  searchDelayMs: number;
6334
- enableResearcher: boolean;
6335
- enableWebsets: boolean;
6336
6303
  }
6337
6304
  export interface StatusLineSettings {
6338
6305
  preset: StatusLinePreset;
@@ -0,0 +1,143 @@
1
+ /** Canonical `plugin.json` `$schema` identifier for Agent Plugins 1.0.0 (spec §5.2). */
2
+ export declare const AGENT_PLUGIN_MANIFEST_SCHEMA = "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json";
3
+ /** Canonical `mcp.json` `$schema` identifier for Agent Plugins 1.0.0 (spec §7.2.1). */
4
+ export declare const AGENT_PLUGIN_MCP_SCHEMA = "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json";
5
+ /** Validated portable manifest fields from a plugin's root `plugin.json` (spec §5). */
6
+ export interface AgentPluginManifest {
7
+ name: string;
8
+ version?: string;
9
+ description?: string;
10
+ author?: {
11
+ name?: string;
12
+ email?: string;
13
+ url?: string;
14
+ };
15
+ homepage?: string;
16
+ repository?: string;
17
+ license?: string;
18
+ keywords?: string[];
19
+ /**
20
+ * Client-owned data keyed by reverse-domain namespace. Member values are
21
+ * opaque: this client implements no namespace, and §8.1/§11.1 require
22
+ * ignoring unimplemented namespaces without validating their values.
23
+ */
24
+ extensions?: Record<string, unknown>;
25
+ }
26
+ /**
27
+ * Outcome of parsing a candidate `plugin.json`:
28
+ * - `none` — the document does not target Agent Plugins (no recognized `$schema`);
29
+ * legacy plugin conventions may still apply to the directory.
30
+ * - `valid` — a conformant manifest; `warnings` carries the non-fatal violations
31
+ * the spec requires reporting (unknown top-level fields, non-object `extensions`).
32
+ * - `invalid` — the document targets Agent Plugins but violates the closed schema
33
+ * fatally; the plugin must be rejected and none of its components loaded (spec §5.2).
34
+ */
35
+ export type AgentPluginManifestResult = {
36
+ status: "none";
37
+ } | {
38
+ status: "valid";
39
+ manifest: AgentPluginManifest;
40
+ warnings: string[];
41
+ } | {
42
+ status: "invalid";
43
+ reason: string;
44
+ };
45
+ /** Enforce the plugin `name` constraints from spec §5.5. */
46
+ export declare function isValidAgentPluginName(name: string): boolean;
47
+ /**
48
+ * Validate `SKILL.md` frontmatter against the Agent Skills specification
49
+ * (https://agentskills.io/specification), the source of truth for skill
50
+ * validity under Agent Plugins §7.1, mirroring the official skills-ref
51
+ * reference validator: the frontmatter schema is CLOSED to its six fields and
52
+ * any unexpected key rejects the skill. Returns the first violation, or `null`
53
+ * when the skill conforms. Frontmatter keys must be raw (unnormalized).
54
+ */
55
+ export declare function validateAgentSkillFrontmatter(frontmatter: Record<string, unknown>, dirName: string): string | null;
56
+ /**
57
+ * Parse and validate a root `plugin.json` document against the closed
58
+ * Agent Plugins 1.0.0 manifest schema (spec §5.2–§5.5, §8.1).
59
+ */
60
+ export declare function parseAgentPluginManifest(raw: string): AgentPluginManifestResult;
61
+ /**
62
+ * Expand `${PLUGIN_ROOT}` and `${PLUGIN_DATA}` in a configuration value
63
+ * (spec §9.2). Single non-recursive pass; replacement text is never rescanned,
64
+ * and no other placeholder or environment-variable expansion is performed.
65
+ */
66
+ export declare function expandAgentPluginPlaceholders(value: string, pluginRoot: string, pluginData: string): string;
67
+ /** A validated `mcp.json` server entry, resolved to launch-ready values. */
68
+ export interface AgentPluginMcpServer {
69
+ name: string;
70
+ transport: "stdio" | "http" | "sse";
71
+ /** Absolute path for `./`-relative commands; bare executable token otherwise. */
72
+ command?: string;
73
+ args?: string[];
74
+ /** Expanded configured env plus the client-supplied `PLUGIN_ROOT`/`PLUGIN_DATA`. */
75
+ env?: Record<string, string>;
76
+ /** Absolute working directory; defaults to the plugin root for stdio servers. */
77
+ cwd?: string;
78
+ url?: string;
79
+ headers?: Record<string, string>;
80
+ }
81
+ /**
82
+ * Outcome of parsing a plugin's `mcp.json`:
83
+ * - `disabled` — the top-level document is invalid, so MCP is disabled for the
84
+ * plugin while other component types keep loading (spec §7.2.2 rule 2).
85
+ * - `ok` — the document is valid; individually invalid server entries are
86
+ * skipped with a warning (spec §7.2.2 rule 3).
87
+ */
88
+ export type AgentPluginMcpResult = {
89
+ status: "disabled";
90
+ reason: string;
91
+ } | {
92
+ status: "ok";
93
+ servers: AgentPluginMcpServer[];
94
+ warnings: string[];
95
+ };
96
+ export interface AgentPluginMcpOptions {
97
+ /** Filesystem-resolved plugin root. */
98
+ pluginRoot: string;
99
+ /** Client-managed persistent data directory for this plugin (spec §9.1). */
100
+ pluginData: string;
101
+ }
102
+ /**
103
+ * Parse and validate a plugin's `mcp.json` against the closed Agent Plugins
104
+ * 1.0.0 MCP configuration (spec §7.2), resolving stdio commands and working
105
+ * directories against the plugin root and expanding plugin variables.
106
+ */
107
+ export declare function parseAgentPluginMcp(raw: string, options: AgentPluginMcpOptions): Promise<AgentPluginMcpResult>;
108
+ /**
109
+ * Classification of a plugin root directory against the Agent Plugins standard:
110
+ * - `none` — no Agent Plugins manifest; legacy plugin conventions govern.
111
+ * - `standard` — a valid Agent Plugin; the standard governs its portable
112
+ * components (skills and MCP servers). `realRoot` is the filesystem-resolved
113
+ * plugin root every package path is contained within.
114
+ * - `invalid` — the root claims Agent Plugins conformance but its manifest is
115
+ * fatally invalid; no component may be discovered or executed (spec §11.3).
116
+ */
117
+ export type AgentPluginRootStatus = {
118
+ kind: "none";
119
+ } | {
120
+ kind: "standard";
121
+ manifest: AgentPluginManifest;
122
+ warnings: string[];
123
+ realRoot: string;
124
+ } | {
125
+ kind: "invalid";
126
+ reason: string;
127
+ };
128
+ /** Drop cached classifications (tests, or after plugin installs outside the shared registry flow). */
129
+ export declare function clearAgentPluginRootCache(): void;
130
+ /**
131
+ * Determine whether a plugin root is governed by the Agent Plugins standard.
132
+ * Results are cached per root path; the cache clears with the shared plugin
133
+ * roots cache and via {@link clearAgentPluginRootCache}.
134
+ */
135
+ export declare function classifyAgentPluginRoot(rootPath: string): Promise<AgentPluginRootStatus>;
136
+ /**
137
+ * Whether a legacy plugin provider (claude-plugins, omp-plugins) may process a
138
+ * root for the given surface. Roots governed by the Agent Plugins standard keep
139
+ * their portable components (`skills`, `mcp`) exclusive to the standard loader,
140
+ * while client-specific surfaces (commands, hooks, tools, …) still load from
141
+ * hybrid packages. Fatally invalid Agent Plugins packages are rejected entirely.
142
+ */
143
+ export declare function legacyProviderAllowed(rootPath: string, surface: "skills" | "mcp" | "other"): Promise<boolean>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,34 @@
1
+ /** Lexical containment: `target` is `base` itself or a descendant of it. */
2
+ export declare function isContained(base: string, target: string): boolean;
3
+ /** Resolve symlinks and equivalents; `null` when the path is missing or unresolvable. */
4
+ export declare function realpathIfExists(p: string): Promise<string | null>;
5
+ /** Outcome of resolving a fixed package path without reading it. */
6
+ export type ContainedPathResolution = {
7
+ status: "missing";
8
+ } | {
9
+ status: "outside";
10
+ } | {
11
+ status: "ok";
12
+ realPath: string;
13
+ };
14
+ /**
15
+ * Resolve a fixed package path WITHOUT reading it: symlinks and equivalent
16
+ * mechanisms are resolved first, and a path escaping the filesystem-resolved
17
+ * plugin root is rejected before any I/O could consume outside content.
18
+ */
19
+ export declare function resolveContainedPath(realBase: string, target: string): Promise<ContainedPathResolution>;
20
+ /**
21
+ * Verify a package path stays within the filesystem-resolved plugin root:
22
+ * lexically, and — when the target exists — after resolving symlinks. Unlike
23
+ * {@link resolveContainedPath}, a missing target passes. ONLY for configured
24
+ * paths that are validated but never read or executed at load time (stdio
25
+ * `command`, `cwd` — including `${PLUGIN_DATA}` paths created after
26
+ * validation); access paths MUST use {@link resolveContainedPath} instead,
27
+ * which fails closed on unresolvable targets.
28
+ */
29
+ export declare function isContainedResolved(realBase: string, target: string): Promise<boolean>;
30
+ /**
31
+ * Sync variant of {@link resolveContainedPath} for synchronous callsites
32
+ * (bash `skill://` expansion).
33
+ */
34
+ export declare function resolveContainedPathSync(realBase: string, target: string): ContainedPathResolution;
@@ -18,6 +18,7 @@ import "../capability/slash-command.js";
18
18
  import "../capability/ssh.js";
19
19
  import "../capability/system-prompt.js";
20
20
  import "../capability/tool.js";
21
+ import "./agent-plugins.js";
21
22
  import "./agents-md.js";
22
23
  import "./builtin.js";
23
24
  import "./builtin-defaults.js";
@@ -22,7 +22,7 @@ import type { LocalProtocolOptions } from "../../internal-urls/local-protocol.js
22
22
  import type { Theme } from "../../modes/theme/theme.js";
23
23
  import type { ReadonlySessionManager } from "../../session/session-manager.js";
24
24
  import type { TodoItem } from "../../tools/todo.js";
25
- import type { RecoveredRetryError } from "../shared-events.js";
25
+ import type { RetryErrorUpdate } from "../shared-events.js";
26
26
  /** Alias for clarity */
27
27
  export type CustomToolUIContext = HookUIContext;
28
28
  export type { ExecOptions, ExecResult } from "../../exec/exec.js";
@@ -119,7 +119,7 @@ export type CustomToolSessionEvent = {
119
119
  success: boolean;
120
120
  attempt: number;
121
121
  finalError?: string;
122
- recoveredErrors?: RecoveredRetryError[];
122
+ retryErrors?: RetryErrorUpdate[];
123
123
  } | {
124
124
  reason: "ttsr_triggered";
125
125
  rules: Rule[];
@@ -16,6 +16,8 @@ export declare class ExtensionRuntime implements IExtensionRuntime {
16
16
  config: ProviderConfig;
17
17
  sourceId: string;
18
18
  }>;
19
+ registerProvider(name: string, config: ProviderConfig, sourceId: string): void;
20
+ unregisterProvider(name: string): void;
19
21
  sendMessage(): void;
20
22
  sendUserMessage(): void;
21
23
  appendEntry(): void;
@@ -38,6 +40,11 @@ export declare class ExtensionRuntime implements IExtensionRuntime {
38
40
  export declare function loadExtensionFromFactory(factory: ExtensionFactory, cwd: string, eventBus: EventBus, runtime: IExtensionRuntime, name?: string): Promise<Extension>;
39
41
  /**
40
42
  * Load extensions from paths.
43
+ *
44
+ * Module import (the dominant cold-start cost — file I/O plus module
45
+ * evaluation) runs concurrently across extensions; factory binding then runs
46
+ * sequentially in the original path order, so registration semantics
47
+ * (last-wins collisions, shared runtime flag defaults) stay deterministic.
41
48
  */
42
49
  export declare function loadExtensions(paths: string[], cwd: string, eventBus?: EventBus): Promise<LoadExtensionsResult>;
43
50
  /**
@@ -918,6 +918,13 @@ export interface ExtensionAPI {
918
918
  * });
919
919
  */
920
920
  registerProvider(name: string, config: ProviderConfig): void;
921
+ /**
922
+ * Unregister a provider previously registered by an extension.
923
+ *
924
+ * Removes extension-provided models and restores overridden built-in models.
925
+ * Has no effect when the provider is not registered.
926
+ */
927
+ unregisterProvider(name: string): void;
921
928
  /** Shared event bus for extension communication. */
922
929
  events: EventBus;
923
930
  }
@@ -1042,6 +1049,10 @@ export interface ExtensionRuntimeState {
1042
1049
  config: ProviderConfig;
1043
1050
  sourceId: string;
1044
1051
  }>;
1052
+ /** Queue a provider registration until initialization, then apply it immediately. */
1053
+ registerProvider(name: string, config: ProviderConfig, sourceId: string): void;
1054
+ /** Remove a queued or initialized provider registration. */
1055
+ unregisterProvider(name: string, sourceId: string): void;
1045
1056
  }
1046
1057
  /** Action implementations for ExtensionAPI methods. */
1047
1058
  export interface ExtensionActions {
@@ -200,7 +200,8 @@ export interface AutoRetryStartEvent {
200
200
  errorMessage: string;
201
201
  errorId?: number;
202
202
  }
203
- export interface RecoveredRetryError {
203
+ /** Persisted retry error whose transcript presentation changed when the retry saga settled. */
204
+ export interface RetryErrorUpdate {
204
205
  entryId: string;
205
206
  persistenceKey?: string;
206
207
  note: string;
@@ -212,7 +213,7 @@ export interface AutoRetryEndEvent {
212
213
  success: boolean;
213
214
  attempt: number;
214
215
  finalError?: string;
215
- recoveredErrors?: RecoveredRetryError[];
216
+ retryErrors?: RetryErrorUpdate[];
216
217
  }
217
218
  /** Fired when TTSR rule matching interrupts generation */
218
219
  export interface TtsrTriggeredEvent {
@@ -13,6 +13,11 @@ export interface Skill {
13
13
  * prompt's `<skills>` listing.
14
14
  */
15
15
  hide?: boolean;
16
+ /**
17
+ * Filesystem-resolved plugin root for Agent Plugin skills (spec §4.1):
18
+ * every `skill://` resource access must realpath-resolve within it.
19
+ */
20
+ containRoot?: string;
16
21
  /** Source metadata for display */
17
22
  _source?: SourceMeta;
18
23
  }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * HTTP header precedence and redirect-origin policy for remote MCP transports.
3
+ *
4
+ * Two invariants, applied at every transport fetch:
5
+ *
6
+ * 1. Client-generated headers (protocol headers like `Content-Type`, `Accept`,
7
+ * `Mcp-Session-Id`, and authorization) take precedence over configured
8
+ * headers with the same case-insensitive name. Configured headers can never
9
+ * corrupt the MCP wire protocol via casing tricks.
10
+ * 2. Origin-locked servers (Agent Plugins §7.2.1) never forward configured
11
+ * headers to a different origin: redirects are followed manually and
12
+ * configured headers are attached only when the hop targets the configured
13
+ * origin. Method-changing redirects of non-GET requests are refused.
14
+ */
15
+ /** Header buckets for one MCP HTTP request. */
16
+ export interface MCPHeaderSources {
17
+ /** Client-generated HTTP/MCP/authorization headers; win case-insensitively. */
18
+ generated: Record<string, string>;
19
+ /** Configured headers from the server entry (package or user config). */
20
+ configured?: Record<string, string>;
21
+ }
22
+ /**
23
+ * Merge configured headers under client-generated ones: a configured entry is
24
+ * dropped when a generated header with the same case-insensitive name exists.
25
+ */
26
+ export declare function mergeMCPHeaders({ generated, configured }: MCPHeaderSources): Record<string, string>;
27
+ /**
28
+ * Set a client-generated header, removing any existing entry with the same
29
+ * case-insensitive name so the generated value is the only one sent.
30
+ */
31
+ export declare function setGeneratedHeader(headers: Record<string, string>, name: string, value: string): void;
32
+ export interface MCPFetchInit {
33
+ method: "GET" | "POST" | "DELETE";
34
+ body?: string;
35
+ signal?: AbortSignal;
36
+ }
37
+ /**
38
+ * Fetch an MCP endpoint with header precedence and, for origin-locked servers,
39
+ * manual redirect handling that strips configured headers on cross-origin hops.
40
+ *
41
+ * Non-locked servers keep the platform default redirect behavior. Locked
42
+ * non-GET requests only follow 307/308 (method-preserving); a 301/302/303
43
+ * redirect of a JSON-RPC POST is a connection error, never a silent GET.
44
+ */
45
+ export declare function mcpFetch(url: string, init: MCPFetchInit, sources: MCPHeaderSources, originLocked: boolean): Promise<Response>;
@@ -82,6 +82,13 @@ export interface MCPStdioServerConfig extends MCPServerConfigBase {
82
82
  command: string;
83
83
  args?: string[];
84
84
  env?: Record<string, string>;
85
+ /**
86
+ * `literal`: env values are opaque plugin package data (Agent Plugins
87
+ * §§4.1/9.2) — no env-name lookup, no `!command` execution, no dropping of
88
+ * empty values. The provider already applied the only permitted expansion
89
+ * (`${PLUGIN_ROOT}`/`${PLUGIN_DATA}`).
90
+ */
91
+ envPolicy?: "literal";
85
92
  cwd?: string;
86
93
  }
87
94
  /** HTTP server configuration (Streamable HTTP transport) */
@@ -89,12 +96,20 @@ export interface MCPHttpServerConfig extends MCPServerConfigBase {
89
96
  type: "http";
90
97
  url: string;
91
98
  headers?: Record<string, string>;
99
+ /**
100
+ * `origin-locked`: configured headers are literal package data pinned to the
101
+ * configured URL's origin (Agent Plugins §7.2.1) — never expanded, never
102
+ * forwarded cross-origin, and client-generated headers win case-insensitively.
103
+ */
104
+ headerPolicy?: "origin-locked";
92
105
  }
93
106
  /** SSE server configuration (deprecated, use HTTP) */
94
107
  export interface MCPSseServerConfig extends MCPServerConfigBase {
95
108
  type: "sse";
96
109
  url: string;
97
110
  headers?: Record<string, string>;
111
+ /** See {@link MCPHttpServerConfig.headerPolicy}. */
112
+ headerPolicy?: "origin-locked";
98
113
  }
99
114
  export type MCPServerConfig = MCPStdioServerConfig | MCPHttpServerConfig | MCPSseServerConfig;
100
115
  export declare const MCP_CONFIG_SCHEMA_URL = "https://raw.githubusercontent.com/can1357/oh-my-pi/main/packages/coding-agent/src/config/mcp-schema.json";
@@ -56,6 +56,8 @@ export interface AgentHubDeps {
56
56
  ui?: TUI;
57
57
  /** Tool lookup for transcript renderers (labels, custom render functions). */
58
58
  getTool?: (name: string) => AgentTool | undefined;
59
+ /** Whether the active registry entry came from a built-in factory. */
60
+ isBuiltInTool?: (name: string) => boolean;
59
61
  /** Extension message renderers for custom messages in the transcript. */
60
62
  getMessageRenderer?: (customType: string) => MessageRenderer | undefined;
61
63
  /** Cwd used by tool renderers for path shortening; defaults to the project dir. */
@@ -17,6 +17,8 @@ export interface AgentTranscriptViewerDeps {
17
17
  lifecycle?: () => AgentLifecycleManager;
18
18
  ui: TUI;
19
19
  getTool?: (name: string) => AgentTool | undefined;
20
+ /** Whether the active registry entry came from a built-in factory. */
21
+ isBuiltInTool?: (name: string) => boolean;
20
22
  getMessageRenderer?: (customType: string) => MessageRenderer | undefined;
21
23
  cwd: string;
22
24
  hideThinkingBlock?: () => boolean;
@@ -19,6 +19,8 @@ import { TranscriptContainer } from "./transcript-container.js";
19
19
  export interface ChatTranscriptBuilderDeps {
20
20
  ui: TUI;
21
21
  getTool?: (name: string) => AgentTool | undefined;
22
+ /** Whether the active registry entry came from a built-in factory. */
23
+ isBuiltInTool?: (name: string) => boolean;
22
24
  getMessageRenderer?: (customType: string) => MessageRenderer | undefined;
23
25
  cwd: string;
24
26
  hideThinkingBlock?: () => boolean;
@@ -1,7 +1,7 @@
1
1
  import type { ImageContent } from "@oh-my-pi/pi-ai";
2
2
  import { Editor, type KeyId, TUI } from "@oh-my-pi/pi-tui";
3
3
  import type { AppKeybinding } from "../../config/keybindings.js";
4
- type ConfigurableEditorAction = Extract<AppKeybinding, "app.interrupt" | "app.clear" | "app.exit" | "app.suspend" | "app.display.reset" | "app.thinking.cycle" | "app.model.cycleForward" | "app.model.cycleBackward" | "app.model.select" | "app.model.selectTemporary" | "app.tools.expand" | "app.tools.toggleVisibility" | "app.thinking.toggle" | "app.editor.external" | "app.history.search" | "app.message.dequeue" | "app.retry" | "app.clipboard.pasteImage" | "app.clipboard.pasteTextRaw" | "app.clipboard.copyPrompt">;
4
+ type ConfigurableEditorAction = Extract<AppKeybinding, "app.interrupt" | "app.clear" | "app.exit" | "app.suspend" | "app.display.reset" | "app.thinking.cycle" | "app.model.cycleForward" | "app.model.cycleBackward" | "app.model.select" | "app.model.selectTemporary" | "app.tools.toggleVisibility" | "app.thinking.toggle" | "app.editor.external" | "app.history.search" | "app.message.dequeue" | "app.retry" | "app.clipboard.pasteImage" | "app.clipboard.pasteTextRaw" | "app.clipboard.copyPrompt">;
5
5
  /** Max gap (ms) between two spaces for the later one to count as OS key auto-repeat rather than a
6
6
  * deliberate press. OS auto-repeat is fast; a deliberate tap (even a fast one) is slower. */
7
7
  export declare const SPACE_REPEAT_MAX_GAP_MS = 120;
@@ -140,7 +140,6 @@ export declare class CustomEditor extends Editor {
140
140
  onCycleModelForward?: () => void;
141
141
  onCycleModelBackward?: () => void;
142
142
  onSelectModel?: () => void;
143
- onExpandTools?: () => void;
144
143
  onToggleToolActivity?: () => void;
145
144
  onToggleThinking?: () => void;
146
145
  onExternalEditor?: () => void;
@@ -52,6 +52,8 @@ export interface SegmentContext {
52
52
  session: AgentSession;
53
53
  /** Focused subagent id while the view is proxied at its session, undefined otherwise. */
54
54
  focusedAgentId?: string | undefined;
55
+ /** Effective `statusLine.sessionAccent`; `false` disables hash-derived accent colors, while `true` or omission enables them. */
56
+ sessionAccent?: boolean;
55
57
  activeRepo: ActiveRepoContext | null;
56
58
  width: number;
57
59
  options: StatusLineSegmentOptions;
@@ -28,6 +28,8 @@ export interface ToolExecutionOptions {
28
28
  /** Session-persistent edit clipboard register, forked per preview frame. */
29
29
  clipboard?: Clipboard;
30
30
  showImages?: boolean;
31
+ /** Allow the name-keyed renderer registry only when the active tool is the built-in implementation. */
32
+ useBuiltInRenderer?: boolean;
31
33
  editFuzzyThreshold?: number;
32
34
  editAllowFuzzy?: boolean;
33
35
  /** Live-region probe used to settle detached task progress once the block