@omercnet/paseo-omp 0.2.1 → 0.3.0-next.100.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/CHANGELOG.md +26 -0
- package/README.md +25 -13
- package/SUPPORT.md +7 -3
- package/TESTING.md +21 -18
- package/client/composer-pill-settings.tsx +157 -0
- package/client/external-url.ts +15 -0
- package/client/mcp-authorization.tsx +169 -0
- package/client/mcp-popover.tsx +155 -0
- package/client/memory-panel.tsx +8 -3
- package/client/memory-popover.tsx +8 -4
- package/client/omp-config-surface.tsx +189 -29
- package/client/omp-plugin-manager.tsx +302 -131
- package/client/omp-store-picker.tsx +89 -0
- package/client/omp-store-state.ts +45 -0
- package/client/paseo-types.ts +9 -0
- package/client/provider-diagnostics-state.ts +18 -7
- package/client/quota-popover.tsx +8 -3
- package/client/quota-state.ts +16 -7
- package/client/sessions-popover.tsx +8 -3
- package/docs/alpha-release-checklist.md +6 -8
- package/docs/configuration.md +8 -4
- package/docs/core-provider-issue-audit.md +3 -2
- package/docs/images/mcp-authorization-compact.png +0 -0
- package/docs/images/mcp-controls-wide.png +0 -0
- package/docs/images/plugin-manager.png +0 -0
- package/docs/images/workspace-settings.png +0 -0
- package/docs/installation.md +35 -19
- package/index.client.tsx +339 -123
- package/index.server.ts +44 -14
- package/package.json +7 -8
- package/paseo-plugin.json +2 -2
- package/scripts/prepare-dependencies.mjs +24 -0
- package/server/mcp-browser.ts +95 -0
- package/server/memory.ts +2 -2
- package/server/omp-config.ts +16 -7
- package/server/omp-plugins.ts +70 -21
- package/server/omp-settings.ts +232 -24
- package/server/paths.ts +128 -11
- package/server/provider/catalog.ts +3 -4
- package/server/provider/connection.ts +248 -17
- package/server/provider/host-tools.ts +294 -26
- package/server/provider/omp-rpc.ts +498 -72
- package/server/provider/profile-providers.ts +249 -0
- package/server/provider/registration.ts +11 -0
- package/server/provider/security.ts +8 -10
- package/server/provider/session-descriptors.ts +306 -1
- package/server/provider/session.ts +704 -249
- package/server/provider/subsessions.ts +25 -2
- package/server/provider/timeline-projector.ts +104 -44
- package/server/provider-diagnostics.ts +122 -36
- package/server/quota.ts +3 -2
- package/server/sessions.ts +2 -2
- package/shared/composer-pill-settings.ts +28 -0
- package/shared/external-url.ts +21 -0
- package/shared/hub.ts +3 -3
- package/shared/mcp.ts +47 -0
- package/shared/memory.ts +2 -1
- package/shared/omp-config.ts +5 -1
- package/shared/omp-plugins.ts +74 -33
- package/shared/omp-settings.ts +8 -1
- package/shared/omp-store.ts +58 -0
- package/shared/provider-diagnostics.ts +12 -3
- package/shared/quota.ts +2 -1
- package/shared/sessions.ts +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.3.0](https://github.com/omercnet/paseo-plugins/compare/paseo-omp-v0.2.1...paseo-omp-v0.3.0) (2026-09-18)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **paseo-omp:** add first-class MCP management ([#64](https://github.com/omercnet/paseo-plugins/issues/64)) ([5a8fefa](https://github.com/omercnet/paseo-plugins/commit/5a8fefa9148e8d01f0461aa4a90619ec6ae2c2fa))
|
|
9
|
+
* **paseo-omp:** add workspace-scoped OMP management ([#59](https://github.com/omercnet/paseo-plugins/issues/59)) ([2807aec](https://github.com/omercnet/paseo-plugins/commit/2807aec6217ed2d52f8b4666f0a41a688109f8f5))
|
|
10
|
+
* **paseo-omp:** make composer pills configurable ([#76](https://github.com/omercnet/paseo-plugins/issues/76)) ([28e7501](https://github.com/omercnet/paseo-plugins/commit/28e75011a06a11cdc963187aa4106dfc21d561e6))
|
|
11
|
+
* **release:** publish plugins to npm ([#80](https://github.com/omercnet/paseo-plugins/issues/80)) ([3c93048](https://github.com/omercnet/paseo-plugins/commit/3c93048cfefda97d8c2bc1631e3428fb64bdad09))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Bug Fixes
|
|
15
|
+
|
|
16
|
+
* **paseo-omp:** advertise nested subsession capability ([#62](https://github.com/omercnet/paseo-plugins/issues/62)) ([fcb4e82](https://github.com/omercnet/paseo-plugins/commit/fcb4e8243e9559d70f26ac6945e2f3c0bf05d575))
|
|
17
|
+
* **paseo-omp:** bound model catalogs and retain safe failure diagnostics ([#73](https://github.com/omercnet/paseo-plugins/issues/73)) ([e70afb7](https://github.com/omercnet/paseo-plugins/commit/e70afb72be782446e7ff585bad40940c7231bdc5))
|
|
18
|
+
* **paseo-omp:** correlate terminal events by request ([#81](https://github.com/omercnet/paseo-plugins/issues/81)) ([41f756e](https://github.com/omercnet/paseo-plugins/commit/41f756e9bebf5cbc275e5cbd3657c37d45a18997))
|
|
19
|
+
* **paseo-omp:** fail closed on unowned later-turn terminal events ([#69](https://github.com/omercnet/paseo-plugins/issues/69)) ([072cd09](https://github.com/omercnet/paseo-plugins/commit/072cd09e38e450376bcd3f4c7b5eae9a670b56b5))
|
|
20
|
+
* **paseo-omp:** preserve prompt scheduling error fidelity ([#67](https://github.com/omercnet/paseo-plugins/issues/67)) ([1c6d549](https://github.com/omercnet/paseo-plugins/commit/1c6d549fddca48be8fd86b4dd2c5faea526c8ac0))
|
|
21
|
+
* **paseo-omp:** reconcile incomplete terminal outcomes ([#68](https://github.com/omercnet/paseo-plugins/issues/68)) ([854f4e6](https://github.com/omercnet/paseo-plugins/commit/854f4e6daddf905c671bb39a94d06a2de0c6d51d))
|
|
22
|
+
* **paseo-omp:** replay failed turns from native transcript ([#79](https://github.com/omercnet/paseo-plugins/issues/79)) ([4a13b77](https://github.com/omercnet/paseo-plugins/commit/4a13b778a9ba413b61fe0cc85878d3c333c161d2))
|
|
23
|
+
* **paseo-omp:** scope providers and auxiliary state to named profiles ([#74](https://github.com/omercnet/paseo-plugins/issues/74)) ([b265ad3](https://github.com/omercnet/paseo-plugins/commit/b265ad317a47230ec76dba799197443664492729))
|
|
24
|
+
* **paseo-omp:** settle concurrent startup races ([#70](https://github.com/omercnet/paseo-plugins/issues/70)) ([9d4e6ef](https://github.com/omercnet/paseo-plugins/commit/9d4e6efb26041f9c88ab4ed6c02a9526520b83e9))
|
|
25
|
+
* **paseo-omp:** show immutable approval mode ([#66](https://github.com/omercnet/paseo-plugins/issues/66)) ([4c586dc](https://github.com/omercnet/paseo-plugins/commit/4c586dc7d012127ee7570077a0d12cc0d6415bd4))
|
|
26
|
+
* **paseo-omp:** support Paseo 0.9 beta ([#103](https://github.com/omercnet/paseo-plugins/issues/103)) ([0444d52](https://github.com/omercnet/paseo-plugins/commit/0444d52078a52befa62bb52f44545f22ab10e8c7))
|
|
27
|
+
* **paseo-omp:** support unkeyed terminal events ([#89](https://github.com/omercnet/paseo-plugins/issues/89)) ([a00a831](https://github.com/omercnet/paseo-plugins/commit/a00a83158993fdf648fc10e06f1d8f8ebc62fa6a))
|
|
28
|
+
|
|
3
29
|
## [0.2.1](https://github.com/omercnet/paseo-plugins/compare/paseo-omp-v0.2.0...paseo-omp-v0.2.1) (2026-09-15)
|
|
4
30
|
|
|
5
31
|
|
package/README.md
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
# Paseo OMP plugin
|
|
2
2
|
|
|
3
|
-
Community OMP integration for Paseo. The plugin registers the distinct `omp-plugin` provider and coexists with Paseo's bundled `omp` provider.
|
|
3
|
+
Community OMP integration for Paseo. The plugin registers the distinct `omp-plugin` provider plus named profile providers and coexists with Paseo's bundled `omp` provider.
|
|
4
4
|
|
|
5
5
|
> **Alpha preview:** persistence and protocol contracts are tested, but upgrades may still require re-importing sessions created by an earlier preview.
|
|
6
6
|
|
|
7
7
|
## Quick start
|
|
8
8
|
|
|
9
|
-
Requirements: Paseo
|
|
9
|
+
Requirements: Paseo `>=0.8.0 <0.10.0`, OMP `18.1.15` or newer, and OMP RPC protocol v2. Paseo `0.9.0-beta.1` or newer is required for nested provider-subagent ancestry and spawning-tool links, and is recommended for npm-managed installation and the complete client integration.
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
-
paseo plugin
|
|
12
|
+
paseo plugin install npm:@omercnet/paseo-omp@<version>
|
|
13
13
|
paseo plugin ls paseo-omp
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
-
Open the **OMP** sidebar to review the provider-profile contract, browse and edit native scalar settings, manage OMP-native plugins, verify runtime health, and inspect storage and process diagnostics. Then create an agent and select **OMP Plugin**.
|
|
16
|
+
Open the **OMP** sidebar to review the provider-profile contract, choose which composer pills appear, browse and edit native scalar settings, manage OMP-native plugins, verify runtime health, and inspect storage and process diagnostics. Then create an agent and select **OMP Plugin**. Its optional **MCP** composer control runs OMP-native management commands in the current session; setup questions and authorization stay in that chat timeline, where OAuth can open in a workspace-scoped Paseo Browser or on the current device. Composer pill preferences are shared by clients connected to the same host; normal use requires no other plugin-specific settings.
|
|
17
17
|
|
|
18
18
|
- [Install, update, rollback, and local development](docs/installation.md)
|
|
19
19
|
- [Configuration and every provider option](docs/configuration.md)
|
|
@@ -22,13 +22,23 @@ Open the **OMP** sidebar to review the provider-profile contract, browse and edi
|
|
|
22
22
|
- [Core-provider issue and parity audit](docs/core-provider-issue-audit.md)
|
|
23
23
|
- [Alpha release checklist](docs/alpha-release-checklist.md)
|
|
24
24
|
|
|
25
|
-
The plugin uses
|
|
25
|
+
The plugin uses public Paseo 0.8 and 0.9 beta provider contracts and registers distinct `omp-plugin` and `omp-plugin-<profile>` identities; it does not modify the bundled `omp` provider.
|
|
26
|
+
|
|
27
|
+
## Named OMP profiles
|
|
28
|
+
|
|
29
|
+
At startup the plugin discovers directory names under `~/.omp/profiles/` (or `PI_CONFIG_DIR`) and registers **OMP · <profile>** for each valid lowercase name. Select that provider when creating a profile-backed agent. Discovery, launch, recovery and persisted session listing share its fixed profile and session root. Matching command wrappers, including Doppler, remain supported; conflicting profile or session-directory overrides fail before launch. Plain `env NAME=value omp` wrappers are supported, but environment-control flags such as `env -i` and `env -u` are rejected because they can discard the selected store. Profile-specific XDG roots cannot be overridden by per-launch environment values. Reload the plugin after adding a profile.
|
|
30
|
+
|
|
31
|
+
Paseo 0.8 does not pass agent launch options to its model picker. Separate provider identities let the picker request the correct profile catalog before an agent exists. Existing `omp-plugin` and bundled `omp` agents retain their provider; they are not migrated automatically. Profile names use OMP's lowercase grammar, including dotted names such as `team.prod`.
|
|
32
|
+
|
|
33
|
+
The OMP sidebar and memory panel expose an explicit store selector. Settings, plugins, quota, history, memory and diagnostics use that selection, and profile-agent popovers derive it from the provider ID. OMP-compatible XDG data and state roots are honored when a migrated profile uses them. Default-provider views are labelled **Daemon default store**; changing `providerOptions.command` on the default provider does not make those views profile-aware. Workspace configuration remains project-scoped, with the selected profile supplying inherited settings. Hub records are daemon-wide. The RPCs also accept an explicit absolute `store.agentDir` for custom stores; it is mutually exclusive with `store.profile`.
|
|
34
|
+
|
|
35
|
+
Profile selection is request-local: concurrent clients cannot change each other's process environment or cached results. Settings edits affect the selected store immediately.
|
|
26
36
|
|
|
27
37
|
## Paseo provider SDK coverage
|
|
28
38
|
|
|
29
|
-
This matrix inventories the complete capability set exported by the pinned `@getpaseo/plugin` 0.
|
|
39
|
+
This matrix inventories the complete capability set exported by the pinned `@getpaseo/plugin` 0.9.0-beta.1 provider SDK. It measures strict SDK surface coverage, not general product quality.
|
|
30
40
|
|
|
31
|
-
**Current capability completeness:
|
|
41
|
+
**Current capability completeness: 61.8%.** The provider advertises 11 of 17 capabilities (64.7%); ten are complete and `session.configure` is partial.
|
|
32
42
|
|
|
33
43
|
Scoring is deliberately mechanical so releases remain comparable:
|
|
34
44
|
|
|
@@ -39,7 +49,7 @@ Scoring is deliberately mechanical so releases remain comparable:
|
|
|
39
49
|
|
|
40
50
|
| SDK capability | Completeness | Support and gap |
|
|
41
51
|
| --- | ---: | --- |
|
|
42
|
-
| `prompt.message` | **100%** | Text, structured attachments, optimistic correlation, streaming, and terminal outcomes map to native OMP prompts. |
|
|
52
|
+
| `prompt.message` | **100%** | Text, structured attachments, optimistic correlation, streaming, and terminal outcomes map to native OMP prompts. Matching terminal request IDs remain authoritative; released OMP builds without them use the ordered compatibility policy described below. |
|
|
43
53
|
| `prompt.command` | **100%** | Native command discovery plus structured `compact`, `autocompact`, `handoff`, `steer`, and `follow-up` dispatch. Individual commands can still fail when their documented OMP prerequisites are absent. |
|
|
44
54
|
| `prompt.image` | **100%** | Native image blocks for capable models; private bounded temporary files with cleanup for text-only models. |
|
|
45
55
|
| `prompt.output_schema` | **0%** | Not advertised. OMP has no equivalent structured-output contract; `outputSchema` fails visibly. |
|
|
@@ -55,7 +65,7 @@ Scoring is deliberately mechanical so releases remain comparable:
|
|
|
55
65
|
| `session.unarchive` | **0%** | Not advertised; there is no native OMP archive state to reverse. |
|
|
56
66
|
| `permission` | **100%** | Typed tool permissions when negotiated, with a bounded generic interaction fallback for OMP 18.1.15. Allow, deny, cancel, timeout, and interruption are covered. |
|
|
57
67
|
| `permission.tool_policy` | **0%** | Not advertised. Exact MCP preapproval policy cannot be preserved through OMP `set_host_tools`, so the plugin fails closed instead of broadening access. |
|
|
58
|
-
| `timeline.plugin` | **
|
|
68
|
+
| `timeline.plugin` | **100%** | Negotiated OMP MCP authorization requests render as interactive, schema-validated cards that can open a workspace-scoped Paseo Browser tab, with an on-device and built-in-notification fallback. |
|
|
59
69
|
|
|
60
70
|
Provider functionality outside the capability flags is tracked separately:
|
|
61
71
|
|
|
@@ -68,7 +78,7 @@ Provider functionality outside the capability flags is tracked separately:
|
|
|
68
78
|
| Models, modes, and thinking catalog | **100%** | Native catalog is mapped to opaque public model IDs with committed defaults and permission-gated modes. |
|
|
69
79
|
| Connection `send` / `onEvent` / `close` lifecycle | **100%** | Request correlation, multi-session ownership, process recovery, teardown, and provider reload/removal are covered. |
|
|
70
80
|
| Session launch: cwd, env, system prompt, title, and persistence | **100%** | Complete launch configuration is bounded, validated, forwarded, and re-read on recovery; selected daemon environment values are resolved only when catalog and session children spawn. |
|
|
71
|
-
| MCP server forwarding and host tools | **100%** | Configured MCP tools are discovered, namespaced, labeled, executed, canceled, and bounded. Caller-scoped Paseo orchestration tools retain their native names, such as `create_agent` and `list_profiles`, so OMP skills can invoke them directly. Exact `toolPolicy` remains the separate 0% capability above. |
|
|
81
|
+
| MCP server forwarding and host tools | **100%** | Configured MCP tools are discovered, namespaced, labeled, executed, canceled, and bounded. Caller-scoped Paseo orchestration tools retain their native names, such as `create_agent` and `list_profiles`, so OMP skills can invoke them directly. The MCP composer control delegates native server management to OMP instead of duplicating its profile and workspace precedence. Exact `toolPolicy` remains the separate 0% capability above. |
|
|
72
82
|
| Denied native tools | **100%** | `disallowedTools` becomes an explicit OMP allow-list; unknown names fail closed. |
|
|
73
83
|
| Commands and committed session state events | **100%** | Publishes `session.commands`, `session.opened`, `session.config`, `session.ready`, and request completion in protocol order. |
|
|
74
84
|
| Built-in timeline snapshots | **100%** | Assistant, reasoning, tools, todos, notifications, errors, compaction, and friendly MCP labels use stable IDs and complete snapshots. OMP emits client-safe PNG/JPEG when possible; validated legacy WebP images render on capable clients with an explicit per-image fallback elsewhere. |
|
|
@@ -83,11 +93,13 @@ Tracking rules:
|
|
|
83
93
|
|
|
84
94
|
## Compatibility and coexistence
|
|
85
95
|
|
|
86
|
-
The plugin always remains a separate provider. It registers
|
|
96
|
+
The plugin always remains a separate provider. It registers `omp-plugin` and `omp-plugin-<profile>` identities; it never registers, overrides, removes, or migrates Paseo's bundled `omp` provider. Both identities may be enabled on the same daemon and selected independently per agent.
|
|
97
|
+
|
|
98
|
+
Existing agents whose provider is `omp` remain owned by the bundled provider. New plugin agents persist under their selected `omp-plugin` or `omp-plugin-<profile>` identity with the plugin's versioned opaque handle. The plugin can list and import OMP-native sessions through its own provider flow, but it performs no implicit conversion of bundled-provider records.
|
|
87
99
|
|
|
88
|
-
|
|
100
|
+
OMP `18.1.15` is the oldest version tested end to end. The direct provider's hard compatibility gate is `rpc-ui` protocol v2: metadata-free legacy ready frames and v1-only runtimes are rejected before a provider session opens because they cannot support the advertised persistence and conversation-rewind capabilities. Typed tool approvals remain capability-gated and fall back as described above. For terminal completion, a matching `agent_end.requestId` is authoritative and mismatches are ignored before state changes. Released OMP 18.2.x builds that omit that field use an ordered fallback requiring a fresh correlated native user entry followed by current-turn assistant activity, an idle non-compacting runtime, and no conflicting permission, tool, steer, or child-session work. Ambiguous events while OMP is active are ignored; unresolved ambiguity after confirmed idle fails only the Paseo turn. This trades a bounded residual same-agent stale-event risk for compatibility with released OMP instead of terminating and lazily restarting the runtime after every later prompt. Paseo clients, including mobile clients inside reconnect grace, do not own or terminate the daemon-managed OMP session.
|
|
89
101
|
|
|
90
|
-
|
|
102
|
+
Paseo 0.9.0-beta.1 is the verified canary target and the first release that preserves nested provider-subagent ancestry and spawning-tool links. The required full Docker canary passes there with OMP 18.1.15 and 18.2.0. Paseo 0.9 also provides npm-managed plugin sources, platform-owned external URL opening, and whole-item timeline transforms before Overview grouping. Paseo 0.8.x remains supported for other provider operations and Git or directory installation; its clients do not provide the external URL opener, retain their older timeline presentation semantics, and flatten nested provider subagents.
|
|
91
103
|
|
|
92
104
|
Install, update, disable, or remove `paseo-omp` independently of the bundled provider. Verify the provider snapshot contains `omp-plugin` after installation; a bundled `omp` entry may remain present and is not modified by this plugin.
|
|
93
105
|
|
package/SUPPORT.md
CHANGED
|
@@ -12,12 +12,12 @@ After the failure is isolated:
|
|
|
12
12
|
- report a Paseo plugin SDK, loader, or provider-protocol defect to [Paseo](https://github.com/getpaseo/paseo/issues);
|
|
13
13
|
- keep adaptation, packaging, and cross-project compatibility work in this repository.
|
|
14
14
|
|
|
15
|
-
Do not put credentials, private repository paths, session transcripts, or unredacted RPC payloads in an issue. Report vulnerabilities through the [private GitHub Security Advisory form](https://github.com/omercnet/paseo-plugins/security/advisories/new), not a public issue.
|
|
15
|
+
Do not put credentials, private repository paths, session transcripts, or unredacted RPC payloads in an issue. Report vulnerabilities through the [private GitHub Security Advisory form](https://github.com/omercnet/paseo-plugins/security/advisories/new), not a public issue.
|
|
16
16
|
|
|
17
17
|
## Supported versions
|
|
18
18
|
|
|
19
|
-
- Paseo:
|
|
20
|
-
- OMP: `18.1.15` is the oldest release
|
|
19
|
+
- Paseo: `>=0.8.0 <0.10.0` on both the daemon and every app loading the client entry. The pinned SDK and controlled canary use `0.9.0-beta.1`, the first release that preserves nested provider-subagent ancestry and spawning-tool links. Paseo 0.8.x remains supported for other provider operations.
|
|
20
|
+
- OMP: `18.1.15` is the oldest supported release. The required full Docker canary passes with 18.1.15 and 18.2.0; the hard runtime contract remains `rpc-ui` protocol v2, not the version string alone.
|
|
21
21
|
- Plugin release channel: alpha. Backward compatibility is best effort until stable `0.1.0`; every known migration requirement must be stated in the release notes.
|
|
22
22
|
- Typed approvals: optional. When both peers negotiate `typedToolApprovals: 1`, the plugin uses typed tool permissions. Otherwise it retains the bounded generic extension-question flow.
|
|
23
23
|
|
|
@@ -26,13 +26,17 @@ Do not put credentials, private repository paths, session transcripts, or unreda
|
|
|
26
26
|
- `omp` and `omp-plugin` are independent provider identities. Agents, provider settings, and persisted handles do not migrate automatically between them.
|
|
27
27
|
- Do not open the same underlying OMP session concurrently through both providers. Reservation tracking is provider-local and cannot coordinate ownership with Paseo's bundled adapter.
|
|
28
28
|
- OMP 18.1.15 does not advertise typed tool approvals. The plugin uses its bounded generic permission fallback until both peers negotiate `typedToolApprovals: 1`.
|
|
29
|
+
- OMP releases through 18.2.x may omit the originating prompt `requestId` from `agent_end`. A matching ID is authoritative when present, and a mismatch is discarded before changing turn state. For an unkeyed later-turn terminal, the plugin uses a bounded ordered fallback: the accepted prompt must not be known local-only, a fresh native user entry must correlate to it, current-turn assistant activity must follow that entry, OMP must report idle and non-compacting, and no permission, tool, steer, or child-session work may remain. Ambiguous candidates are ignored while OMP is active; once OMP is confirmed idle, unresolved ambiguity fails only the Paseo turn and keeps the OMP process available. This deliberately accepts a residual same-agent risk: a sufficiently delayed unkeyed event with indistinguishable ordered evidence can still be misattributed. It is safer than accepting any idle `agent_end`, while remaining usable with released OMP builds that cannot provide request identity.
|
|
30
|
+
- Timeline correlation rebuilds an invalid watermark from a complete pre-prompt `get_branch_messages` snapshot, not replayed model context or an evicting identity cache. Snapshots are limited to 1,024 entries and 4 MiB; duplicate IDs, surplus exact-text matches, unavailable history, and exceeded bounds leave users uncorrelated rather than claiming an old entry. Repeated accepted prompts within a turn consume matching branch occurrences in order.
|
|
29
31
|
- Configured MCP servers are supported and bridged into OMP. Paseo's own orchestration tools appear under their native names when the daemon's **Enable Paseo tools** / `daemon.mcp.injectIntoAgents` setting is enabled; other MCP servers remain namespaced. Exact Paseo `toolPolicy` preapproval cannot be represented by OMP `set_host_tools` and therefore fails session startup closed. `disallowedTools` applies only to recognized native OMP built-ins; unknown names are rejected and MCP tools are not silently filtered through it.
|
|
30
32
|
- `qwen2.5:0.5b` is provided only for free exploratory inference. It may ignore exact-output instructions and is not a deterministic protocol or tool-use oracle; use `canary-mock/Deterministic Canary` for assertions.
|
|
31
33
|
- The deterministic mock does not implement OMP's compaction-summary contract, so `/compact` reports `OMP compaction failed` in the canary; compaction remains covered by protocol fixtures.
|
|
32
34
|
- `/handoff` reports `OMP command failed` in the controlled canary even with deterministic role models configured; treat handoff as unavailable there until its native prerequisite is isolated.
|
|
33
35
|
- On official Paseo 0.8.0, requesting a live approval-mode change that the plugin rejects can trigger the daemon's unhandled-rejection restart path. Create a new `full`, `write`, or `ask` session instead of changing mode in place.
|
|
36
|
+
- Paseo 0.8 clients do not expose the platform-owned plugin URL opener and transform timeline items after Overview grouping. Use a 0.9.0-beta.1 app for external documentation/device-authorization actions and for reliable image-card transformation of every source tool call.
|
|
34
37
|
- Native Fast mode and a first-class plan mode are not exposed. `/handoff` is implemented but is not reproducible in the controlled canary without its native OMP workflow prerequisites.
|
|
35
38
|
- Terminal-started OMP sessions are discoverable and importable but are not registered automatically through a terminal hook.
|
|
39
|
+
- Paseo clients do not own OMP sessions. Mobile or desktop disconnects remain subject to Paseo's reconnect grace while the daemon-owned provider and OMP child continue independently; reconnecting can reveal an existing turn but does not transfer or sever runtime ownership.
|
|
36
40
|
- OMP tool output reaching RPC stdout is strictly parsed and bounded, but channel purity ultimately depends on OMP keeping non-protocol output off stdout.
|
|
37
41
|
|
|
38
42
|
The deduplicated comparison with every known OMP report in `getpaseo/paseo` is maintained in [docs/core-provider-issue-audit.md](docs/core-provider-issue-audit.md).
|
package/TESTING.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# OMP provider parity audit
|
|
2
2
|
|
|
3
|
-
Validated against the Paseo plugin SDK versions pinned in `package.json
|
|
3
|
+
Validated against the Paseo plugin SDK versions pinned in `package.json` and the real OMP compatibility matrix: high-use historical releases 17.2.15, 17.3.4, 18.0.11, and 18.1.10; minimum supported release 18.1.15; latest published 18.1 patch 18.1.22; and current release 18.2.0. On 2026-09-18, the full controlled canary passed against OMP 18.1.15 and 18.2.0 on official Paseo image `0.9.0-beta.1@sha256:f75a0eb3547ad3cc6bbdeaa7277d2d50eb4d06a9dd669d480371d7adf1c911b5`.
|
|
4
4
|
|
|
5
5
|
Classifications:
|
|
6
6
|
|
|
@@ -31,7 +31,8 @@ Classifications:
|
|
|
31
31
|
| Text prompts | **Equivalent** | Bounded multipart text joins and native prompt lifecycle coverage in `tests/provider.test.ts`. |
|
|
32
32
|
| Image prompts | **Equivalent** | Valid native image models receive image blocks; text-only models receive private content-addressed local files with an aggregate cap and turn/session/failure cleanup. The file path is valid because the direct provider and OMP child share the daemon host. |
|
|
33
33
|
| Structured attachments | **Equivalent** | Forge change requests/issues, legacy GitHub forms, text, reviews, and uploaded files render to bounded OMP prompt text; regression in `tests/provider.test.ts`. |
|
|
34
|
-
| Optimistic message correlation | **Equivalent** | Native entry lookup, repeated-text occurrence
|
|
34
|
+
| Optimistic message correlation | **Equivalent** | Native entry lookup, repeated-text occurrence correlation, steering correlation, replay-boundary dedupe, and exactly-one `session.prompt_result` regressions. Bounded branch snapshots rebuild incomplete or evicted replay watermarks; duplicate IDs, surplus matching entries, unavailable snapshots, and count/byte overflow retain local user-message fallback instead of claiming an old entry. |
|
|
35
|
+
| Terminal correlation on later turns | **Equivalent with legacy fallback** | A matching `agent_end.requestId` is authoritative and a mismatch is discarded before turn state changes. Released OMP builds that omit the field use ordered evidence from the accepted prompt: a fresh branch-correlated native user entry, later current-turn assistant activity, an idle non-compacting runtime, and no conflicting permission, tool, steer, or child-session work. `prompt_result.agentInvoked: false` remains local-only. Active ambiguous terminals are ignored; confirmed-idle ambiguity fails only the Paseo turn without killing the OMP process. Tests cover three sequential legacy prompts, stale terminals before evidence and while active, repeated text, local-only results, keyed mismatch/match, and degraded state/history. The remaining risk is same-agent misattribution when a delayed unkeyed event is indistinguishable from this ordered evidence. |
|
|
35
36
|
| Streaming assistant text | **Equivalent** | `OmpTimelineProjector` publishes stable complete snapshots with frame coalescing and bounded retained bytes. |
|
|
36
37
|
| Streaming reasoning | **Equivalent** | Indexed thinking blocks map to stable `reasoning` items and share stream bounds. |
|
|
37
38
|
| `contentIndex` ordering | **Equivalent** | Stable 0→1→0 updates, sparse-index rejection, and 64-block bounds are tested in `tests/provider.test.ts`. |
|
|
@@ -40,8 +41,8 @@ Classifications:
|
|
|
40
41
|
| Compaction events | **Equivalent** | Manual and automatic operations retain IDs, distinguish retry/skipped/canceled/failed states, flush streams, and refresh usage. |
|
|
41
42
|
| Custom messages | **Equivalent** | Displayable custom and bash-execution messages map to typed or fallback items; `display: false` remains hidden. |
|
|
42
43
|
| Advisor messages | **Equivalent** | Advisor notes preserve severity/attribution in stable tool-call blocks; `advisor_yielded` emits completion notice. |
|
|
43
|
-
| System notices | **Equivalent** | Native notices and safe passive UI notifications map to bounded notification items; hidden custom notices remain hidden. |
|
|
44
|
-
| Ask interactions | **Equivalent** | Select/confirm/input/editor questions, option descriptions, fixed-only rejection, bounded freeform input, native sentinel/follow-up submission, cancellation, timeout, and turn ownership are covered by permission regressions. |
|
|
44
|
+
| System notices | **Equivalent** | Native notices and safe passive UI notifications map to bounded notification items; hidden custom notices remain hidden. Negotiated MCP authorization URLs use a schema-validated plugin item, can route through the caller-scoped Paseo `browser_new_tab` tool, and retain a notification fallback. |
|
|
45
|
+
| Ask interactions | **Equivalent** | Select/confirm/input/editor questions, including remote OAuth redirect/code completion, option descriptions, fixed-only rejection, bounded freeform input, native sentinel/follow-up submission, cancellation, timeout, and turn ownership are covered by permission regressions. Allow, deny, cancel, timeout, and interruption remain in the agent timeline. |
|
|
45
46
|
| Typed tool permission presentation | **Equivalent** | OMP `typedToolApprovals: 1` is negotiated reciprocally; strict native request/cancel/response frames are correlated exactly once and mapped from trusted shell/edit/write identity to bounded, content-preserving `kind: "tool"` permissions. Older OMP builds retain generic extension questions. |
|
|
46
47
|
| Slash command catalog | **Equivalent** | Native commands and aliases refresh authoritatively; the bundled `compact`, `autocompact`, `handoff`, `steer`, and `follow-up` commands are always published. |
|
|
47
48
|
| Manual `/compact` | **Equivalent** | Uses native `compact`, exposes one loading/completed operation, keeps long requests alive, refreshes usage, and supports interruption. |
|
|
@@ -56,7 +57,7 @@ Classifications:
|
|
|
56
57
|
| Retry fallback events | **Equivalent** | Fallback telemetry renders bounded status items and triggers committed model/thinking refresh without trusting event strings as state. |
|
|
57
58
|
| Context and token usage | **Equivalent** | Periodic, post-compaction, fallback, terminal, timeout, and stale-generation samples publish `session.usage`. |
|
|
58
59
|
| Native host tools | **Equivalent** | Paseo's caller-scoped MCP endpoint is converted to OMP host tools with workspace identity, progress, cancellation, bounded results, and ownership cleanup. |
|
|
59
|
-
| Configured MCP servers | **Equivalent** | stdio/http/SSE transports are opened by the plugin host process, namespaced, paginated, bounded, and passed through OMP's native host-tool API. |
|
|
60
|
+
| Configured MCP servers | **Equivalent** | stdio/http/SSE transports are opened by the plugin host process, namespaced, paginated, bounded, and passed through OMP's native host-tool API. The agent-scoped MCP composer control invokes OMP's native management commands without copying its discovery or credential state. |
|
|
60
61
|
| Subagents | **Equivalent** | Live lifecycle/progress/events create provider-owned child sessions; subscription failure removes the negotiated capability. |
|
|
61
62
|
| Nested child timelines | **Equivalent** | Child/grandchild ancestry, stable IDs, live restart, cold transcript replay, terminal states, and cumulative replay bounds are covered. |
|
|
62
63
|
| Conversation rewind | **Equivalent** | Only conversation scope is advertised; active-turn/stale-token rejection and branch replay are tested. |
|
|
@@ -94,9 +95,17 @@ npm run test:integration:wsl
|
|
|
94
95
|
|
|
95
96
|
The WSL script skips when `wsl.exe` or WSL Node is unavailable. Set `PASEO_OMP_REQUIRE_WSL=1` to make either condition fatal, as CI does. `PASEO_OMP_WSL_NODE` may override the default `node` executable inside WSL.
|
|
96
97
|
|
|
97
|
-
|
|
98
|
+
Run the full local provider integration canary with:
|
|
98
99
|
|
|
99
|
-
|
|
100
|
+
```sh
|
|
101
|
+
npm run test:integration:canary
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Set `PASEO_CANARY_OMP_VERSION` to exercise another pinned release. The local runner knows the SHA-256 values for every version in the compatibility matrix; an unlisted version requires explicit `PASEO_CANARY_OMP_SHA256_AMD64` and `PASEO_CANARY_OMP_SHA256_ARM64` values. It allocates isolated loopback ports, builds a version-specific image, waits for both services to become healthy, runs the deterministic provider scenarios, prints container logs on failure, and always removes its containers, volumes, and image namespace. CI runs this full canary for OMP 18.1.15 and 18.2.0 whenever `paseo-omp` changes; both matrix entries feed the required `CI sentinel` gate and must pass before the supported OMP floor changes.
|
|
105
|
+
|
|
106
|
+
The Linux real-OMP CI matrix downloads checksummed `omp-linux-x64` assets for OMP 17.2.15, 17.3.4, 18.0.11, 18.1.10, 18.1.15, 18.1.22, and 18.2.0, verifies each binary's pinned GitHub release SHA-256, and runs `PASEO_OMP_REAL_E2E=1 PASEO_OMP_VERSION=<version> npm test -- tests/provider.real.e2e.test.ts`. The historical entries are the four pre-floor releases with more than 4,000 downloads shown by npm for the seven days ending 2026-09-15; they are compatibility regression probes, not a support commitment. The remaining entries cover the supported floor, newest patch in that minor line, and current release. The test uses the real OMP binary and a local deterministic OpenAI-compatible model endpoint, including three sequential prompts on one native session, a Bash tool, and oversized-image transport.
|
|
107
|
+
|
|
108
|
+
The controlled canary passed end to end with OMP 18.1.15 and 18.2.0 on 2026-09-18. In addition to runtime health, catalog, prompts, tools, MCP, permissions, steering, interruption, persistence, Hub, usage, rewind, and plugin RPC coverage, it verified that a direct child has `parentSubagentId: null` and the root task's `toolCallId`, a nested child has its direct parent's public subagent ID and the nested task's `toolCallId`, both children finish as `completed`, and both timelines remain independently fetchable without cross-contamination.
|
|
100
109
|
|
|
101
110
|
## OMP RPC compatibility intake
|
|
102
111
|
|
|
@@ -115,11 +124,7 @@ The plugin maintainer owns triage and adaptation. Escalate an isolated OMP imple
|
|
|
115
124
|
|
|
116
125
|
## Release publication
|
|
117
126
|
|
|
118
|
-
`release-please.yml`
|
|
119
|
-
|
|
120
|
-
The publisher builds the self-contained ZIP, writes its corruption-detection checksum, creates a signed GitHub build-provenance attestation for both files, rechecks that the tag still resolves to the gated SHA, and uploads with `--clobber`. To recover an interrupted upload, dispatch **Publish Paseo OMP** with the existing `paseo-omp-v<version>` tag; the same identity and CI gates apply, so reruns are idempotent.
|
|
121
|
-
|
|
122
|
-
The SHA-256 file is not a signature. Consumers authenticate the archive with `gh attestation verify` and may use the checksum only to detect accidental transfer or storage corruption.
|
|
127
|
+
`release-please.yml` creates GitHub releases and publishes every released plugin path to npm through trusted publishing. Stable versions use the `latest` distribution tag; prereleases use `next`. npm generates provenance from the GitHub Actions OIDC identity, and the workflow waits for registry propagation before succeeding.
|
|
123
128
|
|
|
124
129
|
### Alpha release channel
|
|
125
130
|
|
|
@@ -131,17 +136,15 @@ The go/no-go criteria, manual acceptance boundary, and alpha limitation list are
|
|
|
131
136
|
|
|
132
137
|
## Audit verification
|
|
133
138
|
|
|
134
|
-
- `npm run check`: clean
|
|
139
|
+
- `npm run check`: clean.
|
|
135
140
|
- `npm run typecheck`: clean.
|
|
136
141
|
- `npm test`: full Vitest suite passed, with environment-gated scenarios skipped when their runtimes were unavailable.
|
|
137
142
|
- `npm test -- tests/provider-conformance.test.ts`: host-boundary conformance coverage includes `prompt.command`, `session.configure`, typed and fallback permission allow/deny/cancel paths, registry-driven reload/removal, verified stubborn-descendant cleanup, and sequential turns plus interrupt races with post-turn barriers.
|
|
138
|
-
- `PASEO_OMP_REAL_E2E=1 npm test -- tests/provider.real.e2e.test.ts`: the installed
|
|
143
|
+
- `PASEO_OMP_REAL_E2E=1 PASEO_OMP_VERSION=<version> npm test -- tests/provider.real.e2e.test.ts`: the installed matrix version's catalog and hermetic real-binary text/Bash and oversized-image scenarios run against a local deterministic model.
|
|
139
144
|
- `npm run test:coverage`: Vitest enforces aggregate 85% function and 89% line coverage over loaded source modules. Generated `dist/**` trees are excluded.
|
|
140
|
-
- `npm run
|
|
141
|
-
- `npm run test:integration:install`: the self-contained archive imports dependencies and compiles with an unreachable proxy; a fresh Git-style checkout installs with lifecycle scripts disabled, retains required runtime packages, typechecks, bundles both entries, and loads the server contribution.
|
|
145
|
+
- `npm run test:integration:install`: npm package acquisition retains required production dependencies, and a fresh Git-style checkout runs frozen production-only preparation with lifecycle scripts disabled. Both installed trees resolve runtime dependencies, compile the client and server entries with Paseo's host compiler, and load the server contribution.
|
|
142
146
|
- `npm run test:integration:docker`: verifies the host/container ownership boundary.
|
|
143
147
|
- `npm run test:integration:wsl`: locally skips when `wsl.exe` is unavailable; Windows CI sets `PASEO_OMP_REQUIRE_WSL=1`, so this boundary remains required there.
|
|
144
|
-
- `
|
|
145
|
-
- `mise x actionlint@1.7.12 -- actionlint .github/workflows/*.yml`: passed.
|
|
148
|
+
- `npm run test:integration:canary`: passed against OMP 18.1.15 and 18.2.0 on official Paseo `0.9.0-beta.1`; direct and nested ancestry, spawning-tool links, terminal status, and independently addressable child timelines passed.
|
|
146
149
|
- `zizmor .github/workflows`: no findings (offline audit; six repository-wide suppressions remain).
|
|
147
150
|
- Release Please 17.1.2 `config.json` and `manifest.json` schema validation: passed for `release-please-config.json` and `.release-please-manifest.json`.
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { type PluginSurfaceProps, type SettingsState, useSettings } from "@getpaseo/plugin/client";
|
|
2
|
+
import {
|
|
3
|
+
SettingsAction,
|
|
4
|
+
SettingsCard,
|
|
5
|
+
SettingsSection,
|
|
6
|
+
SettingsSwitch,
|
|
7
|
+
} from "@getpaseo/plugin/client/ui";
|
|
8
|
+
import { useCallback, useEffect, useMemo } from "react";
|
|
9
|
+
import { Text, View } from "react-native";
|
|
10
|
+
import {
|
|
11
|
+
type ComposerPillKey,
|
|
12
|
+
type ComposerPillSettings,
|
|
13
|
+
composerPillSettings,
|
|
14
|
+
DEFAULT_COMPOSER_PILL_SETTINGS,
|
|
15
|
+
} from "../shared/composer-pill-settings";
|
|
16
|
+
|
|
17
|
+
type ReadySettings = Extract<
|
|
18
|
+
SettingsState<typeof composerPillSettings.schema>,
|
|
19
|
+
{ status: "ready" }
|
|
20
|
+
>;
|
|
21
|
+
|
|
22
|
+
const PILLS: readonly { key: ComposerPillKey; label: string; hint: string }[] = [
|
|
23
|
+
{
|
|
24
|
+
key: "mcp",
|
|
25
|
+
label: "MCP",
|
|
26
|
+
hint: "OMP-native server controls on OMP Plugin agents",
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
key: "hub",
|
|
30
|
+
label: "Hub",
|
|
31
|
+
hint: "Supervised process status when this workspace has Hub processes",
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
key: "memory",
|
|
35
|
+
label: "Memory",
|
|
36
|
+
hint: "Retained facts for the current workspace",
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
key: "sessions",
|
|
40
|
+
label: "Sessions",
|
|
41
|
+
hint: "Recent OMP prompts for the current workspace",
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
key: "quota",
|
|
45
|
+
label: "Quota",
|
|
46
|
+
hint: "Provider quota usage when OMP has matching account data",
|
|
47
|
+
},
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
function ComposerPillControls({
|
|
51
|
+
settings,
|
|
52
|
+
onChange,
|
|
53
|
+
}: {
|
|
54
|
+
settings: ReadySettings;
|
|
55
|
+
onChange(settings: ComposerPillSettings): void;
|
|
56
|
+
}) {
|
|
57
|
+
const save = useCallback(
|
|
58
|
+
async (key: ComposerPillKey, value: boolean) => {
|
|
59
|
+
const next = { ...settings.values, [key]: value };
|
|
60
|
+
if (await settings.save(next, settings.revision)) onChange(next);
|
|
61
|
+
},
|
|
62
|
+
[onChange, settings],
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
return (
|
|
66
|
+
<SettingsSection
|
|
67
|
+
title="Composer pills"
|
|
68
|
+
info="Applies to all workspaces and connected clients on this host."
|
|
69
|
+
>
|
|
70
|
+
<SettingsCard>
|
|
71
|
+
{PILLS.map(({ key, label, hint }) => (
|
|
72
|
+
<SettingsSwitch
|
|
73
|
+
key={key}
|
|
74
|
+
label={label}
|
|
75
|
+
hint={hint}
|
|
76
|
+
value={settings.values[key]}
|
|
77
|
+
disabled={settings.saving}
|
|
78
|
+
onValueChange={(value) => void save(key, value)}
|
|
79
|
+
/>
|
|
80
|
+
))}
|
|
81
|
+
<SettingsAction
|
|
82
|
+
label="Restore composer pill defaults"
|
|
83
|
+
actionLabel="Reset"
|
|
84
|
+
disabled={settings.saving}
|
|
85
|
+
onPress={async () => {
|
|
86
|
+
if (await settings.reset()) onChange({ ...DEFAULT_COMPOSER_PILL_SETTINGS });
|
|
87
|
+
}}
|
|
88
|
+
/>
|
|
89
|
+
{settings.saveError ? (
|
|
90
|
+
<SettingsAction
|
|
91
|
+
label="Reload saved composer preferences"
|
|
92
|
+
hint="Use after a conflict or connection error"
|
|
93
|
+
error={settings.saveError}
|
|
94
|
+
actionLabel="Reload"
|
|
95
|
+
disabled={settings.saving}
|
|
96
|
+
onPress={settings.reload}
|
|
97
|
+
/>
|
|
98
|
+
) : null}
|
|
99
|
+
</SettingsCard>
|
|
100
|
+
</SettingsSection>
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function ComposerPillSettingsSection({
|
|
105
|
+
theme,
|
|
106
|
+
onChange,
|
|
107
|
+
}: {
|
|
108
|
+
theme: PluginSurfaceProps["theme"];
|
|
109
|
+
onChange(settings: ComposerPillSettings): void;
|
|
110
|
+
}) {
|
|
111
|
+
const settings = useSettings(composerPillSettings);
|
|
112
|
+
const styles = useMemo(
|
|
113
|
+
() => ({
|
|
114
|
+
root: { gap: 12 },
|
|
115
|
+
text: { color: theme.colors.foreground },
|
|
116
|
+
error: { color: theme.colors.statusDanger },
|
|
117
|
+
}),
|
|
118
|
+
[theme],
|
|
119
|
+
);
|
|
120
|
+
const readyValues = settings.status === "ready" ? settings.values : undefined;
|
|
121
|
+
|
|
122
|
+
useEffect(() => {
|
|
123
|
+
if (readyValues) onChange(readyValues);
|
|
124
|
+
}, [onChange, readyValues]);
|
|
125
|
+
|
|
126
|
+
if (settings.status === "loading") return <Text style={styles.text}>Loading preferences…</Text>;
|
|
127
|
+
if (settings.status !== "ready") {
|
|
128
|
+
return (
|
|
129
|
+
<View style={styles.root}>
|
|
130
|
+
<SettingsSection title="Composer pills">
|
|
131
|
+
<Text accessibilityRole="alert" style={styles.error}>
|
|
132
|
+
{settings.error}
|
|
133
|
+
</Text>
|
|
134
|
+
<SettingsCard>
|
|
135
|
+
<SettingsAction
|
|
136
|
+
label="Read composer preferences again"
|
|
137
|
+
actionLabel="Reload"
|
|
138
|
+
onPress={settings.reload}
|
|
139
|
+
/>
|
|
140
|
+
{settings.status === "invalid" ? (
|
|
141
|
+
<SettingsAction
|
|
142
|
+
label="Replace invalid preferences with defaults"
|
|
143
|
+
actionLabel="Reset"
|
|
144
|
+
disabled={settings.saving}
|
|
145
|
+
onPress={async () => {
|
|
146
|
+
if (await settings.reset()) onChange({ ...DEFAULT_COMPOSER_PILL_SETTINGS });
|
|
147
|
+
}}
|
|
148
|
+
/>
|
|
149
|
+
) : null}
|
|
150
|
+
</SettingsCard>
|
|
151
|
+
</SettingsSection>
|
|
152
|
+
</View>
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return <ComposerPillControls settings={settings} onChange={onChange} />;
|
|
157
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as paseoClient from "@getpaseo/plugin/client";
|
|
2
|
+
import { Linking } from "react-native";
|
|
3
|
+
import { selectExternalUrlOpener, validatedHttpUrl } from "../shared/external-url";
|
|
4
|
+
|
|
5
|
+
const paseoOpenExternalUrl =
|
|
6
|
+
"openExternalUrl" in paseoClient && typeof paseoClient.openExternalUrl === "function"
|
|
7
|
+
? paseoClient.openExternalUrl
|
|
8
|
+
: undefined;
|
|
9
|
+
const openExternalUrl = selectExternalUrlOpener(paseoOpenExternalUrl, (url) =>
|
|
10
|
+
Linking.openURL(url),
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
export function openOmpExternalUrl(url: string): Promise<void> {
|
|
14
|
+
return openExternalUrl(validatedHttpUrl(url));
|
|
15
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { type PluginTimelineItemProps, useRpc } from "@getpaseo/plugin/client";
|
|
2
|
+
import { Icon } from "@getpaseo/plugin/client/react-native";
|
|
3
|
+
import { useMemo, useState } from "react";
|
|
4
|
+
import { Pressable, Text, View } from "react-native";
|
|
5
|
+
import {
|
|
6
|
+
type OmpMcpAuthorizationTimeline,
|
|
7
|
+
openOmpMcpAuthorizationInPaseoBrowser,
|
|
8
|
+
} from "../shared/mcp";
|
|
9
|
+
import { openOmpExternalUrl } from "./external-url";
|
|
10
|
+
|
|
11
|
+
function browserAuthorizationError(error: unknown): string {
|
|
12
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
13
|
+
if (/No Paseo desktop browser host/iu.test(detail)) {
|
|
14
|
+
return "No Paseo desktop browser host is connected. Open the authorization on this device.";
|
|
15
|
+
}
|
|
16
|
+
if (/browser tools are disabled/iu.test(detail)) {
|
|
17
|
+
return "Paseo browser tools are disabled. Open the authorization on this device.";
|
|
18
|
+
}
|
|
19
|
+
if (/browser tools are unavailable/iu.test(detail)) {
|
|
20
|
+
return "Paseo tools are not available in this OMP session. Open the authorization on this device.";
|
|
21
|
+
}
|
|
22
|
+
if (/session is no longer available|session is closed/iu.test(detail)) {
|
|
23
|
+
return "The OMP authorization session ended. Start authorization again or open the URL on this device.";
|
|
24
|
+
}
|
|
25
|
+
return "Could not open a Paseo Browser tab. Open the authorization on this device.";
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function OmpMcpAuthorizationCard({
|
|
29
|
+
item,
|
|
30
|
+
theme,
|
|
31
|
+
layout,
|
|
32
|
+
}: PluginTimelineItemProps<OmpMcpAuthorizationTimeline>) {
|
|
33
|
+
const openInPaseoBrowser = useRpc(openOmpMcpAuthorizationInPaseoBrowser);
|
|
34
|
+
const [opening, setOpening] = useState<"paseo" | "device" | null>(null);
|
|
35
|
+
const [message, setMessage] = useState<string | null>(null);
|
|
36
|
+
const [error, setError] = useState<string | null>(null);
|
|
37
|
+
const styles = useMemo(
|
|
38
|
+
() => ({
|
|
39
|
+
card: {
|
|
40
|
+
gap: layout.compact ? 10 : 12,
|
|
41
|
+
padding: layout.compact ? 12 : 14,
|
|
42
|
+
borderWidth: 1,
|
|
43
|
+
borderColor: theme.colors.border,
|
|
44
|
+
borderRadius: 10,
|
|
45
|
+
backgroundColor: theme.colors.surface1,
|
|
46
|
+
},
|
|
47
|
+
header: { flexDirection: "row" as const, alignItems: "center" as const, gap: 8 },
|
|
48
|
+
title: { color: theme.colors.foreground, fontSize: 14, fontWeight: "700" as const },
|
|
49
|
+
text: { color: theme.colors.foregroundMuted, fontSize: 13, lineHeight: 18 },
|
|
50
|
+
url: { color: theme.colors.accent, fontSize: 12, lineHeight: 17 },
|
|
51
|
+
buttonRow: { flexDirection: "row" as const, flexWrap: "wrap" as const, gap: 8 },
|
|
52
|
+
button: {
|
|
53
|
+
flexDirection: "row" as const,
|
|
54
|
+
alignItems: "center" as const,
|
|
55
|
+
alignSelf: "flex-start" as const,
|
|
56
|
+
gap: 7,
|
|
57
|
+
paddingHorizontal: 12,
|
|
58
|
+
paddingVertical: 9,
|
|
59
|
+
borderRadius: 8,
|
|
60
|
+
backgroundColor: theme.colors.accent,
|
|
61
|
+
},
|
|
62
|
+
buttonSecondary: {
|
|
63
|
+
borderWidth: 1,
|
|
64
|
+
borderColor: theme.colors.border,
|
|
65
|
+
backgroundColor: theme.colors.surface2,
|
|
66
|
+
},
|
|
67
|
+
buttonPressed: { opacity: 0.78 },
|
|
68
|
+
buttonDisabled: { opacity: 0.55 },
|
|
69
|
+
buttonText: {
|
|
70
|
+
color: theme.colors.accentForeground,
|
|
71
|
+
fontSize: 13,
|
|
72
|
+
fontWeight: "600" as const,
|
|
73
|
+
},
|
|
74
|
+
buttonTextSecondary: { color: theme.colors.foreground },
|
|
75
|
+
success: { color: theme.colors.statusSuccess, fontSize: 12 },
|
|
76
|
+
error: { color: theme.colors.statusDanger, fontSize: 12 },
|
|
77
|
+
}),
|
|
78
|
+
[layout.compact, theme],
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
async function openPaseoBrowser(): Promise<void> {
|
|
82
|
+
setOpening("paseo");
|
|
83
|
+
setError(null);
|
|
84
|
+
setMessage(null);
|
|
85
|
+
try {
|
|
86
|
+
const authorizationToken = item.data.browserAuthorizationToken;
|
|
87
|
+
if (!authorizationToken) throw new Error("Browser authorization is unavailable");
|
|
88
|
+
await openInPaseoBrowser({ authorizationToken });
|
|
89
|
+
setMessage("Opened in a Paseo Browser tab for this workspace.");
|
|
90
|
+
} catch (cause) {
|
|
91
|
+
setError(browserAuthorizationError(cause));
|
|
92
|
+
} finally {
|
|
93
|
+
setOpening(null);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async function openOnDevice(): Promise<void> {
|
|
98
|
+
setOpening("device");
|
|
99
|
+
setError(null);
|
|
100
|
+
setMessage(null);
|
|
101
|
+
try {
|
|
102
|
+
await openOmpExternalUrl(item.data.url);
|
|
103
|
+
} catch {
|
|
104
|
+
setError("Could not open the authorization URL. Copy the URL below into a browser.");
|
|
105
|
+
} finally {
|
|
106
|
+
setOpening(null);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return (
|
|
111
|
+
<View style={styles.card}>
|
|
112
|
+
<View style={styles.header}>
|
|
113
|
+
<Icon name="KeyRound" size={16} color={theme.colors.accent} />
|
|
114
|
+
<Text style={styles.title}>OMP MCP authorization</Text>
|
|
115
|
+
</View>
|
|
116
|
+
{item.data.instructions ? <Text style={styles.text}>{item.data.instructions}</Text> : null}
|
|
117
|
+
<View style={styles.buttonRow}>
|
|
118
|
+
{item.data.browserAuthorizationToken ? (
|
|
119
|
+
<Pressable
|
|
120
|
+
accessibilityRole="button"
|
|
121
|
+
accessibilityLabel="Open MCP authorization in Paseo Browser"
|
|
122
|
+
disabled={opening !== null}
|
|
123
|
+
onPress={() => void openPaseoBrowser()}
|
|
124
|
+
style={({ pressed }) => [
|
|
125
|
+
styles.button,
|
|
126
|
+
pressed ? styles.buttonPressed : null,
|
|
127
|
+
opening !== null ? styles.buttonDisabled : null,
|
|
128
|
+
]}
|
|
129
|
+
>
|
|
130
|
+
<Icon name="PanelsTopLeft" size={15} color={theme.colors.accentForeground} />
|
|
131
|
+
<Text style={styles.buttonText}>
|
|
132
|
+
{opening === "paseo" ? "Opening…" : "Open in Paseo Browser"}
|
|
133
|
+
</Text>
|
|
134
|
+
</Pressable>
|
|
135
|
+
) : null}
|
|
136
|
+
<Pressable
|
|
137
|
+
accessibilityRole="link"
|
|
138
|
+
accessibilityLabel="Open MCP authorization on this device"
|
|
139
|
+
disabled={opening !== null}
|
|
140
|
+
onPress={() => void openOnDevice()}
|
|
141
|
+
style={({ pressed }) => [
|
|
142
|
+
styles.button,
|
|
143
|
+
styles.buttonSecondary,
|
|
144
|
+
pressed ? styles.buttonPressed : null,
|
|
145
|
+
opening !== null ? styles.buttonDisabled : null,
|
|
146
|
+
]}
|
|
147
|
+
>
|
|
148
|
+
<Icon name="ExternalLink" size={15} color={theme.colors.foreground} />
|
|
149
|
+
<Text style={[styles.buttonText, styles.buttonTextSecondary]}>
|
|
150
|
+
{opening === "device" ? "Opening…" : "Open on this device"}
|
|
151
|
+
</Text>
|
|
152
|
+
</Pressable>
|
|
153
|
+
</View>
|
|
154
|
+
<Text selectable style={styles.url}>
|
|
155
|
+
{item.data.url}
|
|
156
|
+
</Text>
|
|
157
|
+
{item.data.loopbackCallback ? (
|
|
158
|
+
<Text style={styles.text}>
|
|
159
|
+
Paseo Browser keeps authorization in this workspace when a desktop browser host is
|
|
160
|
+
connected. For a localhost callback, that browser host must run on the daemon machine.
|
|
161
|
+
Otherwise, copy the final URL or authorization code and paste it into the OMP prompt in
|
|
162
|
+
this chat.
|
|
163
|
+
</Text>
|
|
164
|
+
) : null}
|
|
165
|
+
{message ? <Text style={styles.success}>{message}</Text> : null}
|
|
166
|
+
{error ? <Text style={styles.error}>{error}</Text> : null}
|
|
167
|
+
</View>
|
|
168
|
+
);
|
|
169
|
+
}
|