@omercnet/paseo-omp 0.2.1 → 0.3.0-next.92.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 +6 -2
- 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 +213 -9
- package/server/provider/host-tools.ts +71 -0
- package/server/provider/omp-rpc.ts +82 -15
- package/server/provider/profile-providers.ts +249 -0
- package/server/provider/registration.ts +11 -0
- package/server/provider/session-descriptors.ts +306 -1
- package/server/provider/session.ts +704 -249
- package/server/provider/subsessions.ts +4 -1
- package/server/provider/timeline-projector.ts +70 -33
- 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
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type PluginSurfaceProps, useRpc } from "@getpaseo/plugin/client";
|
|
2
2
|
import { TextInput } from "@getpaseo/plugin/client/react-native";
|
|
3
3
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
4
|
-
import { useMemo, useRef, useState } from "react";
|
|
4
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
5
5
|
import type { TextStyle, ViewStyle } from "react-native";
|
|
6
6
|
import { Pressable, Switch, Text, View } from "react-native";
|
|
7
7
|
import {
|
|
@@ -18,18 +18,28 @@ import {
|
|
|
18
18
|
type OmpPluginMutation,
|
|
19
19
|
} from "../shared/omp-plugins";
|
|
20
20
|
|
|
21
|
+
import type { OmpStore } from "../shared/omp-store";
|
|
22
|
+
import { ompStoreKey } from "./omp-store-state";
|
|
23
|
+
|
|
21
24
|
const PLUGINS_QUERY_KEY = ["paseo-omp", "plugins"] as const;
|
|
22
25
|
|
|
26
|
+
type ConfirmationOrigin =
|
|
27
|
+
| { surface: "install" }
|
|
28
|
+
| { surface: "plugin"; key: string }
|
|
29
|
+
| { surface: "config"; key: string };
|
|
30
|
+
|
|
23
31
|
type PendingConfirmation =
|
|
24
32
|
| {
|
|
25
33
|
kind: "plugin";
|
|
26
34
|
input: OmpPluginMutation;
|
|
35
|
+
origin: ConfirmationOrigin;
|
|
27
36
|
title: string;
|
|
28
37
|
warning: string;
|
|
29
38
|
}
|
|
30
39
|
| {
|
|
31
40
|
kind: "config";
|
|
32
41
|
input: OmpPluginConfigMutation;
|
|
42
|
+
origin: ConfirmationOrigin;
|
|
33
43
|
title: string;
|
|
34
44
|
warning: string;
|
|
35
45
|
};
|
|
@@ -229,13 +239,55 @@ function MetadataRow({
|
|
|
229
239
|
);
|
|
230
240
|
}
|
|
231
241
|
|
|
232
|
-
function
|
|
242
|
+
function ConfirmationPanel({
|
|
243
|
+
confirmation,
|
|
244
|
+
busy,
|
|
245
|
+
styles,
|
|
246
|
+
onCancel,
|
|
247
|
+
onConfirm,
|
|
248
|
+
}: {
|
|
249
|
+
confirmation: PendingConfirmation;
|
|
250
|
+
busy: boolean;
|
|
251
|
+
styles: PluginManagerStyles;
|
|
252
|
+
onCancel(): void;
|
|
253
|
+
onConfirm(): void;
|
|
254
|
+
}) {
|
|
255
|
+
const action = confirmation.input.action;
|
|
256
|
+
const confirmLabel = action === "set" ? "Confirm change" : `Confirm ${action}`;
|
|
257
|
+
return (
|
|
258
|
+
<View accessibilityRole="alert" style={styles.confirmation}>
|
|
259
|
+
<Text style={styles.cardTitle}>{confirmation.title}</Text>
|
|
260
|
+
<Text style={styles.warning}>{confirmation.warning}</Text>
|
|
261
|
+
<View style={styles.actions}>
|
|
262
|
+
<ActionButton label="Cancel" disabled={busy} styles={styles} onPress={onCancel} />
|
|
263
|
+
<ActionButton
|
|
264
|
+
label={busy ? "Applying…" : confirmLabel}
|
|
265
|
+
disabled={busy}
|
|
266
|
+
primary
|
|
267
|
+
danger={action === "uninstall" || action === "delete"}
|
|
268
|
+
styles={styles}
|
|
269
|
+
onPress={onConfirm}
|
|
270
|
+
/>
|
|
271
|
+
</View>
|
|
272
|
+
</View>
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function pluginCardIdentity(plugin: OmpInstalledPlugin): string {
|
|
277
|
+
return `${plugin.source}:${plugin.scope ?? "global"}:${plugin.path ?? plugin.id}:${plugin.version ?? "unknown"}`;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
function confirmationFor(
|
|
281
|
+
input: OmpPluginMutation,
|
|
282
|
+
origin: ConfirmationOrigin,
|
|
283
|
+
): PendingConfirmation {
|
|
233
284
|
const target = input.action === "install" ? input.source : input.plugin;
|
|
234
285
|
switch (input.action) {
|
|
235
286
|
case "install":
|
|
236
287
|
return {
|
|
237
288
|
kind: "plugin",
|
|
238
289
|
input,
|
|
290
|
+
origin,
|
|
239
291
|
title: `Install ${target}?`,
|
|
240
292
|
warning:
|
|
241
293
|
"OMP plugins are trusted code. Installing can fetch code and change persistent state; runtime extensions load in a future OMP session.",
|
|
@@ -244,6 +296,7 @@ function confirmationFor(input: OmpPluginMutation): PendingConfirmation {
|
|
|
244
296
|
return {
|
|
245
297
|
kind: "plugin",
|
|
246
298
|
input,
|
|
299
|
+
origin,
|
|
247
300
|
title: `Enable ${target}?`,
|
|
248
301
|
warning:
|
|
249
302
|
"Enabling changes persistent state and permits this plugin's trusted code to load in future OMP sessions.",
|
|
@@ -252,6 +305,7 @@ function confirmationFor(input: OmpPluginMutation): PendingConfirmation {
|
|
|
252
305
|
return {
|
|
253
306
|
kind: "plugin",
|
|
254
307
|
input,
|
|
308
|
+
origin,
|
|
255
309
|
title: `Disable ${target}?`,
|
|
256
310
|
warning:
|
|
257
311
|
"Disabling changes persistent state. OMP sessions that are already running are not unloaded.",
|
|
@@ -260,6 +314,7 @@ function confirmationFor(input: OmpPluginMutation): PendingConfirmation {
|
|
|
260
314
|
return {
|
|
261
315
|
kind: "plugin",
|
|
262
316
|
input,
|
|
317
|
+
origin,
|
|
263
318
|
title: `Uninstall ${target}?`,
|
|
264
319
|
warning:
|
|
265
320
|
"Uninstalling removes the selected plugin registration and cached installation. Running OMP sessions are unchanged.",
|
|
@@ -268,6 +323,7 @@ function confirmationFor(input: OmpPluginMutation): PendingConfirmation {
|
|
|
268
323
|
return {
|
|
269
324
|
kind: "plugin",
|
|
270
325
|
input,
|
|
326
|
+
origin,
|
|
271
327
|
title: `Upgrade ${target}?`,
|
|
272
328
|
warning:
|
|
273
329
|
"Upgrading fetches and replaces trusted plugin code. The updated runtime loads in a future OMP session.",
|
|
@@ -278,11 +334,13 @@ function confirmationFor(input: OmpPluginMutation): PendingConfirmation {
|
|
|
278
334
|
function configConfirmationFor(
|
|
279
335
|
input: OmpPluginConfigMutation,
|
|
280
336
|
setting: OmpPluginConfigSetting,
|
|
337
|
+
origin: ConfirmationOrigin,
|
|
281
338
|
): PendingConfirmation {
|
|
282
339
|
if (input.action === "delete") {
|
|
283
340
|
return {
|
|
284
341
|
kind: "config",
|
|
285
342
|
input,
|
|
343
|
+
origin,
|
|
286
344
|
title: `Delete ${setting.key}?`,
|
|
287
345
|
warning:
|
|
288
346
|
"This changes persistent OMP plugin configuration. Future sessions will use the setting's default or environment fallback.",
|
|
@@ -291,6 +349,7 @@ function configConfirmationFor(
|
|
|
291
349
|
return {
|
|
292
350
|
kind: "config",
|
|
293
351
|
input,
|
|
352
|
+
origin,
|
|
294
353
|
title: `Set ${setting.key}?`,
|
|
295
354
|
warning: setting.secret
|
|
296
355
|
? "This writes a secret value to OMP's persistent plugin configuration. The value will remain write-only in Paseo."
|
|
@@ -302,18 +361,27 @@ function ConfigSettingEditor({
|
|
|
302
361
|
plugin,
|
|
303
362
|
setting,
|
|
304
363
|
busy,
|
|
364
|
+
confirmation,
|
|
365
|
+
confirmationOpen,
|
|
305
366
|
theme,
|
|
306
367
|
styles,
|
|
368
|
+
onCancel,
|
|
369
|
+
onApply,
|
|
307
370
|
onConfirm,
|
|
308
371
|
}: {
|
|
309
372
|
plugin: string;
|
|
310
373
|
setting: OmpPluginConfigSetting;
|
|
311
374
|
busy: boolean;
|
|
375
|
+
confirmation: PendingConfirmation | null;
|
|
376
|
+
confirmationOpen: boolean;
|
|
312
377
|
theme: PluginSurfaceProps["theme"];
|
|
313
378
|
styles: PluginManagerStyles;
|
|
379
|
+
onCancel(): void;
|
|
380
|
+
onApply(): void;
|
|
314
381
|
onConfirm(input: OmpPluginConfigMutation, setting: OmpPluginConfigSetting): void;
|
|
315
382
|
}) {
|
|
316
383
|
const [draft, setDraft] = useState<string | boolean>(setting.type === "boolean" ? false : "");
|
|
384
|
+
const blocked = busy || confirmationOpen;
|
|
317
385
|
let value: string | number | boolean | undefined;
|
|
318
386
|
let validationMessage: string | null = null;
|
|
319
387
|
if (!setting.secret) {
|
|
@@ -373,7 +441,7 @@ function ConfigSettingEditor({
|
|
|
373
441
|
<View style={styles.metadataRow}>
|
|
374
442
|
<Switch
|
|
375
443
|
accessibilityLabel={`New value for ${setting.key}`}
|
|
376
|
-
disabled={
|
|
444
|
+
disabled={blocked}
|
|
377
445
|
value={draft === true}
|
|
378
446
|
onValueChange={setDraft}
|
|
379
447
|
/>
|
|
@@ -387,8 +455,8 @@ function ConfigSettingEditor({
|
|
|
387
455
|
<Pressable
|
|
388
456
|
key={option}
|
|
389
457
|
accessibilityRole="radio"
|
|
390
|
-
accessibilityState={{ checked: selected, disabled:
|
|
391
|
-
disabled={
|
|
458
|
+
accessibilityState={{ checked: selected, disabled: blocked }}
|
|
459
|
+
disabled={blocked}
|
|
392
460
|
onPress={() => setDraft(option)}
|
|
393
461
|
style={[styles.scopeButton, selected ? styles.scopeButtonActive : null]}
|
|
394
462
|
>
|
|
@@ -402,7 +470,7 @@ function ConfigSettingEditor({
|
|
|
402
470
|
) : (
|
|
403
471
|
<TextInput
|
|
404
472
|
accessibilityLabel={`New value for ${setting.key}`}
|
|
405
|
-
editable={!
|
|
473
|
+
editable={!blocked}
|
|
406
474
|
value={typeof draft === "string" ? draft : ""}
|
|
407
475
|
onChangeText={setDraft}
|
|
408
476
|
placeholder="Enter a new value"
|
|
@@ -416,28 +484,38 @@ function ConfigSettingEditor({
|
|
|
416
484
|
{validationMessage && (setting.type !== "boolean" || value === undefined) ? (
|
|
417
485
|
<Text style={styles.error}>{validationMessage}</Text>
|
|
418
486
|
) : null}
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
487
|
+
{confirmation ? (
|
|
488
|
+
<ConfirmationPanel
|
|
489
|
+
confirmation={confirmation}
|
|
490
|
+
busy={busy}
|
|
491
|
+
styles={styles}
|
|
492
|
+
onCancel={onCancel}
|
|
493
|
+
onConfirm={onApply}
|
|
494
|
+
/>
|
|
495
|
+
) : (
|
|
496
|
+
<View style={styles.actions}>
|
|
497
|
+
{!setting.secret ? (
|
|
498
|
+
<ActionButton
|
|
499
|
+
label="Review change"
|
|
500
|
+
disabled={blocked || !candidate?.success}
|
|
501
|
+
primary
|
|
502
|
+
styles={styles}
|
|
503
|
+
onPress={() => {
|
|
504
|
+
if (candidate?.success) onConfirm(candidate.data, setting);
|
|
505
|
+
}}
|
|
506
|
+
/>
|
|
507
|
+
) : null}
|
|
508
|
+
{setting.configured ? (
|
|
509
|
+
<ActionButton
|
|
510
|
+
label="Delete setting"
|
|
511
|
+
disabled={blocked}
|
|
512
|
+
danger
|
|
513
|
+
styles={styles}
|
|
514
|
+
onPress={() => onConfirm({ action: "delete", plugin, key: setting.key }, setting)}
|
|
515
|
+
/>
|
|
516
|
+
) : null}
|
|
517
|
+
</View>
|
|
518
|
+
)}
|
|
441
519
|
</View>
|
|
442
520
|
);
|
|
443
521
|
}
|
|
@@ -445,19 +523,32 @@ function ConfigSettingEditor({
|
|
|
445
523
|
function PluginCard({
|
|
446
524
|
plugin,
|
|
447
525
|
busy,
|
|
526
|
+
confirmation,
|
|
527
|
+
confirmationOpen,
|
|
528
|
+
workspaceScoped,
|
|
448
529
|
inspecting,
|
|
449
530
|
styles,
|
|
531
|
+
onCancel,
|
|
532
|
+
onApply,
|
|
450
533
|
onConfirm,
|
|
451
534
|
onInspect,
|
|
452
535
|
}: {
|
|
453
536
|
plugin: OmpInstalledPlugin;
|
|
454
537
|
busy: boolean;
|
|
538
|
+
confirmation: PendingConfirmation | null;
|
|
539
|
+
confirmationOpen: boolean;
|
|
540
|
+
workspaceScoped: boolean;
|
|
455
541
|
inspecting: boolean;
|
|
456
542
|
styles: PluginManagerStyles;
|
|
457
|
-
|
|
543
|
+
onCancel(): void;
|
|
544
|
+
onApply(): void;
|
|
545
|
+
onConfirm(input: OmpPluginMutation, origin: ConfirmationOrigin): void;
|
|
458
546
|
onInspect(plugin: string): void;
|
|
459
547
|
}) {
|
|
460
|
-
const scope = plugin.scope
|
|
548
|
+
const scope = plugin.scope ?? undefined;
|
|
549
|
+
const identity = pluginCardIdentity(plugin);
|
|
550
|
+
const blocked = busy || confirmationOpen;
|
|
551
|
+
const projectUnavailable = plugin.scope === "project" && !workspaceScoped;
|
|
461
552
|
return (
|
|
462
553
|
<View style={styles.pluginCard}>
|
|
463
554
|
<View style={styles.cardHeader}>
|
|
@@ -490,56 +581,85 @@ function PluginCard({
|
|
|
490
581
|
) : null}
|
|
491
582
|
{plugin.scope === "project" ? (
|
|
492
583
|
<Text style={styles.warning}>
|
|
493
|
-
|
|
584
|
+
{workspaceScoped
|
|
585
|
+
? "This installation is scoped to the current workspace."
|
|
586
|
+
: "Open this project's workspace OMP panel to manage this installation."}
|
|
494
587
|
</Text>
|
|
495
588
|
) : null}
|
|
496
589
|
{plugin.ambiguous ? (
|
|
497
590
|
<Text style={styles.warning}>
|
|
498
|
-
Multiple installations share this
|
|
591
|
+
Multiple installations share this lifecycle target, so path-specific actions remain
|
|
592
|
+
unavailable.
|
|
593
|
+
</Text>
|
|
594
|
+
) : null}
|
|
595
|
+
{plugin.configAmbiguous ? (
|
|
596
|
+
<Text style={styles.warning}>
|
|
597
|
+
Multiple installations share this package identity, so settings are read-only.
|
|
499
598
|
</Text>
|
|
500
599
|
) : null}
|
|
501
600
|
</View>
|
|
502
|
-
|
|
503
|
-
<
|
|
504
|
-
|
|
505
|
-
|
|
601
|
+
{confirmation ? (
|
|
602
|
+
<ConfirmationPanel
|
|
603
|
+
confirmation={confirmation}
|
|
604
|
+
busy={busy}
|
|
506
605
|
styles={styles}
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
action: plugin.enabled ? "disable" : "enable",
|
|
510
|
-
plugin: plugin.id,
|
|
511
|
-
...(scope ? { scope } : {}),
|
|
512
|
-
})
|
|
513
|
-
}
|
|
606
|
+
onCancel={onCancel}
|
|
607
|
+
onConfirm={onApply}
|
|
514
608
|
/>
|
|
515
|
-
|
|
609
|
+
) : (
|
|
610
|
+
<View style={styles.actions}>
|
|
516
611
|
<ActionButton
|
|
517
|
-
label={
|
|
518
|
-
disabled={
|
|
612
|
+
label={plugin.enabled ? "Disable" : "Enable"}
|
|
613
|
+
disabled={blocked || projectUnavailable || plugin.ambiguous}
|
|
519
614
|
styles={styles}
|
|
520
|
-
onPress={() =>
|
|
615
|
+
onPress={() =>
|
|
616
|
+
onConfirm(
|
|
617
|
+
{
|
|
618
|
+
action: plugin.enabled ? "disable" : "enable",
|
|
619
|
+
plugin: plugin.id,
|
|
620
|
+
...(scope ? { scope } : {}),
|
|
621
|
+
},
|
|
622
|
+
{ surface: "plugin", key: identity },
|
|
623
|
+
)
|
|
624
|
+
}
|
|
521
625
|
/>
|
|
522
|
-
|
|
523
|
-
|
|
626
|
+
{plugin.configurable && plugin.packageName ? (
|
|
627
|
+
<ActionButton
|
|
628
|
+
label={inspecting ? "Loading settings…" : "Configure settings"}
|
|
629
|
+
disabled={
|
|
630
|
+
blocked || inspecting || plugin.scope === "project" || plugin.configAmbiguous
|
|
631
|
+
}
|
|
632
|
+
styles={styles}
|
|
633
|
+
onPress={() => onInspect(plugin.packageName ?? plugin.id)}
|
|
634
|
+
/>
|
|
635
|
+
) : null}
|
|
636
|
+
{plugin.source === "marketplace" ? (
|
|
637
|
+
<ActionButton
|
|
638
|
+
label="Upgrade"
|
|
639
|
+
disabled={blocked || projectUnavailable || plugin.ambiguous}
|
|
640
|
+
styles={styles}
|
|
641
|
+
onPress={() =>
|
|
642
|
+
onConfirm(
|
|
643
|
+
{ action: "upgrade", plugin: plugin.id, ...(scope ? { scope } : {}) },
|
|
644
|
+
{ surface: "plugin", key: identity },
|
|
645
|
+
)
|
|
646
|
+
}
|
|
647
|
+
/>
|
|
648
|
+
) : null}
|
|
524
649
|
<ActionButton
|
|
525
|
-
label="
|
|
526
|
-
disabled={
|
|
650
|
+
label="Uninstall"
|
|
651
|
+
disabled={blocked || projectUnavailable || plugin.ambiguous}
|
|
652
|
+
danger
|
|
527
653
|
styles={styles}
|
|
528
654
|
onPress={() =>
|
|
529
|
-
onConfirm(
|
|
655
|
+
onConfirm(
|
|
656
|
+
{ action: "uninstall", plugin: plugin.id, ...(scope ? { scope } : {}) },
|
|
657
|
+
{ surface: "plugin", key: identity },
|
|
658
|
+
)
|
|
530
659
|
}
|
|
531
660
|
/>
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
label="Uninstall"
|
|
535
|
-
disabled={busy || plugin.scope === "project" || plugin.ambiguous}
|
|
536
|
-
danger
|
|
537
|
-
styles={styles}
|
|
538
|
-
onPress={() =>
|
|
539
|
-
onConfirm({ action: "uninstall", plugin: plugin.id, ...(scope ? { scope } : {}) })
|
|
540
|
-
}
|
|
541
|
-
/>
|
|
542
|
-
</View>
|
|
661
|
+
</View>
|
|
662
|
+
)}
|
|
543
663
|
</View>
|
|
544
664
|
);
|
|
545
665
|
}
|
|
@@ -547,10 +667,15 @@ function PluginCard({
|
|
|
547
667
|
export function OmpPluginManagerSection({
|
|
548
668
|
theme,
|
|
549
669
|
compact,
|
|
670
|
+
cwd,
|
|
671
|
+
store,
|
|
550
672
|
}: {
|
|
551
673
|
theme: PluginSurfaceProps["theme"];
|
|
552
674
|
compact: boolean;
|
|
675
|
+
cwd?: string;
|
|
676
|
+
store?: OmpStore;
|
|
553
677
|
}) {
|
|
678
|
+
const context = { store, ...(cwd ? { cwd } : {}) };
|
|
554
679
|
const loadPlugins = useRpc(listOmpPlugins);
|
|
555
680
|
const inspectPluginConfig = useRpc(inspectOmpPluginConfig);
|
|
556
681
|
const mutatePlugin = useRpc(mutateOmpPlugin);
|
|
@@ -564,14 +689,19 @@ export function OmpPluginManagerSection({
|
|
|
564
689
|
const [configEditGenerations, setConfigEditGenerations] = useState<Record<string, number>>({});
|
|
565
690
|
const inspectionGeneration = useRef(0);
|
|
566
691
|
const plugins = useQuery({
|
|
567
|
-
queryKey: PLUGINS_QUERY_KEY,
|
|
568
|
-
queryFn: () => loadPlugins(
|
|
692
|
+
queryKey: [...PLUGINS_QUERY_KEY, ompStoreKey(store), cwd ?? "global"],
|
|
693
|
+
queryFn: () => loadPlugins(context),
|
|
569
694
|
staleTime: Number.POSITIVE_INFINITY,
|
|
570
695
|
});
|
|
571
696
|
const mutation = useMutation({
|
|
572
|
-
|
|
697
|
+
mutationKey: ["paseo-omp", "plugins", ompStoreKey(store)],
|
|
698
|
+
mutationFn: (input: OmpPluginMutation) => mutatePlugin({ ...input, ...context }),
|
|
573
699
|
onSuccess: (result) => {
|
|
574
|
-
queryClient.
|
|
700
|
+
void queryClient.invalidateQueries({ queryKey: PLUGINS_QUERY_KEY });
|
|
701
|
+
queryClient.setQueryData(
|
|
702
|
+
[...PLUGINS_QUERY_KEY, ompStoreKey(store), cwd ?? "global"],
|
|
703
|
+
result.state,
|
|
704
|
+
);
|
|
575
705
|
setNotice({ tone: result.ok ? "success" : "error", text: result.message });
|
|
576
706
|
if (result.ok && confirmation?.kind === "plugin" && confirmation.input.action === "install") {
|
|
577
707
|
setSource("");
|
|
@@ -585,7 +715,7 @@ export function OmpPluginManagerSection({
|
|
|
585
715
|
});
|
|
586
716
|
const configInspection = useMutation({
|
|
587
717
|
mutationFn: ({ plugin }: { plugin: string; generation: number }) =>
|
|
588
|
-
inspectPluginConfig({ plugin }),
|
|
718
|
+
inspectPluginConfig({ plugin, ...context }),
|
|
589
719
|
onSuccess: (result, request) => {
|
|
590
720
|
if (inspectionGeneration.current === request.generation) setInspected(result);
|
|
591
721
|
},
|
|
@@ -594,7 +724,8 @@ export function OmpPluginManagerSection({
|
|
|
594
724
|
},
|
|
595
725
|
});
|
|
596
726
|
const configMutation = useMutation({
|
|
597
|
-
|
|
727
|
+
mutationKey: ["paseo-omp", "plugin-config", ompStoreKey(store)],
|
|
728
|
+
mutationFn: (input: OmpPluginConfigMutation) => mutatePluginConfig({ ...input, ...context }),
|
|
598
729
|
onSuccess: (result, input) => {
|
|
599
730
|
if (result.config.available) setInspected(result.config);
|
|
600
731
|
if (result.ok) {
|
|
@@ -604,6 +735,7 @@ export function OmpPluginManagerSection({
|
|
|
604
735
|
[identity]: (current[identity] ?? 0) + 1,
|
|
605
736
|
}));
|
|
606
737
|
}
|
|
738
|
+
void queryClient.invalidateQueries({ queryKey: PLUGINS_QUERY_KEY });
|
|
607
739
|
setNotice({ tone: result.ok ? "success" : "error", text: result.message });
|
|
608
740
|
setConfirmation(null);
|
|
609
741
|
},
|
|
@@ -613,6 +745,25 @@ export function OmpPluginManagerSection({
|
|
|
613
745
|
},
|
|
614
746
|
});
|
|
615
747
|
const busy = mutation.isPending || configMutation.isPending;
|
|
748
|
+
useEffect(() => {
|
|
749
|
+
if (!confirmation) return;
|
|
750
|
+
const { origin } = confirmation;
|
|
751
|
+
if (
|
|
752
|
+
origin.surface === "plugin" &&
|
|
753
|
+
plugins.data?.available &&
|
|
754
|
+
!plugins.data.plugins.some((plugin) => pluginCardIdentity(plugin) === origin.key)
|
|
755
|
+
) {
|
|
756
|
+
setConfirmation(null);
|
|
757
|
+
return;
|
|
758
|
+
}
|
|
759
|
+
if (
|
|
760
|
+
origin.surface === "config" &&
|
|
761
|
+
inspected &&
|
|
762
|
+
!inspected.settings.some((setting) => `${inspected.plugin}:${setting.key}` === origin.key)
|
|
763
|
+
) {
|
|
764
|
+
setConfirmation(null);
|
|
765
|
+
}
|
|
766
|
+
}, [confirmation, inspected, plugins.data]);
|
|
616
767
|
|
|
617
768
|
const requestInstall = () => {
|
|
618
769
|
const parsed = OmpPluginInstallSourceSchema.safeParse(source);
|
|
@@ -624,18 +775,33 @@ export function OmpPluginManagerSection({
|
|
|
624
775
|
return;
|
|
625
776
|
}
|
|
626
777
|
setNotice(null);
|
|
627
|
-
setConfirmation(
|
|
778
|
+
setConfirmation(
|
|
779
|
+
confirmationFor(
|
|
780
|
+
{
|
|
781
|
+
action: "install",
|
|
782
|
+
source: parsed.data,
|
|
783
|
+
scope: "user",
|
|
784
|
+
...context,
|
|
785
|
+
},
|
|
786
|
+
{ surface: "install" },
|
|
787
|
+
),
|
|
788
|
+
);
|
|
628
789
|
};
|
|
629
|
-
const requestMutation = (input: OmpPluginMutation) => {
|
|
790
|
+
const requestMutation = (input: OmpPluginMutation, origin: ConfirmationOrigin) => {
|
|
630
791
|
setNotice(null);
|
|
631
|
-
setConfirmation(confirmationFor(input));
|
|
792
|
+
setConfirmation(confirmationFor({ ...input, ...context }, origin));
|
|
632
793
|
};
|
|
633
794
|
const requestConfigMutation = (
|
|
634
795
|
input: OmpPluginConfigMutation,
|
|
635
796
|
setting: OmpPluginConfigSetting,
|
|
636
797
|
) => {
|
|
637
798
|
setNotice(null);
|
|
638
|
-
setConfirmation(
|
|
799
|
+
setConfirmation(
|
|
800
|
+
configConfirmationFor({ ...input, ...context }, setting, {
|
|
801
|
+
surface: "config",
|
|
802
|
+
key: `${input.plugin}:${input.key}`,
|
|
803
|
+
}),
|
|
804
|
+
);
|
|
639
805
|
};
|
|
640
806
|
const inspect = (plugin: string) => {
|
|
641
807
|
inspectionGeneration.current += 1;
|
|
@@ -665,7 +831,7 @@ export function OmpPluginManagerSection({
|
|
|
665
831
|
</View>
|
|
666
832
|
<ActionButton
|
|
667
833
|
label={plugins.isFetching ? "Refreshing…" : "Refresh"}
|
|
668
|
-
disabled={plugins.isFetching || busy}
|
|
834
|
+
disabled={plugins.isFetching || busy || confirmation !== null}
|
|
669
835
|
styles={styles}
|
|
670
836
|
onPress={() => {
|
|
671
837
|
void plugins.refetch();
|
|
@@ -681,7 +847,7 @@ export function OmpPluginManagerSection({
|
|
|
681
847
|
</Text>
|
|
682
848
|
<TextInput
|
|
683
849
|
accessibilityLabel="OMP plugin source"
|
|
684
|
-
editable={!busy}
|
|
850
|
+
editable={!busy && confirmation === null}
|
|
685
851
|
value={source}
|
|
686
852
|
onChangeText={setSource}
|
|
687
853
|
placeholder="name@marketplace or package source"
|
|
@@ -690,43 +856,26 @@ export function OmpPluginManagerSection({
|
|
|
690
856
|
autoCorrect={false}
|
|
691
857
|
style={styles.input}
|
|
692
858
|
/>
|
|
693
|
-
|
|
694
|
-
<
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
primary
|
|
859
|
+
{confirmation?.origin.surface === "install" ? (
|
|
860
|
+
<ConfirmationPanel
|
|
861
|
+
confirmation={confirmation}
|
|
862
|
+
busy={busy}
|
|
698
863
|
styles={styles}
|
|
699
|
-
|
|
864
|
+
onCancel={() => setConfirmation(null)}
|
|
865
|
+
onConfirm={applyConfirmation}
|
|
700
866
|
/>
|
|
701
|
-
|
|
702
|
-
</View>
|
|
703
|
-
|
|
704
|
-
{confirmation ? (
|
|
705
|
-
<View accessibilityRole="alert" style={styles.confirmation}>
|
|
706
|
-
<Text style={styles.cardTitle}>{confirmation.title}</Text>
|
|
707
|
-
<Text style={styles.warning}>{confirmation.warning}</Text>
|
|
867
|
+
) : (
|
|
708
868
|
<View style={styles.actions}>
|
|
709
869
|
<ActionButton
|
|
710
|
-
label="
|
|
711
|
-
disabled={busy}
|
|
712
|
-
styles={styles}
|
|
713
|
-
onPress={() => setConfirmation(null)}
|
|
714
|
-
/>
|
|
715
|
-
<ActionButton
|
|
716
|
-
label={busy ? "Applying…" : "Confirm"}
|
|
717
|
-
disabled={busy}
|
|
870
|
+
label="Review install"
|
|
871
|
+
disabled={busy || confirmation !== null || source.length === 0}
|
|
718
872
|
primary
|
|
719
|
-
danger={
|
|
720
|
-
confirmation.kind === "plugin"
|
|
721
|
-
? confirmation.input.action === "uninstall"
|
|
722
|
-
: confirmation.input.action === "delete"
|
|
723
|
-
}
|
|
724
873
|
styles={styles}
|
|
725
|
-
onPress={
|
|
874
|
+
onPress={requestInstall}
|
|
726
875
|
/>
|
|
727
876
|
</View>
|
|
728
|
-
|
|
729
|
-
|
|
877
|
+
)}
|
|
878
|
+
</View>
|
|
730
879
|
|
|
731
880
|
{notice ? (
|
|
732
881
|
<Text
|
|
@@ -763,23 +912,34 @@ export function OmpPluginManagerSection({
|
|
|
763
912
|
|
|
764
913
|
{plugins.data?.plugins.length ? (
|
|
765
914
|
<View style={styles.pluginGrid}>
|
|
766
|
-
{plugins.data.plugins.map((plugin) =>
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
plugin
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
915
|
+
{plugins.data.plugins.map((plugin) => {
|
|
916
|
+
const identity = pluginCardIdentity(plugin);
|
|
917
|
+
const localConfirmation =
|
|
918
|
+
confirmation?.origin.surface === "plugin" && confirmation.origin.key === identity
|
|
919
|
+
? confirmation
|
|
920
|
+
: null;
|
|
921
|
+
return (
|
|
922
|
+
<PluginCard
|
|
923
|
+
key={identity}
|
|
924
|
+
plugin={plugin}
|
|
925
|
+
busy={busy}
|
|
926
|
+
confirmation={localConfirmation}
|
|
927
|
+
confirmationOpen={confirmation !== null}
|
|
928
|
+
workspaceScoped={cwd !== undefined}
|
|
929
|
+
inspecting={
|
|
930
|
+
configInspection.isPending &&
|
|
931
|
+
configInspection.variables?.plugin === plugin.packageName
|
|
932
|
+
}
|
|
933
|
+
styles={styles}
|
|
934
|
+
onCancel={() => setConfirmation(null)}
|
|
935
|
+
onApply={applyConfirmation}
|
|
936
|
+
onConfirm={requestMutation}
|
|
937
|
+
onInspect={inspect}
|
|
938
|
+
/>
|
|
939
|
+
);
|
|
940
|
+
})}
|
|
780
941
|
</View>
|
|
781
942
|
) : null}
|
|
782
|
-
|
|
783
943
|
{configInspection.error || configMutation.error ? (
|
|
784
944
|
<Text accessibilityRole="alert" style={styles.error}>
|
|
785
945
|
Could not update OMP plugin settings.
|
|
@@ -791,7 +951,7 @@ export function OmpPluginManagerSection({
|
|
|
791
951
|
<Text style={styles.cardTitle}>Settings · {inspected.plugin}</Text>
|
|
792
952
|
<ActionButton
|
|
793
953
|
label="Close"
|
|
794
|
-
disabled={busy}
|
|
954
|
+
disabled={busy || confirmation !== null}
|
|
795
955
|
styles={styles}
|
|
796
956
|
onPress={() => {
|
|
797
957
|
inspectionGeneration.current += 1;
|
|
@@ -814,17 +974,28 @@ export function OmpPluginManagerSection({
|
|
|
814
974
|
<Text style={styles.muted}>This plugin declares no settings.</Text>
|
|
815
975
|
) : null}
|
|
816
976
|
<View style={styles.settings}>
|
|
817
|
-
{inspected.settings.map((setting) =>
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
977
|
+
{inspected.settings.map((setting) => {
|
|
978
|
+
const identity = `${inspected.plugin}:${setting.key}`;
|
|
979
|
+
const localConfirmation =
|
|
980
|
+
confirmation?.origin.surface === "config" && confirmation.origin.key === identity
|
|
981
|
+
? confirmation
|
|
982
|
+
: null;
|
|
983
|
+
return (
|
|
984
|
+
<ConfigSettingEditor
|
|
985
|
+
key={`${identity}:${configEditGenerations[identity] ?? 0}`}
|
|
986
|
+
plugin={inspected.plugin}
|
|
987
|
+
setting={setting}
|
|
988
|
+
busy={busy}
|
|
989
|
+
confirmation={localConfirmation}
|
|
990
|
+
confirmationOpen={confirmation !== null}
|
|
991
|
+
theme={theme}
|
|
992
|
+
styles={styles}
|
|
993
|
+
onCancel={() => setConfirmation(null)}
|
|
994
|
+
onApply={applyConfirmation}
|
|
995
|
+
onConfirm={requestConfigMutation}
|
|
996
|
+
/>
|
|
997
|
+
);
|
|
998
|
+
})}
|
|
828
999
|
</View>
|
|
829
1000
|
</View>
|
|
830
1001
|
) : null}
|