@omercnet/paseo-gas-city 0.1.0 → 0.2.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 +13 -0
- package/README.md +27 -17
- package/client/city-operations.tsx +4 -10
- package/client/factory-panel.tsx +1 -3
- package/client/gas-city-surface.tsx +2 -8
- package/index.server.ts +35 -24
- package/package.json +15 -14
- package/paseo-plugin.json +1 -1
- package/server/handlers.ts +23 -31
- package/shared/rpc.ts +5 -9
- package/shared/settings.ts +0 -16
- package/bun.lock +0 -1217
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.2.0](https://github.com/omercnet/paseo-plugins/compare/paseo-gas-city-v0.1.0...paseo-gas-city-v0.2.0) (2026-09-18)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **release:** publish plugins to npm ([#80](https://github.com/omercnet/paseo-plugins/issues/80)) ([3c93048](https://github.com/omercnet/paseo-plugins/commit/3c93048cfefda97d8c2bc1631e3428fb64bdad09))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* **gas-city:** support Paseo 0.9 beta settings ([#102](https://github.com/omercnet/paseo-plugins/issues/102)) ([dd4ccda](https://github.com/omercnet/paseo-plugins/commit/dd4ccda0d85e4160c9ad39d5a9045fb690ed5510))
|
|
14
|
+
* **gas-city:** support Paseo 0.9 beta settings ([#91](https://github.com/omercnet/paseo-plugins/issues/91)) ([15c9a97](https://github.com/omercnet/paseo-plugins/commit/15c9a970ce5fccd7a09ed4284b8aa2d37c43b464))
|
|
15
|
+
|
|
3
16
|
## [0.1.0](https://github.com/omercnet/paseo-plugins/compare/paseo-gas-city-v0.0.1...paseo-gas-city-v0.1.0) (2026-09-11)
|
|
4
17
|
|
|
5
18
|
|
package/README.md
CHANGED
|
@@ -48,6 +48,11 @@ Gas City settings are host-scoped and shared by every Paseo client connected to
|
|
|
48
48
|
- **Workspace mappings** override automatic longest-ancestor rig matching when a workspace is
|
|
49
49
|
ambiguous or lives outside its rig path.
|
|
50
50
|
|
|
51
|
+
Paseo 0.8 does not expose persisted settings to server handlers. On 0.8, server operations therefore
|
|
52
|
+
use schema defaults only: the loopback endpoint, remote access and mutations disabled, the default
|
|
53
|
+
event limit, and no workspace mappings. Customized Gas City settings require Paseo `0.9.0-beta.1`
|
|
54
|
+
or later.
|
|
55
|
+
|
|
51
56
|
Settings are a safety and routing configuration, not a credential vault. Put authentication and
|
|
52
57
|
network access controls in front of Gas City itself.
|
|
53
58
|
|
|
@@ -64,7 +69,7 @@ host. Enabling a remote endpoint sends requests to that host from the Paseo daem
|
|
|
64
69
|
|
|
65
70
|
## Requirements and limitations
|
|
66
71
|
|
|
67
|
-
- Paseo `^0.8.0` with plugins enabled.
|
|
72
|
+
- Paseo `^0.8.0` or `^0.9.0-beta.1` with plugins enabled.
|
|
68
73
|
- A reachable Gas City v1.4.1 supervisor exposing its HTTP API.
|
|
69
74
|
- HTTP or HTTPS endpoints only. Credentials, query strings, and fragments are rejected.
|
|
70
75
|
- Automatic workspace mapping requires the workspace path to be inside exactly one discovered rig;
|
|
@@ -79,24 +84,32 @@ host. Enabling a remote endpoint sends requests to that host from the Paseo daem
|
|
|
79
84
|
|
|
80
85
|
## Install
|
|
81
86
|
|
|
82
|
-
|
|
87
|
+
With Paseo `0.9.0-beta.1`, install the npm package:
|
|
83
88
|
|
|
84
89
|
```bash
|
|
85
|
-
paseo plugin
|
|
90
|
+
paseo plugin install npm:@omercnet/paseo-gas-city
|
|
86
91
|
```
|
|
87
92
|
|
|
88
|
-
|
|
93
|
+
Paseo 0.9 npm updates are reviewed before they are applied. Check for a candidate, then run the
|
|
94
|
+
interactive review:
|
|
89
95
|
|
|
90
96
|
```bash
|
|
97
|
+
paseo plugin update gas-city --check
|
|
91
98
|
paseo plugin update gas-city
|
|
92
99
|
```
|
|
93
100
|
|
|
94
|
-
|
|
101
|
+
Paseo 0.8 users can install from Git instead:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
paseo plugin install omercnet/paseo-plugins:paseo-gas-city
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Paseo 0.8 and 0.9 can also install from a local checkout on the Paseo daemon host:
|
|
95
108
|
|
|
96
109
|
```bash
|
|
97
110
|
git clone https://github.com/omercnet/paseo-plugins.git
|
|
98
111
|
cd paseo-plugins/paseo-gas-city
|
|
99
|
-
|
|
112
|
+
npm ci
|
|
100
113
|
paseo plugin install "$PWD"
|
|
101
114
|
```
|
|
102
115
|
|
|
@@ -117,24 +130,21 @@ mapped rig.
|
|
|
117
130
|
## Develop
|
|
118
131
|
|
|
119
132
|
```bash
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
133
|
+
npm ci
|
|
134
|
+
npm run check
|
|
135
|
+
npm run typecheck
|
|
136
|
+
npm test
|
|
137
|
+
npm run test:coverage
|
|
138
|
+
npm run verify:package
|
|
126
139
|
```
|
|
127
140
|
|
|
128
141
|
Build and verify the distributable archives with:
|
|
129
142
|
|
|
130
143
|
```bash
|
|
131
|
-
|
|
132
|
-
|
|
144
|
+
npm run verify:package
|
|
145
|
+
npm run package:release
|
|
133
146
|
```
|
|
134
147
|
|
|
135
148
|
Release Please maintains the package version, changelog, component tag, and GitHub release. Tags use
|
|
136
149
|
`paseo-gas-city-v<version>`. The release workflow re-runs checks, typechecking, coverage, and package
|
|
137
150
|
verification before uploading the ZIP asset and its SHA-256 checksum.
|
|
138
|
-
|
|
139
|
-
The package is `@omercnet/paseo-gas-city` at version `0.0.1`. The supported distribution paths are
|
|
140
|
-
the Git source above and the versioned GitHub release ZIP.
|
|
@@ -30,7 +30,6 @@ import {
|
|
|
30
30
|
listWork,
|
|
31
31
|
performSessionAction,
|
|
32
32
|
type SessionActionRequest,
|
|
33
|
-
toGasCityRpcSettings,
|
|
34
33
|
} from "../shared";
|
|
35
34
|
import type { SlingIntent } from "./dispatch-intent";
|
|
36
35
|
import {
|
|
@@ -392,7 +391,6 @@ export function CityOperations({
|
|
|
392
391
|
const [sessionMessage, setSessionMessage] = useState("");
|
|
393
392
|
const [interactionResponse, setInteractionResponse] = useState<InteractionResponse>("allow");
|
|
394
393
|
const [eventCursor, setEventCursor] = useState<string | null>(null);
|
|
395
|
-
const rpcSettings = useMemo(() => toGasCityRpcSettings(settings), [settings]);
|
|
396
394
|
|
|
397
395
|
useEffect(() => {
|
|
398
396
|
if (!slingIntent) return;
|
|
@@ -403,10 +401,7 @@ export function CityOperations({
|
|
|
403
401
|
onDismissSlingIntent?.(slingIntent.id);
|
|
404
402
|
}, [onDismissSlingIntent, slingIntent]);
|
|
405
403
|
|
|
406
|
-
const scope = useMemo(
|
|
407
|
-
() => ({ settings: rpcSettings, cityName, rigName }),
|
|
408
|
-
[cityName, rigName, rpcSettings],
|
|
409
|
-
);
|
|
404
|
+
const scope = useMemo(() => ({ cityName, rigName }), [cityName, rigName]);
|
|
410
405
|
const queryRoot = useMemo(
|
|
411
406
|
() => cityQueryRoot(host.id, settings.endpointUrl, cityName, rigName),
|
|
412
407
|
[cityName, host.id, rigName, settings.endpointUrl],
|
|
@@ -433,8 +428,7 @@ export function CityOperations({
|
|
|
433
428
|
});
|
|
434
429
|
const eventsQuery = useQuery({
|
|
435
430
|
queryKey: [...queryRoot, "events", settings.eventLimit, eventCursor],
|
|
436
|
-
queryFn: () =>
|
|
437
|
-
loadEvents({ settings: rpcSettings, scope: "city", cityName, cursor: eventCursor }),
|
|
431
|
+
queryFn: () => loadEvents({ scope: "city", cityName, cursor: eventCursor }),
|
|
438
432
|
refetchInterval: settings.refreshIntervalMs,
|
|
439
433
|
});
|
|
440
434
|
const attentionQuery = useQuery({
|
|
@@ -507,7 +501,7 @@ export function CityOperations({
|
|
|
507
501
|
noConvoy: false,
|
|
508
502
|
merge: "direct",
|
|
509
503
|
} satisfies DispatchRequest;
|
|
510
|
-
return runDispatch({
|
|
504
|
+
return runDispatch({ request });
|
|
511
505
|
},
|
|
512
506
|
onSuccess: (result) => {
|
|
513
507
|
toast.show(`Dispatched ${result.beadId ?? "work"} to ${result.target}.`, {
|
|
@@ -554,7 +548,7 @@ export function CityOperations({
|
|
|
554
548
|
} else {
|
|
555
549
|
request = { ...base, action: sessionAction };
|
|
556
550
|
}
|
|
557
|
-
return runSessionAction({
|
|
551
|
+
return runSessionAction({ request });
|
|
558
552
|
},
|
|
559
553
|
onSuccess: (result) => {
|
|
560
554
|
toast.show(`${sessionAction} accepted for ${result.sessionId}.`, { variant: "success" });
|
package/client/factory-panel.tsx
CHANGED
|
@@ -12,7 +12,6 @@ import {
|
|
|
12
12
|
type GasCitySettings,
|
|
13
13
|
gasCitySettings,
|
|
14
14
|
resolveWorkspaceRig,
|
|
15
|
-
toGasCityRpcSettings,
|
|
16
15
|
type WorkspaceRigMapping,
|
|
17
16
|
} from "../shared";
|
|
18
17
|
import { CityOperations } from "./city-operations";
|
|
@@ -62,7 +61,6 @@ function ReadyFactoryPanel({
|
|
|
62
61
|
settings,
|
|
63
62
|
}: PluginWorkspacePanelProps & { settings: GasCitySettings }) {
|
|
64
63
|
const styles = useMemo(() => createStyles(theme, layout.compact), [layout.compact, theme]);
|
|
65
|
-
const rpcSettings = useMemo(() => toGasCityRpcSettings(settings), [settings]);
|
|
66
64
|
const workspace = useWorkspace(workspaceId, ({ directory, name, title }) => ({
|
|
67
65
|
directory,
|
|
68
66
|
name,
|
|
@@ -71,7 +69,7 @@ function ReadyFactoryPanel({
|
|
|
71
69
|
const loadMapping = useRpc(resolveWorkspaceRig);
|
|
72
70
|
const mapping = useQuery({
|
|
73
71
|
queryKey: ["gas-city", host.id, settings.endpointUrl, "workspace-mapping", workspaceId],
|
|
74
|
-
queryFn: () => loadMapping({
|
|
72
|
+
queryFn: () => loadMapping({ workspaceId }),
|
|
75
73
|
refetchInterval: settings.refreshIntervalMs,
|
|
76
74
|
});
|
|
77
75
|
const retryMapping = () => void mapping.refetch();
|
|
@@ -3,12 +3,7 @@ import { Icon, ScrollView } from "@getpaseo/plugin/client/react-native";
|
|
|
3
3
|
import { useQuery } from "@tanstack/react-query";
|
|
4
4
|
import { useMemo, useState } from "react";
|
|
5
5
|
import { ActivityIndicator, Pressable, StyleSheet, Text, View } from "react-native";
|
|
6
|
-
import {
|
|
7
|
-
discoverSupervisor,
|
|
8
|
-
type GasCitySettings,
|
|
9
|
-
gasCitySettings,
|
|
10
|
-
toGasCityRpcSettings,
|
|
11
|
-
} from "../shared";
|
|
6
|
+
import { discoverSupervisor, type GasCitySettings, gasCitySettings } from "../shared";
|
|
12
7
|
import { CityOperations } from "./city-operations";
|
|
13
8
|
import { selectAvailableCity } from "./view-model";
|
|
14
9
|
|
|
@@ -49,11 +44,10 @@ function ReadyGasCitySurface({
|
|
|
49
44
|
settings,
|
|
50
45
|
}: PluginSurfaceProps & { settings: GasCitySettings }) {
|
|
51
46
|
const styles = useMemo(() => createStyles(theme, layout.compact), [layout.compact, theme]);
|
|
52
|
-
const rpcSettings = useMemo(() => toGasCityRpcSettings(settings), [settings]);
|
|
53
47
|
const loadDiscovery = useRpc(discoverSupervisor);
|
|
54
48
|
const discovery = useQuery({
|
|
55
49
|
queryKey: ["gas-city", host.id, settings.endpointUrl, "discovery"],
|
|
56
|
-
queryFn: () => loadDiscovery({
|
|
50
|
+
queryFn: () => loadDiscovery({}),
|
|
57
51
|
refetchInterval: settings.refreshIntervalMs,
|
|
58
52
|
});
|
|
59
53
|
const retryDiscovery = () => void discovery.refetch();
|
package/index.server.ts
CHANGED
|
@@ -1,19 +1,9 @@
|
|
|
1
|
-
import type { PluginServerContext } from "@getpaseo/plugin/server";
|
|
2
|
-
import {
|
|
3
|
-
handleDiscoverSupervisor,
|
|
4
|
-
handleDispatchWork,
|
|
5
|
-
handleGetCityRigSnapshot,
|
|
6
|
-
handleListAttention,
|
|
7
|
-
handleListConvoys,
|
|
8
|
-
handleListEvents,
|
|
9
|
-
handleListSessions,
|
|
10
|
-
handleListWork,
|
|
11
|
-
handlePerformSessionAction,
|
|
12
|
-
handleResolveWorkspaceRig,
|
|
13
|
-
} from "./server/handlers";
|
|
1
|
+
import type { PluginServerContext, PluginSettings } from "@getpaseo/plugin/server";
|
|
2
|
+
import { createGasCityHandlers } from "./server/handlers";
|
|
14
3
|
import {
|
|
15
4
|
discoverSupervisor,
|
|
16
5
|
dispatchWork,
|
|
6
|
+
GasCitySettingsSchema,
|
|
17
7
|
gasCitySettings,
|
|
18
8
|
getCityRigSnapshot,
|
|
19
9
|
listAttention,
|
|
@@ -25,18 +15,39 @@ import {
|
|
|
25
15
|
resolveWorkspaceRig,
|
|
26
16
|
} from "./shared";
|
|
27
17
|
|
|
18
|
+
type GasCitySettingsHandle = PluginSettings<typeof gasCitySettings.schema>;
|
|
19
|
+
|
|
20
|
+
const paseo08DefaultSettings = GasCitySettingsSchema.parse({});
|
|
21
|
+
const paseo08SettingsHandle: GasCitySettingsHandle = {
|
|
22
|
+
read: async () => ({
|
|
23
|
+
status: "ready",
|
|
24
|
+
revision: "paseo-0.8-schema-defaults",
|
|
25
|
+
values: paseo08DefaultSettings,
|
|
26
|
+
}),
|
|
27
|
+
subscribe: () => () => {},
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export function resolveRegisteredGasCitySettings(
|
|
31
|
+
registered: GasCitySettingsHandle | undefined,
|
|
32
|
+
): GasCitySettingsHandle {
|
|
33
|
+
// Paseo 0.8 registers the persisted settings RPCs but returns no server read handle.
|
|
34
|
+
// Its only authoritative option is the schema-default, fail-closed policy.
|
|
35
|
+
return registered ?? paseo08SettingsHandle;
|
|
36
|
+
}
|
|
37
|
+
|
|
28
38
|
export default function contribute(server: PluginServerContext) {
|
|
29
|
-
server.registerSettings(gasCitySettings);
|
|
30
|
-
|
|
31
|
-
server.handle(
|
|
32
|
-
server.handle(
|
|
33
|
-
server.handle(
|
|
34
|
-
server.handle(
|
|
35
|
-
server.handle(
|
|
36
|
-
server.handle(
|
|
37
|
-
server.handle(
|
|
38
|
-
server.handle(
|
|
39
|
-
server.handle(
|
|
39
|
+
const settings = resolveRegisteredGasCitySettings(server.registerSettings(gasCitySettings));
|
|
40
|
+
const handlers = createGasCityHandlers(settings);
|
|
41
|
+
server.handle(discoverSupervisor, handlers.discoverSupervisor);
|
|
42
|
+
server.handle(resolveWorkspaceRig, handlers.resolveWorkspaceRig);
|
|
43
|
+
server.handle(getCityRigSnapshot, handlers.getCityRigSnapshot);
|
|
44
|
+
server.handle(listSessions, handlers.listSessions);
|
|
45
|
+
server.handle(listConvoys, handlers.listConvoys);
|
|
46
|
+
server.handle(listWork, handlers.listWork);
|
|
47
|
+
server.handle(listEvents, handlers.listEvents);
|
|
48
|
+
server.handle(listAttention, handlers.listAttention);
|
|
49
|
+
server.handle(dispatchWork, handlers.dispatchWork);
|
|
50
|
+
server.handle(performSessionAction, handlers.performSessionAction);
|
|
40
51
|
|
|
41
52
|
return () => {};
|
|
42
53
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@omercnet/paseo-gas-city",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0-next.92.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A Paseo control plane for observing and operating Gas City supervisors.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -17,9 +17,9 @@
|
|
|
17
17
|
"publishConfig": {
|
|
18
18
|
"access": "public"
|
|
19
19
|
},
|
|
20
|
-
"packageManager": "
|
|
20
|
+
"packageManager": "npm@11.19.1",
|
|
21
21
|
"engines": {
|
|
22
|
-
"
|
|
22
|
+
"node": ">=24"
|
|
23
23
|
},
|
|
24
24
|
"keywords": [
|
|
25
25
|
"paseo",
|
|
@@ -33,7 +33,6 @@
|
|
|
33
33
|
"coding-agents"
|
|
34
34
|
],
|
|
35
35
|
"files": [
|
|
36
|
-
"bun.lock",
|
|
37
36
|
"CHANGELOG.md",
|
|
38
37
|
"icon.svg",
|
|
39
38
|
"LICENSE",
|
|
@@ -49,25 +48,27 @@
|
|
|
49
48
|
"scripts": {
|
|
50
49
|
"check": "biome check .",
|
|
51
50
|
"check:write": "biome check --write .",
|
|
52
|
-
"test": "
|
|
53
|
-
"test:coverage": "
|
|
51
|
+
"test": "vitest run",
|
|
52
|
+
"test:coverage": "vitest run --coverage --coverage.reporter=text --coverage.reporter=lcov --coverage.thresholds.lines=90 --coverage.thresholds.functions=85 --coverage.exclude=index.client.tsx --coverage.exclude=index.server.ts",
|
|
54
53
|
"typecheck": "tsc --noEmit -p tsconfig.client.json && tsc --noEmit -p tsconfig.server.json && tsc --noEmit -p tsconfig.scripts.json",
|
|
55
|
-
"package:release": "
|
|
56
|
-
"verify:package": "
|
|
54
|
+
"package:release": "node scripts/package-release.ts",
|
|
55
|
+
"verify:package": "node scripts/verify-package.ts"
|
|
57
56
|
},
|
|
58
57
|
"devDependencies": {
|
|
59
58
|
"@biomejs/biome": "^2.5.10",
|
|
60
|
-
"@getpaseo/cli": "0.
|
|
61
|
-
"@getpaseo/client": "0.
|
|
62
|
-
"@getpaseo/plugin": "0.
|
|
63
|
-
"@getpaseo/protocol": "0.
|
|
59
|
+
"@getpaseo/cli": "0.9.0-beta.1",
|
|
60
|
+
"@getpaseo/client": "0.9.0-beta.1",
|
|
61
|
+
"@getpaseo/plugin": "0.9.0-beta.1",
|
|
62
|
+
"@getpaseo/protocol": "0.9.0-beta.1",
|
|
64
63
|
"@tanstack/react-query": "^5.102.3",
|
|
65
|
-
"@types/
|
|
64
|
+
"@types/node": "^24.5.2",
|
|
66
65
|
"@types/react": "~19.2.0",
|
|
66
|
+
"@vitest/coverage-v8": "^5.0.0",
|
|
67
67
|
"fflate": "^0.8.3",
|
|
68
68
|
"react": "19.1.0",
|
|
69
69
|
"react-native": "0.81.5",
|
|
70
|
-
"typescript": "^
|
|
70
|
+
"typescript": "^7.0.0",
|
|
71
|
+
"vitest": "^5.0.0",
|
|
71
72
|
"zod": "^4.4.3"
|
|
72
73
|
}
|
|
73
74
|
}
|
package/paseo-plugin.json
CHANGED
package/server/handlers.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { RpcInput, RpcOutput } from "@getpaseo/plugin";
|
|
2
|
-
import type { PluginHandlerContext } from "@getpaseo/plugin/server";
|
|
2
|
+
import type { PluginHandlerContext, PluginSettings } from "@getpaseo/plugin/server";
|
|
3
3
|
import {
|
|
4
4
|
AttentionListSchema,
|
|
5
5
|
CityRigSnapshotSchema,
|
|
@@ -10,8 +10,8 @@ import {
|
|
|
10
10
|
EventListSchema,
|
|
11
11
|
GAS_CITY_LIMITS,
|
|
12
12
|
type GasCityDiagnostic,
|
|
13
|
-
type
|
|
14
|
-
|
|
13
|
+
type GasCitySettings,
|
|
14
|
+
type gasCitySettings,
|
|
15
15
|
type getCityRigSnapshot,
|
|
16
16
|
type listAttention,
|
|
17
17
|
type listConvoys,
|
|
@@ -39,10 +39,12 @@ import {
|
|
|
39
39
|
import { mapWorkspaceToRig } from "./workspace-mapping";
|
|
40
40
|
|
|
41
41
|
export interface GasCityHandlerDependencies {
|
|
42
|
-
createClient?: (settings:
|
|
42
|
+
createClient?: (settings: GasCitySettings) => GasCityClient;
|
|
43
43
|
now?: () => Date;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
type GasCitySettingsHandle = PluginSettings<typeof gasCitySettings.schema>;
|
|
47
|
+
|
|
46
48
|
export interface GasCityHandlers {
|
|
47
49
|
discoverSupervisor(
|
|
48
50
|
input: RpcInput<typeof discoverSupervisor>,
|
|
@@ -317,7 +319,7 @@ function parseEventItems(items: readonly unknown[] | null, fallbackCity: string
|
|
|
317
319
|
return { items: parsed, dropped };
|
|
318
320
|
}
|
|
319
321
|
|
|
320
|
-
function requireMutations(settings:
|
|
322
|
+
function requireMutations(settings: GasCitySettings, confirmed: boolean) {
|
|
321
323
|
if (!settings.mutationsEnabled) {
|
|
322
324
|
throw new Error("Gas City mutations are disabled by the interactive safety interlock.");
|
|
323
325
|
}
|
|
@@ -333,6 +335,7 @@ async function workspacePath(
|
|
|
333
335
|
}
|
|
334
336
|
|
|
335
337
|
export function createGasCityHandlers(
|
|
338
|
+
settingsHandle: GasCitySettingsHandle,
|
|
336
339
|
dependencies: GasCityHandlerDependencies = {},
|
|
337
340
|
): GasCityHandlers {
|
|
338
341
|
const createClient =
|
|
@@ -344,15 +347,17 @@ export function createGasCityHandlers(
|
|
|
344
347
|
}));
|
|
345
348
|
const now = dependencies.now ?? (() => new Date());
|
|
346
349
|
|
|
347
|
-
const resources = (
|
|
348
|
-
const
|
|
350
|
+
const resources = async () => {
|
|
351
|
+
const state = await settingsHandle.read();
|
|
352
|
+
if (state.status !== "ready") throw new Error(`Gas City settings are invalid: ${state.error}`);
|
|
353
|
+
const settings = state.values;
|
|
349
354
|
return { settings, client: createClient(settings) };
|
|
350
355
|
};
|
|
351
356
|
|
|
352
357
|
return {
|
|
353
|
-
async discoverSupervisor(
|
|
358
|
+
async discoverSupervisor(_input) {
|
|
354
359
|
try {
|
|
355
|
-
const { client } = resources(
|
|
360
|
+
const { client } = await resources();
|
|
356
361
|
const [health, cities] = await Promise.all([client.health(), client.cities()]);
|
|
357
362
|
return SupervisorDiscoverySchema.parse({
|
|
358
363
|
state: "available",
|
|
@@ -374,7 +379,7 @@ export function createGasCityHandlers(
|
|
|
374
379
|
},
|
|
375
380
|
|
|
376
381
|
async resolveWorkspaceRig(input, context) {
|
|
377
|
-
const { settings, client } = resources(
|
|
382
|
+
const { settings, client } = await resources();
|
|
378
383
|
try {
|
|
379
384
|
const [path, cityResponse] = await Promise.all([
|
|
380
385
|
workspacePath(input.workspaceId, context),
|
|
@@ -421,7 +426,7 @@ export function createGasCityHandlers(
|
|
|
421
426
|
}
|
|
422
427
|
},
|
|
423
428
|
async getCityRigSnapshot(input, _context) {
|
|
424
|
-
const { client } = resources(
|
|
429
|
+
const { client } = await resources();
|
|
425
430
|
try {
|
|
426
431
|
const [cities, status, rigs] = await Promise.all([
|
|
427
432
|
client.cities(),
|
|
@@ -480,7 +485,7 @@ export function createGasCityHandlers(
|
|
|
480
485
|
},
|
|
481
486
|
|
|
482
487
|
async listSessions(input) {
|
|
483
|
-
const { client } = resources(
|
|
488
|
+
const { client } = await resources();
|
|
484
489
|
try {
|
|
485
490
|
const response = await client.sessions(input.cityName);
|
|
486
491
|
const items = (response.items ?? [])
|
|
@@ -498,7 +503,7 @@ export function createGasCityHandlers(
|
|
|
498
503
|
},
|
|
499
504
|
|
|
500
505
|
async listConvoys(input) {
|
|
501
|
-
const { client } = resources(
|
|
506
|
+
const { client } = await resources();
|
|
502
507
|
try {
|
|
503
508
|
const [response, rigs] = await Promise.all([
|
|
504
509
|
client.convoys(input.cityName),
|
|
@@ -523,7 +528,7 @@ export function createGasCityHandlers(
|
|
|
523
528
|
},
|
|
524
529
|
|
|
525
530
|
async listWork(input) {
|
|
526
|
-
const { settings, client } = resources(
|
|
531
|
+
const { settings, client } = await resources();
|
|
527
532
|
try {
|
|
528
533
|
const response = await client.work(input.cityName, input.rigName, settings.eventLimit);
|
|
529
534
|
return WorkListSchema.parse({
|
|
@@ -541,7 +546,7 @@ export function createGasCityHandlers(
|
|
|
541
546
|
},
|
|
542
547
|
|
|
543
548
|
async listEvents(input) {
|
|
544
|
-
const { settings, client } = resources(
|
|
549
|
+
const { settings, client } = await resources();
|
|
545
550
|
try {
|
|
546
551
|
if (input.scope === "supervisor") {
|
|
547
552
|
const response = await client.supervisorEvents(settings.eventLimit);
|
|
@@ -569,7 +574,7 @@ export function createGasCityHandlers(
|
|
|
569
574
|
},
|
|
570
575
|
|
|
571
576
|
async listAttention(input) {
|
|
572
|
-
const { client } = resources(
|
|
577
|
+
const { client } = await resources();
|
|
573
578
|
try {
|
|
574
579
|
const [status, sessions, convoys, pending, rigs] = await Promise.all([
|
|
575
580
|
client.cityStatus(input.cityName),
|
|
@@ -688,7 +693,7 @@ export function createGasCityHandlers(
|
|
|
688
693
|
},
|
|
689
694
|
|
|
690
695
|
async dispatchWork(input) {
|
|
691
|
-
const { settings, client } = resources(
|
|
696
|
+
const { settings, client } = await resources();
|
|
692
697
|
const request = input.request;
|
|
693
698
|
requireMutations(settings, request.confirmed);
|
|
694
699
|
const target = request.target;
|
|
@@ -738,7 +743,7 @@ export function createGasCityHandlers(
|
|
|
738
743
|
},
|
|
739
744
|
|
|
740
745
|
async performSessionAction(input) {
|
|
741
|
-
const { settings, client } = resources(
|
|
746
|
+
const { settings, client } = await resources();
|
|
742
747
|
const request = input.request;
|
|
743
748
|
requireMutations(settings, request.confirmed);
|
|
744
749
|
let action: string = request.action;
|
|
@@ -775,16 +780,3 @@ export function createGasCityHandlers(
|
|
|
775
780
|
},
|
|
776
781
|
};
|
|
777
782
|
}
|
|
778
|
-
|
|
779
|
-
const defaultHandlers = createGasCityHandlers();
|
|
780
|
-
|
|
781
|
-
export const handleDiscoverSupervisor = defaultHandlers.discoverSupervisor;
|
|
782
|
-
export const handleResolveWorkspaceRig = defaultHandlers.resolveWorkspaceRig;
|
|
783
|
-
export const handleGetCityRigSnapshot = defaultHandlers.getCityRigSnapshot;
|
|
784
|
-
export const handleListSessions = defaultHandlers.listSessions;
|
|
785
|
-
export const handleListConvoys = defaultHandlers.listConvoys;
|
|
786
|
-
export const handleListWork = defaultHandlers.listWork;
|
|
787
|
-
export const handleListEvents = defaultHandlers.listEvents;
|
|
788
|
-
export const handleListAttention = defaultHandlers.listAttention;
|
|
789
|
-
export const handleDispatchWork = defaultHandlers.dispatchWork;
|
|
790
|
-
export const handlePerformSessionAction = defaultHandlers.performSessionAction;
|
package/shared/rpc.ts
CHANGED
|
@@ -17,13 +17,10 @@ import {
|
|
|
17
17
|
WorkListSchema,
|
|
18
18
|
WorkspaceRigMappingSchema,
|
|
19
19
|
} from "./schemas";
|
|
20
|
-
import { GasCityRpcSettingsSchema } from "./settings";
|
|
21
20
|
|
|
22
|
-
const
|
|
23
|
-
const noInput = z.object(settingsInput).strict();
|
|
21
|
+
const noInput = z.object({}).strict();
|
|
24
22
|
const cityRigInput = z
|
|
25
23
|
.object({
|
|
26
|
-
...settingsInput,
|
|
27
24
|
cityName: nameSchema,
|
|
28
25
|
rigName: nameSchema.nullable(),
|
|
29
26
|
})
|
|
@@ -37,7 +34,7 @@ export const discoverSupervisor = defineRpc({
|
|
|
37
34
|
|
|
38
35
|
export const resolveWorkspaceRig = defineRpc({
|
|
39
36
|
name: "gas-city.resolve-workspace-rig",
|
|
40
|
-
input: z.object({
|
|
37
|
+
input: z.object({ workspaceId: identifierSchema }).strict(),
|
|
41
38
|
output: WorkspaceRigMappingSchema,
|
|
42
39
|
});
|
|
43
40
|
|
|
@@ -67,10 +64,9 @@ export const listWork = defineRpc({
|
|
|
67
64
|
export const listEvents = defineRpc({
|
|
68
65
|
name: "gas-city.list-events",
|
|
69
66
|
input: z.discriminatedUnion("scope", [
|
|
70
|
-
z.object({
|
|
67
|
+
z.object({ scope: z.literal("supervisor") }).strict(),
|
|
71
68
|
z
|
|
72
69
|
.object({
|
|
73
|
-
...settingsInput,
|
|
74
70
|
scope: z.literal("city"),
|
|
75
71
|
cityName: nameSchema,
|
|
76
72
|
cursor: z.string().max(GAS_CITY_LIMITS.cursor).nullable(),
|
|
@@ -88,12 +84,12 @@ export const listAttention = defineRpc({
|
|
|
88
84
|
|
|
89
85
|
export const dispatchWork = defineRpc({
|
|
90
86
|
name: "gas-city.dispatch-work",
|
|
91
|
-
input: z.object({
|
|
87
|
+
input: z.object({ request: DispatchRequestSchema }).strict(),
|
|
92
88
|
output: DispatchResultSchema,
|
|
93
89
|
});
|
|
94
90
|
|
|
95
91
|
export const performSessionAction = defineRpc({
|
|
96
92
|
name: "gas-city.perform-session-action",
|
|
97
|
-
input: z.object({
|
|
93
|
+
input: z.object({ request: SessionActionRequestSchema }).strict(),
|
|
98
94
|
output: SessionActionResultSchema,
|
|
99
95
|
});
|
package/shared/settings.ts
CHANGED
|
@@ -62,22 +62,6 @@ export const GasCitySettingsSchema = GasCitySettingsBaseSchema.superRefine(
|
|
|
62
62
|
rejectDuplicateWorkspaceMappings,
|
|
63
63
|
);
|
|
64
64
|
|
|
65
|
-
export const GasCityRpcSettingsSchema = GasCitySettingsBaseSchema.omit({
|
|
66
|
-
refreshIntervalMs: true,
|
|
67
|
-
}).superRefine(rejectDuplicateWorkspaceMappings);
|
|
68
|
-
|
|
69
|
-
export type GasCityRpcSettings = z.infer<typeof GasCityRpcSettingsSchema>;
|
|
70
|
-
|
|
71
|
-
export function toGasCityRpcSettings(settings: GasCitySettings): GasCityRpcSettings {
|
|
72
|
-
return GasCityRpcSettingsSchema.parse({
|
|
73
|
-
endpointUrl: settings.endpointUrl,
|
|
74
|
-
allowRemoteEndpoint: settings.allowRemoteEndpoint,
|
|
75
|
-
mutationsEnabled: settings.mutationsEnabled,
|
|
76
|
-
eventLimit: settings.eventLimit,
|
|
77
|
-
workspaceMappings: settings.workspaceMappings,
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
|
|
81
65
|
export type GasCitySettings = z.infer<typeof GasCitySettingsSchema>;
|
|
82
66
|
export type WorkspaceMappingOverride = z.infer<typeof WorkspaceMappingOverrideSchema>;
|
|
83
67
|
|