@omercnet/paseo-omp 0.4.0 → 1.0.0-next.160.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.
Files changed (40) hide show
  1. package/README.md +8 -8
  2. package/client/external-url.ts +2 -11
  3. package/client/omp-config-styles.ts +284 -0
  4. package/client/omp-config-surface.tsx +16 -286
  5. package/client/omp-routing-editor.tsx +1 -3
  6. package/client/provider-launch-settings.tsx +118 -0
  7. package/index.client.tsx +21 -2
  8. package/index.server.ts +10 -0
  9. package/package.json +14 -9
  10. package/paseo-plugin.json +2 -1
  11. package/scripts/prepare-dependencies.mjs +44 -11
  12. package/server/omp-models.ts +2 -6
  13. package/server/package-version.ts +1 -1
  14. package/server/protocol-violation-diagnostics.ts +1 -1
  15. package/server/provider/catalog.ts +2 -1
  16. package/server/provider/config-normalization.ts +19 -3
  17. package/server/provider/connection.ts +30 -0
  18. package/server/provider/host-tools.ts +2 -2
  19. package/server/provider/mcp-transport.ts +9 -2
  20. package/server/provider/omp-rpc-environment.ts +368 -0
  21. package/server/provider/omp-rpc-process.ts +119 -0
  22. package/server/provider/omp-rpc-protocol.ts +1949 -0
  23. package/server/provider/omp-rpc-transport.ts +1373 -0
  24. package/server/provider/omp-rpc-values.ts +31 -0
  25. package/server/provider/omp-rpc.ts +267 -3311
  26. package/server/provider/profile-providers.ts +2 -1
  27. package/server/provider/prompt-payload.ts +253 -0
  28. package/server/provider/registration.ts +10 -2
  29. package/server/provider/session-compaction.ts +187 -0
  30. package/server/provider/session-descriptors.ts +52 -18
  31. package/server/provider/session-events.ts +42 -0
  32. package/server/provider/session-permissions.ts +987 -0
  33. package/server/provider/session-terminal.ts +307 -0
  34. package/server/provider/session-usage.ts +234 -0
  35. package/server/provider/session.ts +145 -1853
  36. package/server/provider/settings.ts +8 -5
  37. package/server/provider/subsessions.ts +30 -9
  38. package/server/provider/timeline-projector.ts +140 -29
  39. package/shared/external-url.ts +0 -9
  40. package/shared/provider-launch-settings.ts +18 -0
@@ -10,7 +10,6 @@ import { ExternalLink } from "@getpaseo/plugin/client/ui";
10
10
  import { useIsMutating, useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
11
11
  import type { ReactNode } from "react";
12
12
  import { useCallback, useMemo, useState } from "react";
13
- import type { TextStyle, ViewStyle } from "react-native";
14
13
  import { Pressable, ScrollView, Switch, Text, View } from "react-native";
15
14
  import type { ComposerPillSettings } from "../shared/composer-pill-settings";
16
15
  import { listOmpConfig, type OmpConfig } from "../shared/omp-config";
@@ -31,6 +30,7 @@ import { getOmpProviderHealth, type OmpProviderHealth } from "../shared/provider
31
30
  import { getOmpSupportReport, OMP_SUPPORT_ISSUE_URL } from "../shared/support-diagnostics";
32
31
  import { ComposerPillSettingsSection } from "./composer-pill-settings";
33
32
  import { openOmpExternalUrl } from "./external-url";
33
+ import { type OmpConfigStyles, useConfigStyles } from "./omp-config-styles";
34
34
  import { type OmpConfigSurfaceView as SurfaceView, surfaceViewsForScope } from "./omp-config-views";
35
35
  import {
36
36
  documentationForSettingCategory,
@@ -63,6 +63,7 @@ import {
63
63
  summarizeProviderStatus,
64
64
  summarizeRpcUiSupport,
65
65
  } from "./provider-diagnostics-state";
66
+ import { ProviderLaunchSettingsSection } from "./provider-launch-settings";
66
67
  import {
67
68
  refreshSupportReport,
68
69
  type SupportReportCopyState,
@@ -74,284 +75,6 @@ const CONFIG_POLL_MS = 30_000;
74
75
  const HEALTH_QUERY_KEY = ["paseo-omp", "provider-health"] as const;
75
76
  const PROVIDERS_QUERY_KEY = ["paseo-omp", "provider-snapshot"] as const;
76
77
 
77
- export interface OmpConfigStyles {
78
- root: ViewStyle;
79
- pageTitle: TextStyle;
80
- topTabs: ViewStyle;
81
- topTab: ViewStyle;
82
- topTabActive: ViewStyle;
83
- topTabLabel: TextStyle;
84
- topTabLabelActive: TextStyle;
85
- workspace: ViewStyle;
86
- categoryRail: ViewStyle;
87
- categoryList: ViewStyle;
88
- categoryButton: ViewStyle;
89
- categoryButtonActive: ViewStyle;
90
- categoryLabel: TextStyle;
91
- categoryLabelActive: TextStyle;
92
- categoryContent: ViewStyle;
93
- search: TextStyle;
94
- sectionHeader: ViewStyle;
95
- sectionHeaderRow: ViewStyle;
96
- sectionTitle: TextStyle;
97
- source: TextStyle;
98
- muted: TextStyle;
99
- error: TextStyle;
100
- refresh: ViewStyle;
101
- docsActions: ViewStyle;
102
- docLink: ViewStyle;
103
- docLinkPressed: ViewStyle;
104
- docLinkText: TextStyle;
105
- refreshLabel: TextStyle;
106
- helpActions: ViewStyle;
107
- helpReport: ViewStyle;
108
- helpReportText: TextStyle;
109
- helpLinkText: TextStyle;
110
- card: ViewStyle;
111
- cardHeader: ViewStyle;
112
- cardTitle: TextStyle;
113
- row: ViewStyle;
114
- rowLabel: TextStyle;
115
- rowValue: TextStyle;
116
- setting: ViewStyle;
117
- settingHeader: ViewStyle;
118
- settingPath: TextStyle;
119
- settingDescription: TextStyle;
120
- settingValue: TextStyle;
121
- collectionSummary: TextStyle;
122
- chipList: ViewStyle;
123
- chip: ViewStyle;
124
- chipText: TextStyle;
125
- recordList: ViewStyle;
126
- recordRow: ViewStyle;
127
- recordKey: TextStyle;
128
- recordValue: TextStyle;
129
- editorActions: ViewStyle;
130
- editorAction: ViewStyle;
131
- editorActionPrimary: ViewStyle;
132
- editorActionText: TextStyle;
133
- editorActionTextPrimary: TextStyle;
134
- scalarInput: TextStyle;
135
- resetAction: TextStyle;
136
- }
137
-
138
- function useConfigStyles(theme: PluginSurfaceProps["theme"], compact: boolean): OmpConfigStyles {
139
- return useMemo(
140
- () => ({
141
- root: {
142
- flex: 1,
143
- gap: compact ? 10 : 14,
144
- padding: compact ? 16 : 24,
145
- backgroundColor: theme.colors.surface0,
146
- },
147
- pageTitle: {
148
- color: theme.colors.foreground,
149
- fontSize: compact ? 22 : 26,
150
- fontWeight: "700",
151
- },
152
- topTabs: {
153
- flexWrap: "wrap",
154
- flexDirection: "row",
155
- alignSelf: "flex-start",
156
- gap: 4,
157
- padding: 4,
158
- borderWidth: 1,
159
- borderColor: theme.colors.border,
160
- borderRadius: 10,
161
- backgroundColor: theme.colors.surface1,
162
- },
163
- topTab: {
164
- paddingHorizontal: compact ? 10 : 14,
165
- paddingVertical: 8,
166
- borderRadius: 7,
167
- },
168
- topTabActive: { backgroundColor: theme.colors.accent },
169
- topTabLabel: { color: theme.colors.foregroundMuted, fontSize: 13, fontWeight: "600" },
170
- topTabLabelActive: { color: theme.colors.accentForeground },
171
- workspace: {
172
- flexDirection: compact ? "column" : "row",
173
- alignItems: compact ? "stretch" : "flex-start",
174
- gap: compact ? 10 : 18,
175
- },
176
- categoryRail: {
177
- width: compact ? "100%" : 220,
178
- gap: 10,
179
- padding: 10,
180
- borderWidth: 1,
181
- borderColor: theme.colors.border,
182
- borderRadius: 10,
183
- backgroundColor: theme.colors.surface1,
184
- },
185
- categoryList: { gap: 4 },
186
- categoryButton: { paddingHorizontal: 10, paddingVertical: 9, borderRadius: 7 },
187
- categoryButtonActive: { backgroundColor: theme.colors.surface2 },
188
- categoryLabel: { color: theme.colors.foregroundMuted, fontSize: 13, fontWeight: "500" },
189
- categoryLabelActive: { color: theme.colors.foreground, fontWeight: "700" },
190
- categoryContent: { flex: compact ? undefined : 1, minWidth: 0, gap: 10 },
191
- search: {
192
- color: theme.colors.foreground,
193
- borderWidth: 1,
194
- borderColor: theme.colors.border,
195
- borderRadius: 8,
196
- backgroundColor: theme.colors.surface0,
197
- paddingHorizontal: 10,
198
- paddingVertical: 8,
199
- fontSize: 13,
200
- },
201
- sectionHeader: { gap: 4, marginTop: compact ? 2 : 4 },
202
- sectionHeaderRow: { flexDirection: "row", alignItems: "center", flexWrap: "wrap", gap: 10 },
203
- sectionTitle: {
204
- color: theme.colors.foreground,
205
- fontSize: compact ? 16 : 18,
206
- fontWeight: "600",
207
- },
208
- source: { color: theme.colors.foregroundMuted, fontSize: 12 },
209
- muted: { color: theme.colors.foregroundMuted, fontSize: 13 },
210
- error: { color: theme.colors.statusDanger, fontSize: 13 },
211
- docsActions: { flexDirection: "row", alignItems: "center", flexWrap: "wrap", gap: 6 },
212
- docLink: {
213
- paddingHorizontal: 8,
214
- paddingVertical: 5,
215
- borderWidth: 1,
216
- borderColor: theme.colors.border,
217
- borderRadius: 7,
218
- backgroundColor: theme.colors.surface1,
219
- },
220
- docLinkPressed: { opacity: 0.72 },
221
- docLinkText: { color: theme.colors.accent, fontSize: 12, fontWeight: "600" },
222
- refresh: {
223
- flexDirection: "row",
224
- alignItems: "center",
225
- gap: 6,
226
- paddingHorizontal: 10,
227
- paddingVertical: 6,
228
- borderWidth: 1,
229
- borderColor: theme.colors.border,
230
- borderRadius: 8,
231
- backgroundColor: theme.colors.surface1,
232
- },
233
- refreshLabel: { color: theme.colors.foreground, fontSize: 13 },
234
- helpActions: {
235
- flexDirection: "row",
236
- alignItems: "center",
237
- flexWrap: "wrap",
238
- gap: 8,
239
- },
240
- helpReport: {
241
- maxWidth: "100%",
242
- padding: compact ? 10 : 12,
243
- borderWidth: 1,
244
- borderColor: theme.colors.border,
245
- borderRadius: 10,
246
- backgroundColor: theme.colors.surface1,
247
- },
248
- helpReportText: {
249
- color: theme.colors.foreground,
250
- fontSize: compact ? 11 : 12,
251
- lineHeight: compact ? 16 : 18,
252
- },
253
- helpLinkText: { color: theme.colors.accent, fontSize: 13, fontWeight: "600" },
254
- cardHeader: {
255
- flexDirection: "row",
256
- alignItems: "center",
257
- justifyContent: "space-between",
258
- flexWrap: "wrap",
259
- gap: 8,
260
- },
261
- card: {
262
- gap: 8,
263
- padding: compact ? 10 : 12,
264
- borderWidth: 1,
265
- borderColor: theme.colors.border,
266
- borderRadius: 10,
267
- backgroundColor: theme.colors.surface1,
268
- },
269
- cardTitle: { color: theme.colors.foreground, fontSize: 14, fontWeight: "600" },
270
- row: { flexDirection: "row", gap: 8, flexWrap: "wrap" },
271
- rowLabel: { color: theme.colors.foregroundMuted, fontSize: 13 },
272
- rowValue: { color: theme.colors.foreground, fontSize: 13, flexShrink: 1 },
273
- setting: {
274
- gap: 5,
275
- paddingVertical: 10,
276
- borderTopWidth: 1,
277
- borderTopColor: theme.colors.border,
278
- },
279
- settingHeader: {
280
- flexDirection: "row",
281
- alignItems: "baseline",
282
- justifyContent: "space-between",
283
- gap: 12,
284
- },
285
- settingPath: { color: theme.colors.foregroundMuted, fontSize: 11, flexShrink: 1 },
286
- settingDescription: { color: theme.colors.foregroundMuted, fontSize: 12, lineHeight: 17 },
287
- settingValue: { color: theme.colors.foreground, fontSize: 13, fontWeight: "600" },
288
- collectionSummary: { color: theme.colors.foregroundMuted, fontSize: 12 },
289
- chipList: { flexDirection: "row", flexWrap: "wrap", gap: 6 },
290
- chip: {
291
- paddingHorizontal: 8,
292
- paddingVertical: 5,
293
- borderWidth: 1,
294
- borderColor: theme.colors.border,
295
- borderRadius: 999,
296
- backgroundColor: theme.colors.surface2,
297
- },
298
- chipText: { color: theme.colors.foreground, fontSize: 12 },
299
- recordList: { gap: 6 },
300
- recordRow: {
301
- flexDirection: compact ? "column" : "row",
302
- alignItems: compact ? "flex-start" : "baseline",
303
- gap: compact ? 2 : 12,
304
- paddingVertical: 5,
305
- },
306
- recordKey: {
307
- width: compact ? undefined : 150,
308
- color: theme.colors.foregroundMuted,
309
- fontSize: 12,
310
- fontWeight: "600",
311
- },
312
- recordValue: { flex: 1, color: theme.colors.foreground, fontSize: 12 },
313
- editorActions: {
314
- flexDirection: "row",
315
- alignItems: "center",
316
- justifyContent: "flex-end",
317
- gap: 8,
318
- padding: 10,
319
- borderWidth: 1,
320
- borderColor: theme.colors.border,
321
- borderRadius: 10,
322
- backgroundColor: theme.colors.surface1,
323
- },
324
- editorAction: {
325
- paddingHorizontal: 12,
326
- paddingVertical: 8,
327
- borderWidth: 1,
328
- borderColor: theme.colors.border,
329
- borderRadius: 8,
330
- },
331
- editorActionPrimary: {
332
- backgroundColor: theme.colors.accent,
333
- borderColor: theme.colors.accent,
334
- },
335
- editorActionText: { color: theme.colors.foreground, fontSize: 13, fontWeight: "600" },
336
- editorActionTextPrimary: { color: theme.colors.accentForeground },
337
- scalarInput: {
338
- minWidth: 180,
339
- maxWidth: 420,
340
- color: theme.colors.foreground,
341
- borderWidth: 1,
342
- borderColor: theme.colors.border,
343
- borderRadius: 7,
344
- backgroundColor: theme.colors.surface0,
345
- paddingHorizontal: 9,
346
- paddingVertical: 6,
347
- fontSize: 13,
348
- },
349
- resetAction: { color: theme.colors.accent, fontSize: 12, fontWeight: "600" },
350
- }),
351
- [compact, theme],
352
- );
353
- }
354
-
355
78
  function KeyValueRow({
356
79
  styles,
357
80
  label,
@@ -419,8 +142,10 @@ function ProviderSetupSection({ styles }: { styles: OmpConfigStyles }) {
419
142
  return (
420
143
  <SectionCard styles={styles} title="OMP Plugin">
421
144
  <Text style={styles.muted}>
422
- Launch settings currently come from the active Paseo provider profile.
145
+ Host-wide inherited environment names apply to every OMP provider. Profile launch overrides
146
+ remain available for narrower exceptions.
423
147
  </Text>
148
+ <KeyValueRow styles={styles} label="Host policy" value="Inherited daemon environment names" />
424
149
  <KeyValueRow
425
150
  styles={styles}
426
151
  label="Per agent"
@@ -429,7 +154,7 @@ function ProviderSetupSection({ styles }: { styles: OmpConfigStyles }) {
429
154
  <KeyValueRow
430
155
  styles={styles}
431
156
  label="Provider profile"
432
- value="Command, environment, session directory, RPC timeout, role models, and denied tools"
157
+ value="Command, additional environment, session directory, RPC timeout, role models, and denied tools"
433
158
  />
434
159
  </SectionCard>
435
160
  );
@@ -440,15 +165,15 @@ function PluginConfigurationSection({ styles }: { styles: OmpConfigStyles }) {
440
165
  <>
441
166
  <SectionCard styles={styles} title="OMP Plugin launch options">
442
167
  <Text style={styles.muted}>
443
- Paseo does not expose the effective providerOptions for active launches through the plugin
444
- API. Configure these values in the provider profile; this tab documents the supported
445
- contract without claiming defaults are active.
168
+ Configure inherited daemon environment names below. Paseo does not expose effective
169
+ profile options for active launches, so this tab documents profile overrides without
170
+ claiming they are active.
446
171
  </Text>
447
172
  <KeyValueRow styles={styles} label="Command" value="Executable and argument prefix" />
448
173
  <KeyValueRow
449
174
  styles={styles}
450
175
  label="Inherited environment"
451
- value="Daemon variable names copied at OMP spawn time"
176
+ value="Additional profile names copied at OMP spawn time"
452
177
  />
453
178
  <KeyValueRow
454
179
  styles={styles}
@@ -1403,7 +1128,12 @@ function OmpConfigContent({
1403
1128
  </>
1404
1129
  ) : null}
1405
1130
 
1406
- {view === "plugin" ? <PluginConfigurationSection styles={styles} /> : null}
1131
+ {view === "plugin" ? (
1132
+ <>
1133
+ <PluginConfigurationSection styles={styles} />
1134
+ {!cwd ? <ProviderLaunchSettingsSection theme={theme} /> : null}
1135
+ </>
1136
+ ) : null}
1407
1137
 
1408
1138
  {view === "plugins" ? (
1409
1139
  <OmpPluginManagerSection theme={theme} compact={layout.compact} cwd={cwd} store={store} />
@@ -8,7 +8,7 @@ import {
8
8
  type OmpSetting,
9
9
  parseOmpStructuredSettingValue,
10
10
  } from "../shared/omp-settings";
11
- import type { OmpConfigStyles } from "./omp-config-surface";
11
+ import type { OmpConfigStyles } from "./omp-config-styles";
12
12
  import { OmpModelPicker } from "./omp-model-picker";
13
13
  import {
14
14
  aliasChoices,
@@ -99,7 +99,6 @@ function OrderedRoleEditor({
99
99
  return (
100
100
  <View style={styles.recordList}>
101
101
  {roles.map((role, index) => (
102
- // biome-ignore lint/suspicious/noArrayIndexKey: ordered rows are edited by position and must keep input identity while their value changes.
103
102
  <View key={index} style={styles.recordRow}>
104
103
  <Text style={styles.recordKey}>{index + 1}</Text>
105
104
  <TextInput
@@ -172,7 +171,6 @@ function RecordRoutingEditor({
172
171
  ? rawValue
173
172
  : "";
174
173
  return (
175
- // biome-ignore lint/suspicious/noArrayIndexKey: record keys are editable, so row position preserves input identity.
176
174
  <View key={index} style={styles.recordRow}>
177
175
  <TextInput
178
176
  accessibilityLabel={`${formatOmpSettingLabel(setting.path)} ${keyLabel} ${index + 1}`}
@@ -0,0 +1,118 @@
1
+ import { type PluginSurfaceProps, type SettingsState, useSettings } from "@getpaseo/plugin/client";
2
+ import {
3
+ SettingsAction,
4
+ SettingsCard,
5
+ SettingsInput,
6
+ SettingsSection,
7
+ } from "@getpaseo/plugin/client/ui";
8
+ import { useCallback, useEffect, useMemo, useState } from "react";
9
+ import { Text, View } from "react-native";
10
+ import {
11
+ providerLaunchSettings,
12
+ providerLaunchSettingsSchema,
13
+ } from "../shared/provider-launch-settings";
14
+
15
+ type ReadySettings = Extract<
16
+ SettingsState<typeof providerLaunchSettings.schema>,
17
+ { status: "ready" }
18
+ >;
19
+
20
+ function ProviderLaunchSettingsControls({ settings }: { settings: ReadySettings }) {
21
+ const savedNames = settings.values.inheritEnv.join(", ");
22
+ const [rawNames, setRawNames] = useState(() => savedNames);
23
+ useEffect(() => {
24
+ setRawNames(savedNames);
25
+ }, [savedNames]);
26
+ const inheritEnv = [
27
+ ...new Set(
28
+ rawNames
29
+ .split(",")
30
+ .map((name) => name.trim())
31
+ .filter(Boolean),
32
+ ),
33
+ ];
34
+ const next = providerLaunchSettingsSchema.safeParse({ inheritEnv });
35
+ const error = next.success
36
+ ? null
37
+ : (next.error.issues[0]?.message ?? "Enter valid variable names.");
38
+ const save = useCallback(async () => {
39
+ if (!next.success) return;
40
+ await settings.save(next.data, settings.revision);
41
+ }, [next, settings]);
42
+
43
+ return (
44
+ <View style={{ gap: 12 }}>
45
+ <SettingsSection
46
+ title="Inherited environment"
47
+ info="Applies to every OMP Plugin agent on this host. Names are stored, but values are read only from the daemon environment when OMP starts."
48
+ >
49
+ <SettingsCard>
50
+ <SettingsInput
51
+ key={savedNames}
52
+ label="Daemon variable names"
53
+ hint="Comma-separated names. Each selected value is available to OMP and its child processes."
54
+ initialValue={savedNames}
55
+ onChangeText={setRawNames}
56
+ placeholder="ACME_OMP_API_KEY, ACME_OMP_URL"
57
+ error={error ?? undefined}
58
+ disabled={settings.saving}
59
+ />
60
+ <SettingsAction
61
+ label="Save inherited environment"
62
+ hint="Profile-specific names remain additive for narrow exceptions."
63
+ actionLabel="Save"
64
+ disabled={settings.saving || rawNames === savedNames || !next.success}
65
+ onPress={() => void save()}
66
+ />
67
+ <SettingsAction
68
+ label="Clear inherited environment"
69
+ actionLabel="Clear"
70
+ disabled={settings.saving || settings.values.inheritEnv.length === 0}
71
+ onPress={async () => {
72
+ if (await settings.save({ inheritEnv: [] }, settings.revision)) setRawNames("");
73
+ }}
74
+ />
75
+ {settings.saveError ? (
76
+ <SettingsAction
77
+ label="Reload host launch settings"
78
+ error={settings.saveError}
79
+ actionLabel="Reload"
80
+ disabled={settings.saving}
81
+ onPress={settings.reload}
82
+ />
83
+ ) : null}
84
+ </SettingsCard>
85
+ </SettingsSection>
86
+ </View>
87
+ );
88
+ }
89
+
90
+ export function ProviderLaunchSettingsSection({ theme }: { theme: PluginSurfaceProps["theme"] }) {
91
+ const settings = useSettings(providerLaunchSettings);
92
+ const styles = useMemo(
93
+ () => ({
94
+ root: { gap: 12 },
95
+ text: { color: theme.colors.foreground },
96
+ error: { color: theme.colors.statusDanger },
97
+ }),
98
+ [theme],
99
+ );
100
+
101
+ if (settings.status === "loading")
102
+ return <Text style={styles.text}>Loading host launch settings…</Text>;
103
+ if (settings.status !== "ready") {
104
+ return (
105
+ <View style={styles.root}>
106
+ <Text accessibilityRole="alert" style={styles.error}>
107
+ {settings.error}
108
+ </Text>
109
+ <SettingsAction
110
+ label="Read host launch settings again"
111
+ actionLabel="Reload"
112
+ onPress={settings.reload}
113
+ />
114
+ </View>
115
+ );
116
+ }
117
+ return <ProviderLaunchSettingsControls settings={settings} />;
118
+ }
package/index.client.tsx CHANGED
@@ -452,7 +452,25 @@ export default function contribute(client: PluginClientContext) {
452
452
  }, RECONCILE_DEBOUNCE_MS);
453
453
  }
454
454
 
455
- const unsubscribeAgents = client.paseo.agents.subscribe(scheduleReconcile);
455
+ let unsubscribeAgentDirectory = () => {};
456
+ let releaseAgentDirectory: (() => Promise<void>) | undefined;
457
+ void client.paseo.agents
458
+ .list({ subscribe: {} })
459
+ .then(({ subscription }) => {
460
+ if (!subscription) return;
461
+ if (disposed) {
462
+ void subscription.release().catch(() => {});
463
+ return;
464
+ }
465
+ unsubscribeAgentDirectory = subscription.subscribe({
466
+ snapshot: scheduleReconcile,
467
+ update: scheduleReconcile,
468
+ error: () => {},
469
+ });
470
+ releaseAgentDirectory = () => subscription.release();
471
+ void subscription.ready.catch(() => {});
472
+ })
473
+ .catch(() => {});
456
474
  const hubPoll = setInterval(() => {
457
475
  void refreshHubStatus();
458
476
  }, STATUS_POLL_MS);
@@ -467,7 +485,8 @@ export default function contribute(client: PluginClientContext) {
467
485
  return () => {
468
486
  disposed = true;
469
487
  settingsGeneration += 1;
470
- unsubscribeAgents();
488
+ unsubscribeAgentDirectory();
489
+ if (releaseAgentDirectory) void releaseAgentDirectory().catch(() => {});
471
490
  clearTimeout(reconcileTimer);
472
491
  clearInterval(hubPoll);
473
492
  clearInterval(quotaPoll);
package/index.server.ts CHANGED
@@ -24,6 +24,7 @@ import {
24
24
  discoverOmpProfilesSync,
25
25
  } from "./server/provider/profile-providers";
26
26
  import { createOmpProvider } from "./server/provider/registration";
27
+ import { OmpPublicError } from "./server/provider/security";
27
28
  import { resolveGetOmpProviderHealth } from "./server/provider-diagnostics";
28
29
  import { resolveListOmpQuotas } from "./server/quota";
29
30
  import { resolveListOmpSessions } from "./server/sessions";
@@ -43,6 +44,7 @@ import {
43
44
  import { listOmpSettings, updateOmpSettings } from "./shared/omp-settings";
44
45
  import { listOmpStores, type OmpStore } from "./shared/omp-store";
45
46
  import { getOmpProviderHealth } from "./shared/provider-diagnostics";
47
+ import { providerLaunchSettings } from "./shared/provider-launch-settings";
46
48
  import { listOmpQuotas } from "./shared/quota";
47
49
  import { listOmpSessions } from "./shared/sessions";
48
50
  import { getOmpSupportReport } from "./shared/support-diagnostics";
@@ -53,6 +55,12 @@ function scoped<T extends { store?: OmpStore }, R>(handler: (input: T) => R) {
53
55
 
54
56
  export default function contribute(server: PluginServerContext) {
55
57
  server.registerSettings(composerPillSettings);
58
+ const launchSettings = server.registerSettings(providerLaunchSettings);
59
+ const resolveHostInheritEnv = async (): Promise<readonly string[]> => {
60
+ const current = await launchSettings.read();
61
+ if (current.status === "ready") return current.values.inheritEnv;
62
+ throw new OmpPublicError("OMP host launch settings are unavailable");
63
+ };
56
64
  const browserAuthorizationRegistry = new OmpBrowserAuthorizationRegistry();
57
65
  const protocolViolations = new OmpProtocolViolationCollector();
58
66
  const operationalFailures = new OmpOperationalFailureCollector();
@@ -64,6 +72,7 @@ export default function contribute(server: PluginServerContext) {
64
72
  browserAuthorizationRegistry,
65
73
  reportProtocolViolation: protocolViolations.report,
66
74
  reportOperationalFailure: operationalFailures.report,
75
+ resolveHostInheritEnv,
67
76
  }),
68
77
  );
69
78
  }
@@ -97,6 +106,7 @@ export default function contribute(server: PluginServerContext) {
97
106
  browserAuthorizationRegistry,
98
107
  reportProtocolViolation: protocolViolations.report,
99
108
  reportOperationalFailure: operationalFailures.report,
109
+ resolveHostInheritEnv,
100
110
  }),
101
111
  );
102
112
  return () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@omercnet/paseo-omp",
3
- "version": "0.4.0",
3
+ "version": "1.0.0-next.160.1",
4
4
  "type": "module",
5
5
  "description": "Paseo integration for OMP, including its direct provider and workspace tooling.",
6
6
  "license": "MIT",
@@ -16,7 +16,7 @@
16
16
  "publishConfig": {
17
17
  "access": "public"
18
18
  },
19
- "packageManager": "npm@10.9.4",
19
+ "packageManager": "bun@1.4.2",
20
20
  "engines": {
21
21
  "node": ">=22.18.0"
22
22
  },
@@ -48,28 +48,33 @@
48
48
  "test:integration:wsl": "node --import tsx scripts/test-wsl-host-tools.ts",
49
49
  "test:integration:canary": "node --import tsx scripts/test-canary.ts",
50
50
  "test:integration:install": "node --import tsx scripts/test-package-install.ts",
51
- "typecheck": "tsc --noEmit"
51
+ "typecheck": "tsc --noEmit -p tsconfig.client.json && tsc --noEmit -p tsconfig.server.json && tsc --noEmit -p tsconfig.tests.json"
52
52
  },
53
53
  "dependencies": {
54
- "@getpaseo/protocol": "0.9.0-beta.1",
55
- "@modelcontextprotocol/sdk": "1.29.0",
54
+ "@getpaseo/protocol": "0.9.2",
55
+ "@modelcontextprotocol/sdk": "1.30.0",
56
56
  "yaml": "^2.9.0"
57
57
  },
58
58
  "devDependencies": {
59
59
  "@biomejs/biome": "^2.5.10",
60
- "@getpaseo/cli": "0.9.0-beta.1",
61
- "@getpaseo/client": "0.9.0-beta.1",
62
- "@getpaseo/plugin": "0.9.0-beta.1",
60
+ "@getpaseo/cli": "0.9.2",
61
+ "@getpaseo/client": "0.9.2",
62
+ "@getpaseo/plugin": "0.9.2",
63
+ "@getpaseo/server": "0.9.2",
64
+ "@oh-my-pi/pi-agent-core": "18.2.0",
65
+ "@oh-my-pi/pi-coding-agent": "18.2.0",
63
66
  "@tanstack/react-query": "^5.102.3",
64
67
  "@types/node": "^24.10.1",
65
68
  "@types/react": "^19.2.18",
66
69
  "@vitest/coverage-v8": "^5.0.0",
70
+ "esbuild": "0.28.2",
71
+ "pino": "10.3.1",
67
72
  "react": "19.1.0",
68
73
  "react-native": "0.81.5",
69
74
  "tsx": "^4.20.6",
70
75
  "typescript": "^7.0.2",
71
76
  "vitest": "^5.0.0",
72
- "zod": "^4.4.3"
77
+ "zod": "4.4.3"
73
78
  },
74
79
  "overrides": {
75
80
  "qs": "6.16.0"
package/paseo-plugin.json CHANGED
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "id": "paseo-omp",
3
- "requirements": { "paseo": ">=0.9.0-beta.1 <0.10.0" },
3
+ "description": "Paseo integration for OMP, including its direct provider and workspace tooling.",
4
+ "requirements": { "paseo": "^0.9.2" },
4
5
  "build": [["node", "scripts/prepare-dependencies.mjs"]]
5
6
  }