super-dsh 0.1.9 → 0.1.10-e
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 +25 -3
- package/agent-agy/cordis.patch.yml +7 -4
- package/agent-agy/dist/agent.d.ts +12 -11
- package/agent-agy/dist/agy-auth-gateway.d.ts +124 -0
- package/agent-agy/dist/agy-auth-gateway.js +233 -0
- package/agent-agy/dist/agy-auth.d.ts +153 -0
- package/agent-agy/dist/agy-auth.js +179 -0
- package/agent-agy/dist/agy-cli-client.d.ts +39 -9
- package/agent-agy/dist/agy-cli-client.js +82 -18
- package/agent-agy/dist/agy-store.d.ts +8 -0
- package/agent-agy/dist/index.d.ts +46 -16
- package/agent-agy/dist/index.js +82 -56
- package/agent-agy/dist/models.d.ts +70 -0
- package/agent-agy/dist/models.js +102 -3
- package/agent-agy/package.json +7 -5
- package/agent-agy-sdk/cordis.patch.yml +58 -0
- package/agent-agy-sdk/dist/adapter.d.ts +15 -0
- package/agent-agy-sdk/dist/adapter.js +42 -0
- package/agent-agy-sdk/dist/agent-preset-agy.d.ts +27 -0
- package/agent-agy-sdk/dist/agent-preset-agy.js +32 -0
- package/agent-agy-sdk/dist/agent.d.ts +138 -0
- package/agent-agy-sdk/dist/agent.js +494 -0
- package/{agent-agy → agent-agy-sdk}/dist/agy-client.d.ts +26 -6
- package/{agent-agy → agent-agy-sdk}/dist/agy-client.js +43 -25
- package/agent-agy-sdk/dist/agy-sessions.d.ts +25 -0
- package/agent-agy-sdk/dist/agy-sessions.js +107 -0
- package/agent-agy-sdk/dist/agy-store.d.ts +39 -0
- package/agent-agy-sdk/dist/agy-store.js +83 -0
- package/agent-agy-sdk/dist/inbox.d.ts +26 -0
- package/agent-agy-sdk/dist/inbox.js +53 -0
- package/agent-agy-sdk/dist/index.d.ts +93 -0
- package/agent-agy-sdk/dist/index.js +476 -0
- package/agent-agy-sdk/dist/models.d.ts +41 -0
- package/agent-agy-sdk/dist/models.js +74 -0
- package/agent-agy-sdk/dist/sdk-venv.d.ts +76 -0
- package/agent-agy-sdk/dist/sdk-venv.js +173 -0
- package/agent-agy-sdk/dist/world-plugin.d.ts +10 -0
- package/agent-agy-sdk/dist/world-plugin.js +82 -0
- package/agent-agy-sdk/package.json +64 -0
- package/agent-claude/dist/adapter.js +106 -31
- package/agent-claude/dist/agent.js +154 -17
- package/agent-claude/dist/claude-client.js +84 -43
- package/agent-claude/dist/claude-launch.js +101 -0
- package/agent-claude/dist/claude-native-config.js +169 -0
- package/agent-claude/dist/claude-provider-gateway.js +340 -0
- package/agent-claude/dist/claude-providers.js +391 -0
- package/agent-claude/dist/claude-route.js +152 -0
- package/agent-claude/dist/index.js +214 -37
- package/agent-claude/dist/models.js +14 -0
- package/agent-claude/dist/sdk-runtime.js +320 -0
- package/agent-claude/package.json +6 -4
- package/agent-codex/README.md +141 -36
- package/agent-codex/cordis.patch.yml +14 -10
- package/agent-codex/dist/adapter.js +64 -28
- package/agent-codex/dist/agent.js +255 -81
- package/agent-codex/dist/app-server-approvals.js +165 -0
- package/agent-codex/dist/app-server-client.js +723 -0
- package/agent-codex/dist/app-server-events.js +432 -0
- package/agent-codex/dist/app-server-protocol.js +95 -0
- package/agent-codex/dist/app-server-wire.js +299 -0
- package/agent-codex/dist/codex-launch.js +78 -0
- package/agent-codex/dist/codex-native-config.js +392 -0
- package/agent-codex/dist/codex-provider-gateway.js +402 -0
- package/agent-codex/dist/codex-providers.js +376 -0
- package/agent-codex/dist/codex-route.js +86 -0
- package/agent-codex/dist/index.js +256 -115
- package/agent-codex/dist/permission.js +75 -1
- package/agent-codex/package.json +1 -2
- package/agent-codex-sdk/README.md +79 -0
- package/agent-codex-sdk/cordis.patch.yml +81 -0
- package/agent-codex-sdk/dist/adapter.js +91 -0
- package/agent-codex-sdk/dist/agent-preset-codex.js +32 -0
- package/agent-codex-sdk/dist/agent.js +1085 -0
- package/agent-codex-sdk/dist/codex-native-config.js +392 -0
- package/agent-codex-sdk/dist/codex-provider-gateway.js +402 -0
- package/agent-codex-sdk/dist/codex-providers.js +376 -0
- package/agent-codex-sdk/dist/codex-route.js +86 -0
- package/{agent-codex/dist/codex-client.js → agent-codex-sdk/dist/codex-sdk-client.js} +253 -32
- package/agent-codex-sdk/dist/codex-sdk-launch.js +92 -0
- package/agent-codex-sdk/dist/codex-store.js +180 -0
- package/agent-codex-sdk/dist/inbox.js +53 -0
- package/agent-codex-sdk/dist/index.js +739 -0
- package/agent-codex-sdk/dist/permission.js +71 -0
- package/agent-codex-sdk/dist/sdk-runtime.js +307 -0
- package/agent-codex-sdk/dist/session-map.js +167 -0
- package/agent-codex-sdk/dist/world-plugin.js +93 -0
- package/agent-codex-sdk/package.json +79 -0
- package/agent-codex-sdk/scripts/fetch-sdk-runtime.mjs +57 -0
- package/agent-omp/README.md +72 -55
- package/agent-omp/dist/agent.js +36 -11
- package/agent-omp/dist/index.js +92 -52
- package/agent-omp/dist/lazy-rpc.js +11 -4
- package/agent-omp/dist/omp-cli.js +114 -97
- package/agent-omp/dist/omp-store.js +12 -4
- package/agent-omp/dist/permission.js +70 -5
- package/agent-omp/dist/rpc-client.js +409 -0
- package/agent-omp/dist/world-plugin.js +36 -3
- package/agent-omp/package.json +2 -6
- package/agent-omp-sdk/README.md +103 -0
- package/agent-omp-sdk/cordis.patch.yml +108 -0
- package/agent-omp-sdk/dist/adapter.d.ts +21 -0
- package/agent-omp-sdk/dist/adapter.js +36 -0
- package/agent-omp-sdk/dist/agent-preset-omp.d.ts +31 -0
- package/agent-omp-sdk/dist/agent-preset-omp.js +32 -0
- package/agent-omp-sdk/dist/agent.d.ts +64 -0
- package/agent-omp-sdk/dist/agent.js +1178 -0
- package/agent-omp-sdk/dist/discovery.d.ts +57 -0
- package/agent-omp-sdk/dist/discovery.js +116 -0
- package/agent-omp-sdk/dist/inbox.d.ts +28 -0
- package/agent-omp-sdk/dist/inbox.js +53 -0
- package/agent-omp-sdk/dist/index.d.ts +60 -0
- package/agent-omp-sdk/dist/index.js +632 -0
- package/agent-omp-sdk/dist/knobs.d.ts +34 -0
- package/agent-omp-sdk/dist/knobs.js +50 -0
- package/agent-omp-sdk/dist/lazy-rpc.d.ts +98 -0
- package/agent-omp-sdk/dist/lazy-rpc.js +178 -0
- package/agent-omp-sdk/dist/mobile/zoom-guard.d.ts +187 -0
- package/agent-omp-sdk/dist/mobile/zoom-guard.js +294 -0
- package/agent-omp-sdk/dist/mobile-boot.d.ts +49 -0
- package/agent-omp-sdk/dist/mobile-boot.js +38 -0
- package/agent-omp-sdk/dist/models.d.ts +39 -0
- package/agent-omp-sdk/dist/models.js +299 -0
- package/agent-omp-sdk/dist/omp-cli.d.ts +67 -0
- package/agent-omp-sdk/dist/omp-cli.js +164 -0
- package/agent-omp-sdk/dist/omp-disk-discovery.d.ts +27 -0
- package/agent-omp-sdk/dist/omp-disk-discovery.js +178 -0
- package/agent-omp-sdk/dist/omp-executable.d.ts +2 -0
- package/agent-omp-sdk/dist/omp-executable.js +30 -0
- package/agent-omp-sdk/dist/omp-store.d.ts +134 -0
- package/agent-omp-sdk/dist/omp-store.js +526 -0
- package/agent-omp-sdk/dist/pairing.d.ts +7 -0
- package/agent-omp-sdk/dist/pairing.js +45 -0
- package/agent-omp-sdk/dist/permission.d.ts +138 -0
- package/agent-omp-sdk/dist/permission.js +161 -0
- package/agent-omp-sdk/dist/protocol.d.ts +189 -0
- package/agent-omp-sdk/dist/rpc-types.d.ts +77 -0
- package/agent-omp-sdk/dist/rpc-types.js +1 -0
- package/agent-omp-sdk/dist/sdk-client.d.ts +160 -0
- package/{agent-omp → agent-omp-sdk}/dist/sdk-client.js +108 -56
- package/agent-omp-sdk/dist/sdk-runtime.d.ts +211 -0
- package/agent-omp-sdk/dist/sdk-runtime.js +418 -0
- package/agent-omp-sdk/dist/sidecar-client.d.ts +87 -0
- package/agent-omp-sdk/dist/sidecar-client.js +197 -0
- package/agent-omp-sdk/dist/store/adapter.d.ts +17 -0
- package/agent-omp-sdk/dist/store/adapter.js +47 -0
- package/agent-omp-sdk/dist/store/db.d.ts +70 -0
- package/agent-omp-sdk/dist/store/db.js +210 -0
- package/agent-omp-sdk/dist/store/index.d.ts +23 -0
- package/agent-omp-sdk/dist/store/index.js +59 -0
- package/agent-omp-sdk/dist/store/reconcile.d.ts +15 -0
- package/agent-omp-sdk/dist/store/reconcile.js +51 -0
- package/agent-omp-sdk/dist/store/schema.d.ts +8 -0
- package/agent-omp-sdk/dist/store/schema.js +40 -0
- package/agent-omp-sdk/dist/transport.d.ts +49 -0
- package/agent-omp-sdk/dist/transport.js +35 -0
- package/agent-omp-sdk/dist/world-home.d.ts +4 -0
- package/agent-omp-sdk/dist/world-home.js +23 -0
- package/agent-omp-sdk/dist/world-plugin.d.ts +10 -0
- package/agent-omp-sdk/dist/world-plugin.js +137 -0
- package/agent-omp-sdk/package.json +87 -0
- package/client/index.js +1204 -93
- package/cordis.patch.yml +64 -0
- package/package.json +17 -8
- package/superd-hub/dist/client/agent-settings.d.ts +210 -0
- package/superd-hub/dist/client/agent-settings.js +300 -0
- package/superd-hub/dist/client/roster.js +6 -0
- package/superd-hub/dist/client/runtime-settings-api.d.ts +76 -0
- package/superd-hub/dist/client/runtime-settings-api.js +137 -0
- package/superd-hub/dist/client/switch.d.ts +165 -0
- package/superd-hub/dist/client/switch.js +295 -0
- package/superd-hub/lib/client/index.js +1204 -93
- package/agent-codex/dist/models.js +0 -152
- package/agent-omp/dist/sidecar-client.js +0 -195
- /package/{agent-agy → agent-agy-sdk}/bridge/agy_bridge.py +0 -0
- /package/{agent-agy → agent-agy-sdk}/bridge/gemini_openai_server.mjs +0 -0
- /package/{agent-codex/dist/codex-events.js → agent-codex-sdk/dist/codex-sdk-events.js} +0 -0
- /package/{agent-omp → agent-omp-sdk}/dist/protocol.js +0 -0
- /package/{agent-omp → agent-omp-sdk}/sidecar/main.ts +0 -0
package/cordis.patch.yml
CHANGED
|
@@ -71,6 +71,70 @@
|
|
|
71
71
|
name: 'super-dsh/agents/hermes'
|
|
72
72
|
- id: agent-agy
|
|
73
73
|
name: 'super-dsh/agents/agy'
|
|
74
|
+
# Opt-IN SDK half of the Antigravity split (2026-10-02 user ruling). The
|
|
75
|
+
# CLI row above is the PRIMARY path: the user already runs Antigravity, so
|
|
76
|
+
# the CLI reuses that environment (their ~/.gemini, ADC and keyring) for
|
|
77
|
+
# free, while this row drives the Python `google-antigravity` SDK instead.
|
|
78
|
+
#
|
|
79
|
+
# DISABLED BY DEFAULT — turning the row on IS the switch
|
|
80
|
+
# (`plugin-presence IS the roster`): no env var, no config key. It runs as
|
|
81
|
+
# world key `agy-sdk` (roster label "Antigravity (SDK)", world home
|
|
82
|
+
# `agents/agy-sdk`), deliberately distinct from `agy` because the hub's
|
|
83
|
+
# registerAgent hard-throws on a duplicate key and this row ships beside
|
|
84
|
+
# the CLI row — the two can therefore both be enabled harmlessly.
|
|
85
|
+
#
|
|
86
|
+
# No Python is installed at `dsh plugin add` time and this package declares
|
|
87
|
+
# no SDK dependency: the durable venv is fetched into that world home on
|
|
88
|
+
# first real use (agent-agy-sdk/src/sdk-venv.ts).
|
|
89
|
+
- id: agent-agy-sdk
|
|
90
|
+
name: 'super-dsh/agents/agy-sdk'
|
|
91
|
+
disabled: true
|
|
92
|
+
# Opt-IN SDK transport for OMP (2026-10-03 user ruling). `agent-omp` is the
|
|
93
|
+
# PRIMARY path: it drives the operator's own `omp` binary, so the plugin
|
|
94
|
+
# ships no runtime at all. This row drives the SAME agent through the
|
|
95
|
+
# package's in-process SDK face instead — one bun sidecar hosting every
|
|
96
|
+
# session (shared authStorage/modelRegistry), which is the cheaper memory
|
|
97
|
+
# shape for many concurrent sessions, at the cost of fetching a ~900 MB
|
|
98
|
+
# runtime tree.
|
|
99
|
+
#
|
|
100
|
+
# DISABLED BY DEFAULT — turning the row on IS the switch
|
|
101
|
+
# (`plugin-presence IS the roster`): no env var, no config key. It runs as
|
|
102
|
+
# world key `omp-sdk` (roster label "OMP (SDK)", world home
|
|
103
|
+
# `agents/omp-sdk`), deliberately distinct from `omp` because the hub's
|
|
104
|
+
# registerAgent hard-throws on a duplicate key and this row ships beside
|
|
105
|
+
# the RPC row — the two can therefore both be enabled harmlessly.
|
|
106
|
+
#
|
|
107
|
+
# Nothing is installed at `dsh plugin add` time and this package declares no
|
|
108
|
+
# dependency: the durable bun runtime + `@oh-my-pi/pi-coding-agent` tree is
|
|
109
|
+
# fetched into that world home on first real use
|
|
110
|
+
# (agent-omp-sdk/src/sdk-runtime.ts).
|
|
111
|
+
- id: agent-omp-sdk
|
|
112
|
+
name: 'super-dsh/agents/omp-sdk'
|
|
113
|
+
disabled: true
|
|
114
|
+
# PRESERVED SDK line for Codex (2026-10-04 user ruling). `agent-codex` is the
|
|
115
|
+
# PRIMARY path — it drives a `codex app-server` child process, so the plugin
|
|
116
|
+
# bundles no SDK: the CLI the operator already has is the runtime. This row
|
|
117
|
+
# drives the SAME agent through the older in-process `@openai/codex-sdk` face
|
|
118
|
+
# instead, kept because the code was already written and it is a real option
|
|
119
|
+
# (no child process per session, and it works with no `codex` binary on PATH
|
|
120
|
+
# once its runtime is fetched).
|
|
121
|
+
#
|
|
122
|
+
# DISABLED BY DEFAULT — turning the row on IS the switch (`plugin-presence IS
|
|
123
|
+
# the roster`): no env var, no config key. It runs as world key `codex-sdk`
|
|
124
|
+
# (roster label "Codex (SDK)", world home `agents/codex-sdk`), deliberately
|
|
125
|
+
# distinct from `codex` because the hub's registerAgent hard-throws on a
|
|
126
|
+
# duplicate key and this row ships beside the app-server row — the two can
|
|
127
|
+
# therefore both be enabled harmlessly.
|
|
128
|
+
#
|
|
129
|
+
# Nothing is installed at `dsh plugin add` time and this package declares NO
|
|
130
|
+
# dependency — not a dependency, not an optionalDependency, not a peer: the
|
|
131
|
+
# SDK tree (`@openai/codex-sdk` + the codex binary package, pinned together)
|
|
132
|
+
# is fetched into that world home on the first real prompt and is durable
|
|
133
|
+
# there (agent-codex-sdk/src/sdk-runtime.ts; pre-warm with
|
|
134
|
+
# `npm run fetch-sdk-runtime`). Zero-spawn, zero-download window before it.
|
|
135
|
+
- id: agent-codex-sdk
|
|
136
|
+
name: 'super-dsh/agents/codex-sdk'
|
|
137
|
+
disabled: true
|
|
74
138
|
# R2 (2026-09-16): the claude adapter ships STANDALONE only — its /world
|
|
75
139
|
# entry is inert. The HUB side joins it: one generic joiner row with the
|
|
76
140
|
# key; spawn/roster/mount wiring lives in super-dsh/join.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "super-dsh",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Super D for the DeepSeek Harness (DSH)
|
|
3
|
+
"version": "0.1.10-e",
|
|
4
|
+
"description": "Super D for the DeepSeek Harness (DSH) \u2014 one dsh plugin that mounts the superd hub (runtime selector, roster, per-runtime agents) and joins local foreign-agent runtimes (OMP, Codex, Claude, Pi, Hermes, Antigravity) into the DSH Web UI. Each runtime keeps its native home and session store; the hub only bridges.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
@@ -18,6 +18,9 @@
|
|
|
18
18
|
"./agents/pi": "./agent-pi/dist/world-plugin.js",
|
|
19
19
|
"./agents/hermes": "./agent-hermes/dist/world-plugin.js",
|
|
20
20
|
"./agents/agy": "./agent-agy/dist/world-plugin.js",
|
|
21
|
+
"./agents/agy-sdk": "./agent-agy-sdk/dist/world-plugin.js",
|
|
22
|
+
"./agents/omp-sdk": "./agent-omp-sdk/dist/world-plugin.js",
|
|
23
|
+
"./agents/codex-sdk": "./agent-codex-sdk/dist/world-plugin.js",
|
|
21
24
|
"./client": "./client/index.js",
|
|
22
25
|
"./cordis.patch.yml": "./cordis.patch.yml",
|
|
23
26
|
"./package.json": "./package.json",
|
|
@@ -36,10 +39,17 @@
|
|
|
36
39
|
"agent-omp/dist",
|
|
37
40
|
"agent-omp/package.json",
|
|
38
41
|
"agent-omp/cordis.patch.yml",
|
|
39
|
-
"agent-omp/
|
|
42
|
+
"agent-omp-sdk/dist",
|
|
43
|
+
"agent-omp-sdk/sidecar",
|
|
44
|
+
"agent-omp-sdk/package.json",
|
|
45
|
+
"agent-omp-sdk/cordis.patch.yml",
|
|
40
46
|
"agent-codex/dist",
|
|
41
47
|
"agent-codex/package.json",
|
|
42
48
|
"agent-codex/cordis.patch.yml",
|
|
49
|
+
"agent-codex-sdk/dist",
|
|
50
|
+
"agent-codex-sdk/scripts",
|
|
51
|
+
"agent-codex-sdk/package.json",
|
|
52
|
+
"agent-codex-sdk/cordis.patch.yml",
|
|
43
53
|
"agent-claude/dist",
|
|
44
54
|
"agent-claude/package.json",
|
|
45
55
|
"agent-claude/cordis.patch.yml",
|
|
@@ -52,7 +62,10 @@
|
|
|
52
62
|
"agent-agy/dist",
|
|
53
63
|
"agent-agy/package.json",
|
|
54
64
|
"agent-agy/cordis.patch.yml",
|
|
55
|
-
"agent-agy/
|
|
65
|
+
"agent-agy-sdk/dist",
|
|
66
|
+
"agent-agy-sdk/package.json",
|
|
67
|
+
"agent-agy-sdk/cordis.patch.yml",
|
|
68
|
+
"agent-agy-sdk/bridge"
|
|
56
69
|
],
|
|
57
70
|
"dsh": {
|
|
58
71
|
"bundle": {
|
|
@@ -66,12 +79,8 @@
|
|
|
66
79
|
}
|
|
67
80
|
},
|
|
68
81
|
"dependencies": {
|
|
69
|
-
"@anthropic-ai/claude-agent-sdk": "0.3.263",
|
|
70
82
|
"@earendil-works/pi-coding-agent": "0.84.2",
|
|
71
|
-
"@oh-my-pi/pi-coding-agent": "^18.1.14",
|
|
72
83
|
"@openai/codex": "0.154.0",
|
|
73
|
-
"@openai/codex-sdk": "0.154.0",
|
|
74
|
-
"bun": "^1.4.2",
|
|
75
84
|
"ws": "^8.21.0",
|
|
76
85
|
"zod": "4.4.3",
|
|
77
86
|
"@modelcontextprotocol/sdk": "^1.29.0"
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime settings panels for the Hub's Agent Runtimes rows (P3, 2026-10-02
|
|
3
|
+
* user ruling).
|
|
4
|
+
*
|
|
5
|
+
* Interaction contract the UI follows (ruling, verbatim intent):
|
|
6
|
+
* - clicking the ROW BODY expands that runtime's OWN settings inline
|
|
7
|
+
* (accordion: at most one row open at a time);
|
|
8
|
+
* - the row's existing right-hand `switch` affordance is the ONLY switch —
|
|
9
|
+
* the panel never carries a second one.
|
|
10
|
+
*
|
|
11
|
+
* Config belongs to the adapter (agent-adapter-dev-rules §12), so this module
|
|
12
|
+
* owns only the presentation-side logic: which runtimes have a panel, the
|
|
13
|
+
* accordion transition, and a defensive parse of whatever the adapter's
|
|
14
|
+
* `*Auth/get` RPC returns. The adapter decides which auth methods exist, which
|
|
15
|
+
* are available on this machine, and which one is in force.
|
|
16
|
+
*
|
|
17
|
+
* Node-safe by construction (no DOM, no React, no fetch) — the host tsconfig
|
|
18
|
+
* dual-emits this file to `dist/client/agent-settings.js` so
|
|
19
|
+
* test/client-agent-settings.test.mjs can pin the parse and accordion rules
|
|
20
|
+
* under `node --test` (the roster.ts / mesh-api.ts precedent).
|
|
21
|
+
*
|
|
22
|
+
* @module superd-hub/client/agent-settings
|
|
23
|
+
*/
|
|
24
|
+
/** One selectable auth method as the adapter describes it. */
|
|
25
|
+
export interface AuthMethodOption {
|
|
26
|
+
/** Stable id the RPC round-trips (`apiKey` | `oauth` | `adc`). */
|
|
27
|
+
readonly key: string;
|
|
28
|
+
/** Human label rendered on the option. */
|
|
29
|
+
readonly label: string;
|
|
30
|
+
/** Detected on THIS machine. Drives the availability annotation. */
|
|
31
|
+
readonly available: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Rendered but not selectable this round (the OAuth placeholder): the UI
|
|
34
|
+
* shows the shape and says why it is inert, instead of hiding it.
|
|
35
|
+
*/
|
|
36
|
+
readonly placeholder: boolean;
|
|
37
|
+
/** One short line explaining the option (or why it is inert). */
|
|
38
|
+
readonly hint: string;
|
|
39
|
+
}
|
|
40
|
+
/** The adapter's answer to `<runtime>Auth/get`. */
|
|
41
|
+
export interface RuntimeAuthView {
|
|
42
|
+
readonly methods: readonly AuthMethodOption[];
|
|
43
|
+
/** The user's explicit persisted choice; `null` when they have not made one. */
|
|
44
|
+
readonly selected: string | null;
|
|
45
|
+
/** What a new session would ACTUALLY use right now (ladder fallback applied). */
|
|
46
|
+
readonly effective: string | null;
|
|
47
|
+
/** Native file the adapter maintains for this runtime, when it owns one. */
|
|
48
|
+
readonly settingsPath?: string;
|
|
49
|
+
/** Free-form note from the adapter (e.g. why a mode is unavailable). */
|
|
50
|
+
readonly note?: string;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* A runtime's settings panel: which adapter Remote answers for it.
|
|
54
|
+
*
|
|
55
|
+
* The namespace is the adapter's own service key — the hub forwards
|
|
56
|
+
* `envelope.method` verbatim, so the client needs only the name. A runtime absent
|
|
57
|
+
* from this table has no panel yet: its row still expands, to an explicit empty
|
|
58
|
+
* state rather than a dead control (the interaction stays uniform, and a runtime
|
|
59
|
+
* with nothing to configure SAYS so).
|
|
60
|
+
*/
|
|
61
|
+
export interface SettingsPanelSpec {
|
|
62
|
+
/** The adapter's Remote namespace (`agyAuth`). */
|
|
63
|
+
readonly namespace: string;
|
|
64
|
+
/**
|
|
65
|
+
* Which body the expanded row mounts. A runtime's config is not always a
|
|
66
|
+
* choice among a fixed set: Antigravity picks one sign-in form from a ladder,
|
|
67
|
+
* while Codex carries a LIST of providers the user adds, edits and removes
|
|
68
|
+
* (2026-10-03 ruling; the former active/select toggle is gone — which provider
|
|
69
|
+
* a Codex session runs on is DSH's own per-session model selection, not a
|
|
70
|
+
* hub-side switch). One namespace, two shapes — the kind discriminates.
|
|
71
|
+
*/
|
|
72
|
+
readonly kind: 'auth' | 'providers';
|
|
73
|
+
}
|
|
74
|
+
/** The panel spec for a runtime, or `undefined` when it has none yet. */
|
|
75
|
+
export declare function settingsPanelFor(agentKey: string): SettingsPanelSpec | undefined;
|
|
76
|
+
/** Whether this runtime's row body expands into a real settings panel. */
|
|
77
|
+
export declare function hasSettingsPanel(agentKey: string): boolean;
|
|
78
|
+
/**
|
|
79
|
+
* Accordion transition: at most one row open. Clicking the open row closes it;
|
|
80
|
+
* clicking another moves the panel there in one click.
|
|
81
|
+
*/
|
|
82
|
+
export declare function toggleExpanded(current: string | null, key: string): string | null;
|
|
83
|
+
/**
|
|
84
|
+
* Defensive parse of the RPC answer. Returns `undefined` for anything that is
|
|
85
|
+
* not a usable view (no methods, wrong shape, adapter absent) so the panel can
|
|
86
|
+
* render an explicit failure instead of an empty list that looks like success.
|
|
87
|
+
*/
|
|
88
|
+
export declare function parseAuthView(raw: unknown): RuntimeAuthView | undefined;
|
|
89
|
+
/**
|
|
90
|
+
* The option the panel marks as in force: the effective one when the adapter
|
|
91
|
+
* named it, else the explicit selection. `undefined` when neither is known —
|
|
92
|
+
* the panel then marks nothing rather than guessing.
|
|
93
|
+
*/
|
|
94
|
+
export declare function activeMethod(view: RuntimeAuthView): AuthMethodOption | undefined;
|
|
95
|
+
/** Whether an option may be picked (placeholders are rendered, never selected). */
|
|
96
|
+
export declare function selectable(option: AuthMethodOption): boolean;
|
|
97
|
+
/** One model behind a provider, as the panel lists it. */
|
|
98
|
+
export interface ProviderModelOption {
|
|
99
|
+
readonly id: string;
|
|
100
|
+
/** Human label; the adapter sends one, else the id stands in. */
|
|
101
|
+
readonly label: string;
|
|
102
|
+
readonly contextWindow?: number;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* The auth shapes the provider faces use between them: `apiKey` is shared,
|
|
106
|
+
* codex adds `env` (the key lives in a named variable), claude adds
|
|
107
|
+
* `authToken` (a Bearer token). Each face's adapter rejects the other's
|
|
108
|
+
* addition on save, which is why the form offers kinds per view
|
|
109
|
+
* (`authKindOptions`) instead of one fixed list.
|
|
110
|
+
*/
|
|
111
|
+
export type ProviderAuthKind = 'apiKey' | 'env' | 'authToken';
|
|
112
|
+
/** One configured provider, listed but never carrying its key. */
|
|
113
|
+
export interface ProviderOption {
|
|
114
|
+
readonly id: string;
|
|
115
|
+
readonly label: string;
|
|
116
|
+
readonly baseUrl: string;
|
|
117
|
+
readonly protocol: string;
|
|
118
|
+
readonly models: readonly ProviderModelOption[];
|
|
119
|
+
/** Which key shape the entry stores — see `ProviderAuthKind`. */
|
|
120
|
+
readonly authKind: ProviderAuthKind;
|
|
121
|
+
/** The variable an env-shaped provider expects. */
|
|
122
|
+
readonly envName?: string;
|
|
123
|
+
/** Whether a key is available — the ONLY thing the wire says about it. */
|
|
124
|
+
readonly hasKey: boolean;
|
|
125
|
+
}
|
|
126
|
+
/** One wire protocol the adapter offers, and whether it may be picked. */
|
|
127
|
+
export interface ProviderProtocolOption {
|
|
128
|
+
readonly value: string;
|
|
129
|
+
readonly label: string;
|
|
130
|
+
readonly available: boolean;
|
|
131
|
+
readonly hint: string;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* The files this surface reads and writes, shown so where an edit lands is
|
|
135
|
+
* never a surprise. Only `store` is common: each face names its own native
|
|
136
|
+
* files (codex: config/auth/catalogs; claude: settings), and a face that
|
|
137
|
+
* lacks a slot simply omits it — the footer renders what is there.
|
|
138
|
+
*/
|
|
139
|
+
export interface ProviderPaths {
|
|
140
|
+
readonly store: string;
|
|
141
|
+
readonly config?: string;
|
|
142
|
+
readonly auth?: string;
|
|
143
|
+
readonly catalogs?: string;
|
|
144
|
+
readonly settings?: string;
|
|
145
|
+
}
|
|
146
|
+
/** The adapter's answer to `codexProviders/get` / `claudeProviders/get` (and to every mutation). */
|
|
147
|
+
export interface RuntimeProvidersView {
|
|
148
|
+
readonly providers: readonly ProviderOption[];
|
|
149
|
+
/**
|
|
150
|
+
* What the user's OWN native config currently names (codex: the provider
|
|
151
|
+
* `~/.codex/config.toml` selects; claude: the endpoint the `settings.json`
|
|
152
|
+
* env pins). Informational only — there is no action attached to it, and
|
|
153
|
+
* DSH's per-session model selection (not this list) decides what a session
|
|
154
|
+
* runs.
|
|
155
|
+
*/
|
|
156
|
+
readonly native: {
|
|
157
|
+
readonly providerId?: string;
|
|
158
|
+
readonly baseUrl?: string;
|
|
159
|
+
readonly model?: string;
|
|
160
|
+
} | null;
|
|
161
|
+
/**
|
|
162
|
+
* The wire protocols the adapter offers, in the order it offers them. Empty
|
|
163
|
+
* for a face with no protocol choice (claude) — the panel then omits the
|
|
164
|
+
* dropdown instead of inventing options the runtime cannot run.
|
|
165
|
+
*/
|
|
166
|
+
readonly protocols: readonly ProviderProtocolOption[];
|
|
167
|
+
readonly paths: ProviderPaths;
|
|
168
|
+
/** Epoch ms of the last reconcile against the native config, when one has happened. */
|
|
169
|
+
readonly syncedAt?: number;
|
|
170
|
+
readonly note?: string;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Defensive parse of the adapter's providers answer.
|
|
174
|
+
*
|
|
175
|
+
* `undefined` for anything that is not a usable view — but an empty `providers`
|
|
176
|
+
* array is valid (a fresh install), and so is a provider whose `models` array
|
|
177
|
+
* is empty. `protocols` is the codex face's field: an ABSENT field (the claude
|
|
178
|
+
* face) reads as "no protocol choice" and never fails the parse, while a
|
|
179
|
+
* present-but-unusable list is a malformed codex answer and rejects as before.
|
|
180
|
+
*/
|
|
181
|
+
export declare function parseProvidersView(raw: unknown): RuntimeProvidersView | undefined;
|
|
182
|
+
/** One selectable auth shape for the add/edit form (`authKindOptions`). */
|
|
183
|
+
export interface ProviderAuthKindOption {
|
|
184
|
+
readonly value: ProviderAuthKind;
|
|
185
|
+
readonly label: string;
|
|
186
|
+
readonly hint: string;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* The auth shapes the add/edit form may pick for a provider, in display order.
|
|
190
|
+
*
|
|
191
|
+
* The view carries no explicit vocabulary field, so the panel reads it off the
|
|
192
|
+
* one field that distinguishes the faces today: `protocols`. The codex face
|
|
193
|
+
* advertises wire protocols and offers key-or-env-var; the claude face carries
|
|
194
|
+
* neither and offers its two header shapes instead. The list is per-view,
|
|
195
|
+
* never a fixed union — each adapter rejects the other's kinds on save, so a
|
|
196
|
+
* union dropdown would miscode silently. A third face extends the table.
|
|
197
|
+
*/
|
|
198
|
+
export declare function authKindOptions(view: RuntimeProvidersView): readonly ProviderAuthKindOption[];
|
|
199
|
+
/**
|
|
200
|
+
* `provider / model` (codex) or `endpoint / model` (claude) — whichever halves
|
|
201
|
+
* the user's own native config names, joined for the one-line fact the panel
|
|
202
|
+
* states and never acts on.
|
|
203
|
+
*/
|
|
204
|
+
export declare function nativeDescription(native: RuntimeProvidersView['native']): string;
|
|
205
|
+
/**
|
|
206
|
+
* The non-store paths joined for the panel's second footer line, in a fixed
|
|
207
|
+
* slot order. `undefined` when the face named none — the line is omitted
|
|
208
|
+
* entirely rather than rendered with blank slots.
|
|
209
|
+
*/
|
|
210
|
+
export declare function nativePathsLine(paths: ProviderPaths): string | undefined;
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime settings panels for the Hub's Agent Runtimes rows (P3, 2026-10-02
|
|
3
|
+
* user ruling).
|
|
4
|
+
*
|
|
5
|
+
* Interaction contract the UI follows (ruling, verbatim intent):
|
|
6
|
+
* - clicking the ROW BODY expands that runtime's OWN settings inline
|
|
7
|
+
* (accordion: at most one row open at a time);
|
|
8
|
+
* - the row's existing right-hand `switch` affordance is the ONLY switch —
|
|
9
|
+
* the panel never carries a second one.
|
|
10
|
+
*
|
|
11
|
+
* Config belongs to the adapter (agent-adapter-dev-rules §12), so this module
|
|
12
|
+
* owns only the presentation-side logic: which runtimes have a panel, the
|
|
13
|
+
* accordion transition, and a defensive parse of whatever the adapter's
|
|
14
|
+
* `*Auth/get` RPC returns. The adapter decides which auth methods exist, which
|
|
15
|
+
* are available on this machine, and which one is in force.
|
|
16
|
+
*
|
|
17
|
+
* Node-safe by construction (no DOM, no React, no fetch) — the host tsconfig
|
|
18
|
+
* dual-emits this file to `dist/client/agent-settings.js` so
|
|
19
|
+
* test/client-agent-settings.test.mjs can pin the parse and accordion rules
|
|
20
|
+
* under `node --test` (the roster.ts / mesh-api.ts precedent).
|
|
21
|
+
*
|
|
22
|
+
* @module superd-hub/client/agent-settings
|
|
23
|
+
*/
|
|
24
|
+
const SETTINGS_PANELS = {
|
|
25
|
+
// The one runtime with a settings surface this round: the CLI adapter owns the
|
|
26
|
+
// auth ladder and is the configuration surface for the user's local Antigravity.
|
|
27
|
+
agy: { namespace: 'agyAuth', kind: 'auth' },
|
|
28
|
+
// Codex's own config.toml names exactly one `model_provider`, but that file
|
|
29
|
+
// is the USER's and no longer the hub's toggle: Super D hosts the list
|
|
30
|
+
// cc-switch otherwise holds (add / edit / remove) and the adapter owns both
|
|
31
|
+
// the list and whatever it does with the native file.
|
|
32
|
+
codex: { namespace: 'codexProviders', kind: 'providers' },
|
|
33
|
+
// Both Codex lines host the SAME provider list (2026-10-04): the SDK half is
|
|
34
|
+
// the same agent through a different transport, so it carries the same panel
|
|
35
|
+
// and the same Remote namespace. The two worlds keep separate stores under
|
|
36
|
+
// their own `agents/<key>/`, so neither sees the other's list.
|
|
37
|
+
'codex-sdk': { namespace: 'codexProviders', kind: 'providers' },
|
|
38
|
+
// Claude serves the same providers view shape as Codex with no protocol
|
|
39
|
+
// dropdown: its adapter's view carries no `protocols` field (claude has no
|
|
40
|
+
// wire-protocol choice to make), so the body degrades to what the view does
|
|
41
|
+
// carry — two header auth kinds and its own native fact (2026-10-04).
|
|
42
|
+
claude: { namespace: 'claudeProviders', kind: 'providers' },
|
|
43
|
+
};
|
|
44
|
+
/** The panel spec for a runtime, or `undefined` when it has none yet. */
|
|
45
|
+
export function settingsPanelFor(agentKey) {
|
|
46
|
+
return SETTINGS_PANELS[agentKey];
|
|
47
|
+
}
|
|
48
|
+
/** Whether this runtime's row body expands into a real settings panel. */
|
|
49
|
+
export function hasSettingsPanel(agentKey) {
|
|
50
|
+
return settingsPanelFor(agentKey) !== undefined;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Accordion transition: at most one row open. Clicking the open row closes it;
|
|
54
|
+
* clicking another moves the panel there in one click.
|
|
55
|
+
*/
|
|
56
|
+
export function toggleExpanded(current, key) {
|
|
57
|
+
return current === key ? null : key;
|
|
58
|
+
}
|
|
59
|
+
function str(value) {
|
|
60
|
+
return typeof value === 'string' && value !== '' ? value : undefined;
|
|
61
|
+
}
|
|
62
|
+
function methodOption(raw) {
|
|
63
|
+
if (typeof raw !== 'object' || raw === null)
|
|
64
|
+
return undefined;
|
|
65
|
+
const record = raw;
|
|
66
|
+
const key = str(record.key);
|
|
67
|
+
const label = str(record.label);
|
|
68
|
+
if (key === undefined || label === undefined)
|
|
69
|
+
return undefined;
|
|
70
|
+
return {
|
|
71
|
+
key,
|
|
72
|
+
label,
|
|
73
|
+
// Absent flags read as the conservative value: an older adapter that omits
|
|
74
|
+
// `available` must not render an option as usable when we cannot tell.
|
|
75
|
+
available: record.available === true,
|
|
76
|
+
placeholder: record.placeholder === true,
|
|
77
|
+
hint: str(record.hint) ?? '',
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Defensive parse of the RPC answer. Returns `undefined` for anything that is
|
|
82
|
+
* not a usable view (no methods, wrong shape, adapter absent) so the panel can
|
|
83
|
+
* render an explicit failure instead of an empty list that looks like success.
|
|
84
|
+
*/
|
|
85
|
+
export function parseAuthView(raw) {
|
|
86
|
+
if (typeof raw !== 'object' || raw === null)
|
|
87
|
+
return undefined;
|
|
88
|
+
const record = raw;
|
|
89
|
+
if (!Array.isArray(record.methods))
|
|
90
|
+
return undefined;
|
|
91
|
+
const methods = record.methods.map(methodOption).filter((m) => m !== undefined);
|
|
92
|
+
if (methods.length === 0)
|
|
93
|
+
return undefined;
|
|
94
|
+
const settingsPath = str(record.settingsPath);
|
|
95
|
+
const note = str(record.note);
|
|
96
|
+
return {
|
|
97
|
+
methods,
|
|
98
|
+
selected: str(record.selected) ?? null,
|
|
99
|
+
effective: str(record.effective) ?? null,
|
|
100
|
+
...(settingsPath === undefined ? {} : { settingsPath }),
|
|
101
|
+
...(note === undefined ? {} : { note }),
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* The option the panel marks as in force: the effective one when the adapter
|
|
106
|
+
* named it, else the explicit selection. `undefined` when neither is known —
|
|
107
|
+
* the panel then marks nothing rather than guessing.
|
|
108
|
+
*/
|
|
109
|
+
export function activeMethod(view) {
|
|
110
|
+
const wanted = view.effective ?? view.selected;
|
|
111
|
+
if (wanted === null)
|
|
112
|
+
return undefined;
|
|
113
|
+
return view.methods.find((method) => method.key === wanted);
|
|
114
|
+
}
|
|
115
|
+
/** Whether an option may be picked (placeholders are rendered, never selected). */
|
|
116
|
+
export function selectable(option) {
|
|
117
|
+
return !option.placeholder;
|
|
118
|
+
}
|
|
119
|
+
function nonEmpty(value) {
|
|
120
|
+
return typeof value === 'string' && value !== '' ? value : undefined;
|
|
121
|
+
}
|
|
122
|
+
function modelOption(raw) {
|
|
123
|
+
if (typeof raw !== 'object' || raw === null)
|
|
124
|
+
return undefined;
|
|
125
|
+
const record = raw;
|
|
126
|
+
const id = nonEmpty(record.id);
|
|
127
|
+
if (id === undefined)
|
|
128
|
+
return undefined;
|
|
129
|
+
const contextWindow = record.contextWindow;
|
|
130
|
+
return {
|
|
131
|
+
id,
|
|
132
|
+
label: nonEmpty(record.displayName) ?? id,
|
|
133
|
+
...(typeof contextWindow === 'number' && Number.isSafeInteger(contextWindow) && contextWindow > 0
|
|
134
|
+
? { contextWindow }
|
|
135
|
+
: {}),
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
function providerAuthKind(raw) {
|
|
139
|
+
// An unstated or unknown kind reads as the shared conservative default,
|
|
140
|
+
// never as the other face's shape.
|
|
141
|
+
return raw === 'env' ? 'env' : raw === 'authToken' ? 'authToken' : 'apiKey';
|
|
142
|
+
}
|
|
143
|
+
function providerOption(raw) {
|
|
144
|
+
if (typeof raw !== 'object' || raw === null)
|
|
145
|
+
return undefined;
|
|
146
|
+
const record = raw;
|
|
147
|
+
const id = nonEmpty(record.id);
|
|
148
|
+
const label = nonEmpty(record.label);
|
|
149
|
+
const baseUrl = nonEmpty(record.baseUrl);
|
|
150
|
+
if (id === undefined || label === undefined || baseUrl === undefined)
|
|
151
|
+
return undefined;
|
|
152
|
+
const models = Array.isArray(record.models)
|
|
153
|
+
? record.models.map(modelOption).filter((entry) => entry !== undefined)
|
|
154
|
+
: [];
|
|
155
|
+
const envName = nonEmpty(record.envName);
|
|
156
|
+
return {
|
|
157
|
+
id,
|
|
158
|
+
label,
|
|
159
|
+
baseUrl,
|
|
160
|
+
// An unknown protocol is never echoed into a control; the only value this
|
|
161
|
+
// harness can actually run is the safe default.
|
|
162
|
+
protocol: record.protocol === 'chat' ? 'chat' : 'responses',
|
|
163
|
+
models,
|
|
164
|
+
authKind: providerAuthKind(record.authKind),
|
|
165
|
+
...(envName === undefined ? {} : { envName }),
|
|
166
|
+
hasKey: record.hasKey === true,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
function protocolOption(raw) {
|
|
170
|
+
if (typeof raw !== 'object' || raw === null)
|
|
171
|
+
return undefined;
|
|
172
|
+
const record = raw;
|
|
173
|
+
const value = nonEmpty(record.value);
|
|
174
|
+
const label = nonEmpty(record.label);
|
|
175
|
+
if (value === undefined || label === undefined)
|
|
176
|
+
return undefined;
|
|
177
|
+
return { value, label, available: record.available === true, hint: nonEmpty(record.hint) ?? '' };
|
|
178
|
+
}
|
|
179
|
+
function providerPaths(raw) {
|
|
180
|
+
if (typeof raw !== 'object' || raw === null)
|
|
181
|
+
return undefined;
|
|
182
|
+
const record = raw;
|
|
183
|
+
const store = nonEmpty(record.store);
|
|
184
|
+
// The store is the only slot every face promises; the native files are the
|
|
185
|
+
// face's own, and an absent one stays absent rather than blank.
|
|
186
|
+
if (store === undefined)
|
|
187
|
+
return undefined;
|
|
188
|
+
const config = nonEmpty(record.config);
|
|
189
|
+
const auth = nonEmpty(record.auth);
|
|
190
|
+
const catalogs = nonEmpty(record.catalogs);
|
|
191
|
+
const settings = nonEmpty(record.settings);
|
|
192
|
+
return {
|
|
193
|
+
store,
|
|
194
|
+
...(config === undefined ? {} : { config }),
|
|
195
|
+
...(auth === undefined ? {} : { auth }),
|
|
196
|
+
...(catalogs === undefined ? {} : { catalogs }),
|
|
197
|
+
...(settings === undefined ? {} : { settings }),
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Defensive parse of the adapter's providers answer.
|
|
202
|
+
*
|
|
203
|
+
* `undefined` for anything that is not a usable view — but an empty `providers`
|
|
204
|
+
* array is valid (a fresh install), and so is a provider whose `models` array
|
|
205
|
+
* is empty. `protocols` is the codex face's field: an ABSENT field (the claude
|
|
206
|
+
* face) reads as "no protocol choice" and never fails the parse, while a
|
|
207
|
+
* present-but-unusable list is a malformed codex answer and rejects as before.
|
|
208
|
+
*/
|
|
209
|
+
export function parseProvidersView(raw) {
|
|
210
|
+
if (typeof raw !== 'object' || raw === null)
|
|
211
|
+
return undefined;
|
|
212
|
+
const record = raw;
|
|
213
|
+
if (!Array.isArray(record.providers))
|
|
214
|
+
return undefined;
|
|
215
|
+
// Absent `protocols` (the claude face) → nothing to offer, the panel omits
|
|
216
|
+
// the dropdown. Present (the codex face) → must parse to at least one
|
|
217
|
+
// option, exactly as before.
|
|
218
|
+
let protocols = [];
|
|
219
|
+
if (record.protocols !== undefined) {
|
|
220
|
+
if (!Array.isArray(record.protocols))
|
|
221
|
+
return undefined;
|
|
222
|
+
protocols = record.protocols.map(protocolOption).filter((entry) => entry !== undefined);
|
|
223
|
+
if (protocols.length === 0)
|
|
224
|
+
return undefined;
|
|
225
|
+
}
|
|
226
|
+
const paths = providerPaths(record.paths);
|
|
227
|
+
if (paths === undefined)
|
|
228
|
+
return undefined;
|
|
229
|
+
const providers = record.providers.map(providerOption).filter((entry) => entry !== undefined);
|
|
230
|
+
const syncedAt = record.syncedAt;
|
|
231
|
+
const note = nonEmpty(record.note);
|
|
232
|
+
return {
|
|
233
|
+
providers,
|
|
234
|
+
native: nativeConfig(record.native),
|
|
235
|
+
protocols,
|
|
236
|
+
paths,
|
|
237
|
+
...(typeof syncedAt === 'number' && Number.isFinite(syncedAt) ? { syncedAt } : {}),
|
|
238
|
+
...(note === undefined ? {} : { note }),
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* The user's own native config as the adapter last read it. `null` when the
|
|
243
|
+
* adapter said nothing; otherwise an object carrying whichever halves were
|
|
244
|
+
* named — codex names a provider id, claude an endpoint URL — and an empty
|
|
245
|
+
* one is still news (the panel says the file names nothing).
|
|
246
|
+
*/
|
|
247
|
+
function nativeConfig(raw) {
|
|
248
|
+
if (typeof raw !== 'object' || raw === null)
|
|
249
|
+
return null;
|
|
250
|
+
const record = raw;
|
|
251
|
+
const providerId = nonEmpty(record.providerId);
|
|
252
|
+
const baseUrl = nonEmpty(record.baseUrl);
|
|
253
|
+
const model = nonEmpty(record.model);
|
|
254
|
+
return {
|
|
255
|
+
...(providerId === undefined ? {} : { providerId }),
|
|
256
|
+
...(baseUrl === undefined ? {} : { baseUrl }),
|
|
257
|
+
...(model === undefined ? {} : { model }),
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
/** The codex face: a stored key, or the name of a variable holding it. */
|
|
261
|
+
const KEY_OR_ENV = [
|
|
262
|
+
{ value: 'apiKey', label: 'API key', hint: 'Stored with the provider; injected at launch.' },
|
|
263
|
+
{ value: 'env', label: 'Environment variable', hint: 'The child reads the key from a named variable.' },
|
|
264
|
+
];
|
|
265
|
+
/** The claude face: both kinds are literal keys, differing only in the header. */
|
|
266
|
+
const TWO_HEADER_SHAPES = [
|
|
267
|
+
{ value: 'apiKey', label: 'API key (x-api-key)', hint: 'Sent as the x-api-key header.' },
|
|
268
|
+
{ value: 'authToken', label: 'Bearer token', hint: 'Sent as the Authorization header.' },
|
|
269
|
+
];
|
|
270
|
+
/**
|
|
271
|
+
* The auth shapes the add/edit form may pick for a provider, in display order.
|
|
272
|
+
*
|
|
273
|
+
* The view carries no explicit vocabulary field, so the panel reads it off the
|
|
274
|
+
* one field that distinguishes the faces today: `protocols`. The codex face
|
|
275
|
+
* advertises wire protocols and offers key-or-env-var; the claude face carries
|
|
276
|
+
* neither and offers its two header shapes instead. The list is per-view,
|
|
277
|
+
* never a fixed union — each adapter rejects the other's kinds on save, so a
|
|
278
|
+
* union dropdown would miscode silently. A third face extends the table.
|
|
279
|
+
*/
|
|
280
|
+
export function authKindOptions(view) {
|
|
281
|
+
return view.protocols.length > 0 ? KEY_OR_ENV : TWO_HEADER_SHAPES;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* `provider / model` (codex) or `endpoint / model` (claude) — whichever halves
|
|
285
|
+
* the user's own native config names, joined for the one-line fact the panel
|
|
286
|
+
* states and never acts on.
|
|
287
|
+
*/
|
|
288
|
+
export function nativeDescription(native) {
|
|
289
|
+
const parts = [native?.providerId ?? native?.baseUrl, native?.model].filter((part) => part !== undefined);
|
|
290
|
+
return parts.length === 0 ? 'no provider' : parts.join(' / ');
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* The non-store paths joined for the panel's second footer line, in a fixed
|
|
294
|
+
* slot order. `undefined` when the face named none — the line is omitted
|
|
295
|
+
* entirely rather than rendered with blank slots.
|
|
296
|
+
*/
|
|
297
|
+
export function nativePathsLine(paths) {
|
|
298
|
+
const parts = [paths.config, paths.auth, paths.catalogs, paths.settings].filter((part) => part !== undefined);
|
|
299
|
+
return parts.length === 0 ? undefined : parts.join(' · ');
|
|
300
|
+
}
|
|
@@ -25,6 +25,12 @@ const FALLBACK_LABELS = {
|
|
|
25
25
|
pi: 'Pi',
|
|
26
26
|
hermes: 'Hermes',
|
|
27
27
|
agy: 'Antigravity',
|
|
28
|
+
// The opt-in SDK halves carry their own keys so a host that reports only keys
|
|
29
|
+
// still renders a distinguishable label (the composite rows are `disabled: true`
|
|
30
|
+
// by default, so these appear only once an operator turns one on).
|
|
31
|
+
'omp-sdk': 'OMP (SDK)',
|
|
32
|
+
'agy-sdk': 'Antigravity (SDK)',
|
|
33
|
+
'codex-sdk': 'Codex (SDK)',
|
|
28
34
|
};
|
|
29
35
|
/** Coerce a wire `agents` array into links; undefined when unusable/empty. */
|
|
30
36
|
function coerceAgents(raw) {
|