@omercnet/paseo-pr-radar 0.4.1 → 1.0.0-next.155.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/README.md +11 -30
- package/client/directory-observation.ts +55 -0
- package/client/pr-radar.tsx +18 -34
- package/client/radar.ts +2 -11
- package/package.json +12 -13
- package/paseo-plugin.json +2 -1
package/README.md
CHANGED
|
@@ -30,7 +30,7 @@ Paseo supplies normalized workspace pull request status. A daemon-side plugin ha
|
|
|
30
30
|
|
|
31
31
|
## Install
|
|
32
32
|
|
|
33
|
-
### Paseo 0.9
|
|
33
|
+
### Paseo 0.9
|
|
34
34
|
|
|
35
35
|
Paseo 0.9 supports npm plugin sources. Install the published package on the daemon host:
|
|
36
36
|
|
|
@@ -44,44 +44,25 @@ Update an npm installation to the latest published release:
|
|
|
44
44
|
paseo plugin update pr-radar
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
-
The npm install and update flow requires Paseo 0.9.
|
|
47
|
+
The npm install and update flow requires Paseo 0.9.
|
|
48
48
|
|
|
49
|
-
### Paseo 0.8
|
|
50
|
-
|
|
51
|
-
Install from the Git monorepo:
|
|
52
|
-
|
|
53
|
-
```bash
|
|
54
|
-
paseo plugin add omercnet/paseo-plugins:pr-radar
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
Or install a local checkout by absolute path on the daemon host:
|
|
58
|
-
|
|
59
|
-
```bash
|
|
60
|
-
paseo plugin install /absolute/path/to/paseo-plugins/pr-radar
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
On Paseo 0.8, `plugin update` updates Git-managed installations only. Local directory
|
|
64
|
-
installations continue to use their checked-out source and require `plugin reload` after edits.
|
|
65
49
|
|
|
66
50
|
The daemon must have plugins enabled and `gh` authenticated for GitHub viewer-aware triage.
|
|
67
51
|
|
|
68
52
|
## Develop
|
|
69
53
|
|
|
70
54
|
```bash
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
npx paseo plugin install "$PWD"
|
|
77
|
-
npx paseo plugin reload pr-radar
|
|
55
|
+
bun install
|
|
56
|
+
bun run check
|
|
57
|
+
bun run test
|
|
58
|
+
bun run test:coverage
|
|
59
|
+
bun run typecheck
|
|
78
60
|
```
|
|
79
61
|
|
|
80
62
|
Release Please maintains the version, changelog, component tag, and GitHub release from
|
|
81
63
|
Conventional Commits in the monorepo.
|
|
82
64
|
|
|
83
|
-
The manifest
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
Android. React `19.1` and React Native `0.81` match the versions supplied by the plugin host.
|
|
65
|
+
The manifest requires Paseo `^0.9.0`. Development uses the `0.9.0` CLI, client, plugin SDK, and
|
|
66
|
+
protocol packages together. Host-owned navigation opens linked agents and workspaces without private
|
|
67
|
+
routes or page reloads on web, desktop, iOS, and Android. React `19.1` and React Native `0.81`
|
|
68
|
+
match the versions supplied by the plugin host.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { PaseoApi } from "./radar";
|
|
2
|
+
|
|
3
|
+
export function observeDirectoryInvalidation(
|
|
4
|
+
paseo: PaseoApi,
|
|
5
|
+
invalidate: () => void,
|
|
6
|
+
debounceMs: number,
|
|
7
|
+
): () => void {
|
|
8
|
+
const lifetime = new AbortController();
|
|
9
|
+
const subscriptions: Array<{ release(): Promise<void> }> = [];
|
|
10
|
+
const unsubscribes: Array<() => void> = [];
|
|
11
|
+
let stopped = false;
|
|
12
|
+
let timer: NodeJS.Timeout | undefined;
|
|
13
|
+
const scheduleInvalidation = () => {
|
|
14
|
+
if (stopped || timer !== undefined) return;
|
|
15
|
+
timer = setTimeout(() => {
|
|
16
|
+
timer = undefined;
|
|
17
|
+
if (!stopped) invalidate();
|
|
18
|
+
}, debounceMs);
|
|
19
|
+
};
|
|
20
|
+
const attach = (subscription: {
|
|
21
|
+
subscribe(observer: { snapshot(): void; update(message: unknown): void }): () => void;
|
|
22
|
+
release(): Promise<void>;
|
|
23
|
+
}) => {
|
|
24
|
+
subscriptions.push(subscription);
|
|
25
|
+
if (stopped) {
|
|
26
|
+
void subscription.release().catch(() => undefined);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
unsubscribes.push(
|
|
30
|
+
subscription.subscribe({
|
|
31
|
+
snapshot: scheduleInvalidation,
|
|
32
|
+
update: scheduleInvalidation,
|
|
33
|
+
}),
|
|
34
|
+
);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
void paseo.agents
|
|
38
|
+
.list({ subscribe: {}, signal: lifetime.signal })
|
|
39
|
+
.then(({ subscription }) => attach(subscription))
|
|
40
|
+
.catch(() => undefined);
|
|
41
|
+
void paseo.workspaces
|
|
42
|
+
.list({ subscribe: {} })
|
|
43
|
+
.then(({ subscription }) => attach(subscription))
|
|
44
|
+
.catch(() => undefined);
|
|
45
|
+
|
|
46
|
+
return () => {
|
|
47
|
+
stopped = true;
|
|
48
|
+
lifetime.abort();
|
|
49
|
+
if (timer !== undefined) clearTimeout(timer);
|
|
50
|
+
for (const unsubscribe of unsubscribes) unsubscribe();
|
|
51
|
+
void Promise.all(subscriptions.map((subscription) => subscription.release())).catch(
|
|
52
|
+
() => undefined,
|
|
53
|
+
);
|
|
54
|
+
};
|
|
55
|
+
}
|
package/client/pr-radar.tsx
CHANGED
|
@@ -1,17 +1,14 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
openExternalUrl,
|
|
3
|
+
type PluginSurfaceProps,
|
|
4
|
+
usePaseo,
|
|
5
|
+
useRpc,
|
|
6
|
+
} from "@getpaseo/plugin/client";
|
|
3
7
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
4
8
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
5
|
-
import {
|
|
6
|
-
ActivityIndicator,
|
|
7
|
-
FlatList,
|
|
8
|
-
Linking,
|
|
9
|
-
Pressable,
|
|
10
|
-
Text,
|
|
11
|
-
TextInput,
|
|
12
|
-
View,
|
|
13
|
-
} from "react-native";
|
|
9
|
+
import { ActivityIndicator, FlatList, Pressable, Text, TextInput, View } from "react-native";
|
|
14
10
|
import { acknowledgeViewerScope, viewerScope } from "../shared/viewer-scope";
|
|
11
|
+
import { observeDirectoryInvalidation } from "./directory-observation";
|
|
15
12
|
import {
|
|
16
13
|
type AgentEntry,
|
|
17
14
|
agentActionFor,
|
|
@@ -40,11 +37,6 @@ const CLOCK_TICK_MS = 30_000;
|
|
|
40
37
|
|
|
41
38
|
type SavedView = "security" | "updated" | "stale" | "automation";
|
|
42
39
|
|
|
43
|
-
const openExternalUrlCandidate: unknown = Reflect.get(PaseoClient, "openExternalUrl");
|
|
44
|
-
const guardedOpenExternalUrl =
|
|
45
|
-
typeof openExternalUrlCandidate === "function"
|
|
46
|
-
? (openExternalUrlCandidate as (url: string) => Promise<void>)
|
|
47
|
-
: undefined;
|
|
48
40
|
const SAVED_VIEW_TITLES: Record<SavedView, string> = {
|
|
49
41
|
security: "Security",
|
|
50
42
|
updated: "Updated",
|
|
@@ -136,23 +128,15 @@ export function PrRadar({ theme, layout, host, navigation }: PluginSurfaceProps)
|
|
|
136
128
|
return () => clearInterval(clock);
|
|
137
129
|
}, []);
|
|
138
130
|
|
|
139
|
-
useEffect(
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
const unsubscribeAgents = paseo.agents.subscribe(invalidate);
|
|
149
|
-
const unsubscribeWorkspaces = paseo.workspaces.subscribe(invalidate);
|
|
150
|
-
return () => {
|
|
151
|
-
clearTimeout(timer);
|
|
152
|
-
unsubscribeAgents();
|
|
153
|
-
unsubscribeWorkspaces();
|
|
154
|
-
};
|
|
155
|
-
}, [paseo, queryClient, queryKey]);
|
|
131
|
+
useEffect(
|
|
132
|
+
() =>
|
|
133
|
+
observeDirectoryInvalidation(
|
|
134
|
+
paseo,
|
|
135
|
+
() => void queryClient.invalidateQueries({ queryKey }),
|
|
136
|
+
EVENT_DEBOUNCE_MS,
|
|
137
|
+
),
|
|
138
|
+
[paseo, queryClient, queryKey],
|
|
139
|
+
);
|
|
156
140
|
|
|
157
141
|
const rawRows = data?.rows ?? [];
|
|
158
142
|
const scopeUrls = useMemo(() => rawRows.map((row) => row.url), [rawRows]);
|
|
@@ -523,7 +507,7 @@ export function PrRadar({ theme, layout, host, navigation }: PluginSurfaceProps)
|
|
|
523
507
|
const openPr = useCallback(async (row: RadarRow) => {
|
|
524
508
|
setOpenError(null);
|
|
525
509
|
try {
|
|
526
|
-
await openPullRequestUrl(row.url,
|
|
510
|
+
await openPullRequestUrl(row.url, openExternalUrl);
|
|
527
511
|
} catch {
|
|
528
512
|
setOpenError(`Could not open ${row.repository}#${row.number ?? "PR"}.`);
|
|
529
513
|
}
|
package/client/radar.ts
CHANGED
|
@@ -314,19 +314,10 @@ export function buildAgentPrompt(row: RadarRow): string {
|
|
|
314
314
|
|
|
315
315
|
type UrlOpener = (url: string) => Promise<unknown>;
|
|
316
316
|
|
|
317
|
-
export async function openPullRequestUrl(
|
|
318
|
-
url: string,
|
|
319
|
-
guardedOpen: UrlOpener | undefined,
|
|
320
|
-
fallback: { openURL: UrlOpener },
|
|
321
|
-
): Promise<void> {
|
|
317
|
+
export async function openPullRequestUrl(url: string, open: UrlOpener): Promise<void> {
|
|
322
318
|
const parsed = HttpsUrlSchema.safeParse(url);
|
|
323
319
|
if (!parsed.success) throw new Error("Only HTTPS pull request URLs are supported.");
|
|
324
|
-
|
|
325
|
-
if (guardedOpen) {
|
|
326
|
-
await guardedOpen(parsed.data);
|
|
327
|
-
return;
|
|
328
|
-
}
|
|
329
|
-
await fallback.openURL(parsed.data);
|
|
320
|
+
await open(parsed.data);
|
|
330
321
|
}
|
|
331
322
|
|
|
332
323
|
export function buildRadarSnapshot(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@omercnet/paseo-pr-radar",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0-next.155.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A viewer-aware delivery queue for pull requests linked to Paseo workspaces.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"publishConfig": {
|
|
18
18
|
"access": "public"
|
|
19
19
|
},
|
|
20
|
-
"packageManager": "
|
|
20
|
+
"packageManager": "bun@1.4.2",
|
|
21
21
|
"engines": {
|
|
22
22
|
"node": ">=24"
|
|
23
23
|
},
|
|
@@ -42,24 +42,23 @@
|
|
|
42
42
|
"check:write": "biome check --write .",
|
|
43
43
|
"test": "vitest run",
|
|
44
44
|
"test:coverage": "vitest run --coverage --coverage.reporter=text --coverage.reporter=lcov --coverage.thresholds.lines=90 --coverage.thresholds.functions=85",
|
|
45
|
-
"typecheck": "tsc --noEmit"
|
|
46
|
-
"package:release": "node scripts/package-release.ts"
|
|
45
|
+
"typecheck": "tsc --noEmit"
|
|
47
46
|
},
|
|
48
47
|
"devDependencies": {
|
|
49
48
|
"@biomejs/biome": "^2.5.10",
|
|
50
|
-
"@getpaseo/cli": "0.9.0
|
|
51
|
-
"@getpaseo/client": "0.9.0
|
|
52
|
-
"@getpaseo/plugin": "0.9.0
|
|
53
|
-
"@getpaseo/protocol": "0.9.0
|
|
49
|
+
"@getpaseo/cli": "0.9.0",
|
|
50
|
+
"@getpaseo/client": "0.9.0",
|
|
51
|
+
"@getpaseo/plugin": "0.9.0",
|
|
52
|
+
"@getpaseo/protocol": "0.9.0",
|
|
54
53
|
"@tanstack/react-query": "^5.102.3",
|
|
55
|
-
"@types/node": "^24.
|
|
56
|
-
"@types/react": "
|
|
54
|
+
"@types/node": "^24.10.1",
|
|
55
|
+
"@types/react": "^19.2.18",
|
|
56
|
+
"@vitest/coverage-v8": "^5.0.0",
|
|
57
57
|
"fflate": "^0.8.3",
|
|
58
58
|
"react": "19.1.0",
|
|
59
59
|
"react-native": "0.81.5",
|
|
60
|
-
"typescript": "^7.0.
|
|
61
|
-
"@vitest/coverage-v8": "^5.0.0",
|
|
60
|
+
"typescript": "^7.0.2",
|
|
62
61
|
"vitest": "^5.0.0",
|
|
63
|
-
"zod": "
|
|
62
|
+
"zod": "4.4.3"
|
|
64
63
|
}
|
|
65
64
|
}
|
package/paseo-plugin.json
CHANGED