pstack-dsh 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (172) hide show
  1. package/HARNESS.md +109 -0
  2. package/LICENSE +25 -0
  3. package/README.md +168 -0
  4. package/TEST-PLAN.md +70 -0
  5. package/agents/comment-sicko.md +32 -0
  6. package/agents/poteto-agent.md +9 -0
  7. package/cordis.patch.yml +4 -0
  8. package/cordis.yml +4 -0
  9. package/docs/guide/01-setup.md +41 -0
  10. package/docs/guide/02-poteto-mode.md +98 -0
  11. package/docs/guide/03-understand.md +53 -0
  12. package/docs/guide/04-design.md +81 -0
  13. package/docs/guide/05-build-and-clean.md +75 -0
  14. package/docs/guide/06-verify-and-ship.md +87 -0
  15. package/docs/guide/07-overnight.md +81 -0
  16. package/docs/guide/08-principles.md +71 -0
  17. package/docs/guide/09-make-it-yours.md +67 -0
  18. package/docs/guide/10-recipes-and-pitfalls.md +96 -0
  19. package/docs/guide/README.md +30 -0
  20. package/dshx.yml +9 -0
  21. package/lib/client.js +981 -0
  22. package/lib/client.js.map +1 -0
  23. package/lib/index.d.ts +34 -0
  24. package/lib/index.js +1120 -0
  25. package/package.json +140 -0
  26. package/skills/architect/SKILL.md +83 -0
  27. package/skills/architect/references/design-red-flags.md +33 -0
  28. package/skills/architect/references/rationale-template.md +35 -0
  29. package/skills/architect/references/runner-prompt.md +20 -0
  30. package/skills/arena/SKILL.md +73 -0
  31. package/skills/automate-me/SKILL.md +103 -0
  32. package/skills/blast-radius/SKILL.md +50 -0
  33. package/skills/bro/SKILL.md +7 -0
  34. package/skills/create-verification-skill/SKILL.md +44 -0
  35. package/skills/create-verification-skill/references/feature-map-example/README.md +47 -0
  36. package/skills/create-verification-skill/references/feature-map-example/create-note.md +39 -0
  37. package/skills/create-verification-skill/references/feature-map-example/search.md +45 -0
  38. package/skills/figure-it-out/SKILL.md +53 -0
  39. package/skills/how/SKILL.md +45 -0
  40. package/skills/how/references/explainer-prompt.md +55 -0
  41. package/skills/how/references/explorer-prompt.md +52 -0
  42. package/skills/interrogate/SKILL.md +99 -0
  43. package/skills/interrogate/references/code-quality-review.md +47 -0
  44. package/skills/interrogate/references/lead-judgment.md +58 -0
  45. package/skills/interrogate/references/reviewer-prompt.md +72 -0
  46. package/skills/interrogate/references/rubric.md +77 -0
  47. package/skills/maintain-verification-skill/SKILL.md +39 -0
  48. package/skills/no-comments/SKILL.md +24 -0
  49. package/skills/poteto-mode/SKILL.md +149 -0
  50. package/skills/poteto-mode/playbooks/authoring-a-skill.md +12 -0
  51. package/skills/poteto-mode/playbooks/autonomous-run.md +13 -0
  52. package/skills/poteto-mode/playbooks/autopilot-full.md +13 -0
  53. package/skills/poteto-mode/playbooks/autopilot-stack.md +16 -0
  54. package/skills/poteto-mode/playbooks/babysit.md +27 -0
  55. package/skills/poteto-mode/playbooks/bug-fix.md +17 -0
  56. package/skills/poteto-mode/playbooks/eval.md +25 -0
  57. package/skills/poteto-mode/playbooks/feature.md +21 -0
  58. package/skills/poteto-mode/playbooks/hillclimb.md +21 -0
  59. package/skills/poteto-mode/playbooks/investigation.md +14 -0
  60. package/skills/poteto-mode/playbooks/multi-phase-plan.md +156 -0
  61. package/skills/poteto-mode/playbooks/opening-a-pr.md +33 -0
  62. package/skills/poteto-mode/playbooks/orchestrate.md +113 -0
  63. package/skills/poteto-mode/playbooks/pause-safely.md +10 -0
  64. package/skills/poteto-mode/playbooks/perf-issue.md +24 -0
  65. package/skills/poteto-mode/playbooks/prototype.md +14 -0
  66. package/skills/poteto-mode/playbooks/refactoring.md +16 -0
  67. package/skills/poteto-mode/playbooks/runtime-forensics.md +11 -0
  68. package/skills/poteto-mode/playbooks/session-pickup.md +11 -0
  69. package/skills/poteto-mode/playbooks/shipping.md +17 -0
  70. package/skills/poteto-mode/playbooks/trace-forensics.md +14 -0
  71. package/skills/poteto-mode/playbooks/visual-parity.md +11 -0
  72. package/skills/poteto-mode/playbooks/worktree-cleanup.md +14 -0
  73. package/skills/poteto-mode/references/bugbot-triage.md +142 -0
  74. package/skills/poteto-mode/scripts/bootstrap.ts +62 -0
  75. package/skills/poteto-mode/scripts/bun.lock +67 -0
  76. package/skills/poteto-mode/scripts/check-plan.mjs +186 -0
  77. package/skills/poteto-mode/scripts/orch/orch.test.ts +634 -0
  78. package/skills/poteto-mode/scripts/orch/orch.ts +578 -0
  79. package/skills/poteto-mode/scripts/orch/store.ts +1607 -0
  80. package/skills/poteto-mode/scripts/package.json +16 -0
  81. package/skills/poteto-mode/scripts/watch-pr/cli.test.ts +224 -0
  82. package/skills/poteto-mode/scripts/watch-pr/cli.ts +223 -0
  83. package/skills/poteto-mode/scripts/watch-pr/fakes.test-helper.ts +118 -0
  84. package/skills/poteto-mode/scripts/watch-pr/github.test.ts +306 -0
  85. package/skills/poteto-mode/scripts/watch-pr/github.ts +699 -0
  86. package/skills/poteto-mode/scripts/watch-pr/policy.test.ts +420 -0
  87. package/skills/poteto-mode/scripts/watch-pr/policy.ts +832 -0
  88. package/skills/poteto-mode/scripts/watch-pr/render.ts +169 -0
  89. package/skills/poteto-mode/scripts/watch-pr/tsconfig.json +13 -0
  90. package/skills/poteto-mode/scripts/watch-pr/types.compile.ts +93 -0
  91. package/skills/poteto-mode/scripts/watch-pr/types.ts +401 -0
  92. package/skills/poteto-mode/scripts/watch-pr/watch-pr +6 -0
  93. package/skills/poteto-mode/scripts/worktree-audit.sh +86 -0
  94. package/skills/principle-attack-the-premise/SKILL.md +22 -0
  95. package/skills/principle-boundary-discipline/SKILL.md +33 -0
  96. package/skills/principle-build-the-lever/SKILL.md +22 -0
  97. package/skills/principle-encode-lessons-in-structure/SKILL.md +30 -0
  98. package/skills/principle-exhaust-the-design-space/SKILL.md +20 -0
  99. package/skills/principle-experience-first/SKILL.md +18 -0
  100. package/skills/principle-fix-root-causes/SKILL.md +22 -0
  101. package/skills/principle-foundational-thinking/SKILL.md +20 -0
  102. package/skills/principle-guard-the-context-window/SKILL.md +16 -0
  103. package/skills/principle-laziness-protocol/SKILL.md +17 -0
  104. package/skills/principle-make-operations-idempotent/SKILL.md +23 -0
  105. package/skills/principle-migrate-callers-then-delete-legacy-apis/SKILL.md +21 -0
  106. package/skills/principle-minimize-reader-load/SKILL.md +22 -0
  107. package/skills/principle-model-the-domain/SKILL.md +25 -0
  108. package/skills/principle-never-block-on-the-human/SKILL.md +21 -0
  109. package/skills/principle-outcome-oriented-execution/SKILL.md +21 -0
  110. package/skills/principle-prove-it-works/SKILL.md +32 -0
  111. package/skills/principle-redesign-from-first-principles/SKILL.md +15 -0
  112. package/skills/principle-separate-before-serializing-shared-state/SKILL.md +15 -0
  113. package/skills/principle-sequence-verifiable-units/SKILL.md +21 -0
  114. package/skills/principle-subtract-before-you-add/SKILL.md +20 -0
  115. package/skills/principle-test-behavior-not-implementation/SKILL.md +24 -0
  116. package/skills/principle-type-system-discipline/SKILL.md +30 -0
  117. package/skills/recall/SKILL.md +35 -0
  118. package/skills/reflect/SKILL.md +65 -0
  119. package/skills/reflect/references/divergent-reviewer.md +43 -0
  120. package/skills/reflect/references/judgment-reviewer.md +42 -0
  121. package/skills/reflect/references/synthesizer.md +56 -0
  122. package/skills/reflect/references/tooling-reviewer.md +55 -0
  123. package/skills/setup-pstack/SKILL.md +32 -0
  124. package/skills/setup-pstack/references/catalog.md +28 -0
  125. package/skills/setup-pstack/references/spawn.md +61 -0
  126. package/skills/show-me-your-work/SKILL.md +82 -0
  127. package/skills/show-me-your-work/references/decision-log-template.tsv +1 -0
  128. package/skills/show-me-your-work/scripts/log.sh +40 -0
  129. package/skills/swarm/SKILL.md +44 -0
  130. package/skills/tdd/SKILL.md +44 -0
  131. package/skills/teach/SKILL.md +21 -0
  132. package/skills/technical-writing/SKILL.md +127 -0
  133. package/skills/typescript-best-practices/SKILL.md +30 -0
  134. package/skills/typescript-best-practices/references/patterns.md +313 -0
  135. package/skills/unslop/SKILL.md +67 -0
  136. package/skills/why/SKILL.md +146 -0
  137. package/skills/why/references/epistemics.md +144 -0
  138. package/skills/why/references/investigator-prompt.md +103 -0
  139. package/skills/why/references/source-playbook.md +17 -0
  140. package/skills/why/references/sources/code-archaeology.md +88 -0
  141. package/skills/why/references/sources/databricks.md +70 -0
  142. package/skills/why/references/sources/datadog.md +99 -0
  143. package/skills/why/references/sources/incident-postmortem.md +15 -0
  144. package/skills/why/references/sources/linear.md +48 -0
  145. package/skills/why/references/sources/notion.md +55 -0
  146. package/skills/why/references/sources/sentry.md +100 -0
  147. package/skills/why/references/sources/slack.md +54 -0
  148. package/skills/why/references/synthesizer-prompt.md +135 -0
  149. package/src/catalog-types.ts +54 -0
  150. package/src/catalog.ts +308 -0
  151. package/src/client/PstackSettings.tsx +519 -0
  152. package/src/client/api.ts +56 -0
  153. package/src/client/index.tsx +38 -0
  154. package/src/client/locales.ts +65 -0
  155. package/src/client/poteto-defaults.ts +37 -0
  156. package/src/frontmatter.ts +73 -0
  157. package/src/home.ts +13 -0
  158. package/src/http-trust.ts +38 -0
  159. package/src/ids.ts +39 -0
  160. package/src/index.ts +85 -0
  161. package/src/overlay-model.ts +139 -0
  162. package/src/overlay.ts +40 -0
  163. package/src/persona.ts +38 -0
  164. package/src/plugin-config.ts +29 -0
  165. package/src/request-overlay.ts +40 -0
  166. package/src/roles.ts +55 -0
  167. package/src/settings-api.ts +48 -0
  168. package/src/settings-draft.ts +144 -0
  169. package/src/settings-routes.ts +77 -0
  170. package/src/skills-provider.ts +96 -0
  171. package/src/spawn.ts +52 -0
  172. package/src/tools.ts +226 -0
package/lib/client.js ADDED
@@ -0,0 +1,981 @@
1
+ window.__ModuleLoader__.load({
2
+ id: "pstack-dsh",
3
+ factory: (require) => {
4
+ var module = { exports: {} };
5
+ var exports = module.exports;
6
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
+ let react = require("react");
8
+ let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
9
+ let react_jsx_runtime = require("react/jsx-runtime");
10
+ //#region src/roles.ts
11
+ /**
12
+ * pstack role keys used by playbooks and Settings → pstack.
13
+ * These are pstack names, not Cursor slugs and not grok-build `subagent_type` values.
14
+ */
15
+ const SCALAR_ROLES = [
16
+ "feature",
17
+ "refactoring",
18
+ "bug-fix",
19
+ "perf-issue",
20
+ "hillclimb",
21
+ "judgment-and-prose",
22
+ "hardest-tasks",
23
+ "how-explorer",
24
+ "how-explainer",
25
+ "why-investigators",
26
+ "why-synthesizer",
27
+ "reflect-tooling",
28
+ "reflect-judgment",
29
+ "swarm-workers",
30
+ "independent-verifier",
31
+ "poteto-agent",
32
+ "comment-sicko"
33
+ ];
34
+ const PANEL_ROLES = [
35
+ "how-critics",
36
+ "arena-runners",
37
+ "arena-cross-judge-pool",
38
+ "architect-runners",
39
+ "interrogate-reviewers"
40
+ ];
41
+ const ALL_ROLES = [...SCALAR_ROLES, ...PANEL_ROLES];
42
+ function isPanelRole(value) {
43
+ return PANEL_ROLES.includes(value);
44
+ }
45
+ function emptyOverlay() {
46
+ const roles = {};
47
+ for (const role of ALL_ROLES) roles[role] = {
48
+ inherit: true,
49
+ routes: []
50
+ };
51
+ return {
52
+ version: 1,
53
+ roles
54
+ };
55
+ }
56
+ function routeKey(provider, model) {
57
+ return `${provider}::${model}`;
58
+ }
59
+ //#endregion
60
+ //#region src/settings-draft.ts
61
+ function selectableRoutes(routes) {
62
+ return routes.filter((route) => route.selectable);
63
+ }
64
+ function overlayToDraft(overlay) {
65
+ return ALL_ROLES.map((role) => {
66
+ const assignment = overlay.roles[role] ?? {
67
+ inherit: true,
68
+ routes: []
69
+ };
70
+ const inherit = assignment.inherit || assignment.routes.length === 0;
71
+ return {
72
+ role,
73
+ panel: isPanelRole(role),
74
+ inherit,
75
+ inheritChoice: "inherit-parent",
76
+ routes: inherit ? [] : assignment.routes.map((route) => ({ ...route }))
77
+ };
78
+ });
79
+ }
80
+ function draftToOverlay(drafts) {
81
+ const overlay = emptyOverlay();
82
+ for (const draft of drafts) {
83
+ if (draft.inherit || draft.routes.length === 0) {
84
+ overlay.roles[draft.role] = {
85
+ inherit: true,
86
+ routes: []
87
+ };
88
+ continue;
89
+ }
90
+ overlay.roles[draft.role] = {
91
+ inherit: false,
92
+ routes: draft.panel ? draft.routes.map((route) => ({ ...route })) : [draft.routes[0]]
93
+ };
94
+ }
95
+ return overlay;
96
+ }
97
+ function liveFor(routes, provider, model) {
98
+ return routes.find((route) => route.selectable && route.provider === provider && route.model === model);
99
+ }
100
+ function stripIllegalEffort(route, live) {
101
+ const found = liveFor(live, route.provider, route.model);
102
+ if (found === void 0) return {
103
+ provider: route.provider,
104
+ model: route.model
105
+ };
106
+ if (route.reasoningEffort === void 0) return {
107
+ provider: route.provider,
108
+ model: route.model
109
+ };
110
+ if (found.efforts.length === 0) return {
111
+ provider: route.provider,
112
+ model: route.model
113
+ };
114
+ if (!found.efforts.some((effort) => effort.id === route.reasoningEffort)) return {
115
+ provider: route.provider,
116
+ model: route.model
117
+ };
118
+ return {
119
+ provider: route.provider,
120
+ model: route.model,
121
+ reasoningEffort: route.reasoningEffort
122
+ };
123
+ }
124
+ function applyInheritAll(drafts, choice = "inherit-parent") {
125
+ return drafts.map((draft) => draft.role === "how-critics" ? draft : {
126
+ ...draft,
127
+ inherit: true,
128
+ inheritChoice: choice,
129
+ routes: []
130
+ });
131
+ }
132
+ function applyRouteToAll(drafts, route, live) {
133
+ const cleaned = stripIllegalEffort(route, live);
134
+ if (liveFor(live, cleaned.provider, cleaned.model) === void 0) return drafts;
135
+ return drafts.map((draft) => draft.role === "how-critics" ? draft : {
136
+ ...draft,
137
+ inherit: false,
138
+ inheritChoice: "inherit-parent",
139
+ routes: draft.panel ? [{ ...cleaned }] : [{ ...cleaned }]
140
+ });
141
+ }
142
+ function routeSelectValue(draft, index = 0) {
143
+ if (draft.inherit || draft.routes.length === 0) return draft.inheritChoice;
144
+ const route = draft.routes[index];
145
+ if (route === void 0) return draft.inheritChoice;
146
+ return routeKey(route.provider, route.model);
147
+ }
148
+ function parseRouteSelectValue(value, live) {
149
+ if (value === "inherit-parent" || value === "auto") return {
150
+ inherit: true,
151
+ inheritChoice: value
152
+ };
153
+ const separator = value.indexOf("::");
154
+ if (separator <= 0) return {
155
+ inherit: true,
156
+ inheritChoice: "inherit-parent"
157
+ };
158
+ const found = liveFor(live, value.slice(0, separator), value.slice(separator + 2));
159
+ if (found === void 0) return {
160
+ inherit: true,
161
+ inheritChoice: "inherit-parent"
162
+ };
163
+ return {
164
+ inherit: false,
165
+ route: {
166
+ provider: found.provider,
167
+ model: found.model
168
+ }
169
+ };
170
+ }
171
+ //#endregion
172
+ //#region src/ids.ts
173
+ /** Settings nav id. Official slot `settings.section` (`packages/client/ui-settings/src/client/contract/slots.ts`). */
174
+ const SETTINGS_SECTION_ID = "pstack";
175
+ /** Same-origin Web routes. Pattern: dsh-oauth-login `src/auth-routes.ts`. */
176
+ const SETTINGS_SNAPSHOT_PATH = "/plugins/pstack-dsh/settings";
177
+ const SETTINGS_SAVE_PATH = "/plugins/pstack-dsh/settings";
178
+ //#endregion
179
+ //#region src/client/api.ts
180
+ /** Use the same Host notifications as DSH's model directory, scoped to the open settings page. */
181
+ function listenForCatalogChanges(ctx, listener) {
182
+ const disposers = [
183
+ ctx.remote.$on("llm/adapters-updated", listener),
184
+ ctx.remote.$on("settings/document-updated", listener),
185
+ ctx.remote.$on("credentials/reference-updated", listener),
186
+ ctx.on("connection/reset", listener)
187
+ ];
188
+ return () => {
189
+ for (const dispose of disposers) dispose();
190
+ };
191
+ }
192
+ async function jsonRequest(path, method, body, signal) {
193
+ const response = await fetch(path, {
194
+ method,
195
+ headers: {
196
+ accept: "application/json",
197
+ ...body === void 0 ? {} : { "content-type": "application/json" }
198
+ },
199
+ credentials: "same-origin",
200
+ cache: "no-store",
201
+ signal,
202
+ ...body === void 0 ? {} : { body: JSON.stringify(body) }
203
+ });
204
+ const value = await response.json().catch(() => void 0);
205
+ if (!response.ok) {
206
+ const message = typeof value === "object" && value !== null && "error" in value && typeof value.error === "string" ? value.error : `HTTP ${response.status}`;
207
+ throw new Error(message);
208
+ }
209
+ return value;
210
+ }
211
+ function loadSettingsSnapshot(signal) {
212
+ return jsonRequest(SETTINGS_SNAPSHOT_PATH, "GET", void 0, signal);
213
+ }
214
+ function saveSettingsOverlay(overlay) {
215
+ return jsonRequest(SETTINGS_SAVE_PATH, "PUT", { overlay });
216
+ }
217
+ //#endregion
218
+ //#region src/client/poteto-defaults.ts
219
+ const GROK = "grok-4.6-fast-xhigh";
220
+ const SOL = "gpt-5.6-sol-max";
221
+ const FABLE = "claude-fable-5-1-thinking-max";
222
+ const PANEL = `${FABLE}, ${SOL}, ${GROK}, claude-opus-5-thinking-xhigh`;
223
+ const POTETO_DEFAULT_SLUGS = {
224
+ feature: GROK,
225
+ refactoring: GROK,
226
+ "bug-fix": FABLE,
227
+ "perf-issue": FABLE,
228
+ hillclimb: FABLE,
229
+ "judgment-and-prose": FABLE,
230
+ "hardest-tasks": FABLE,
231
+ "how-explorer": GROK,
232
+ "how-explainer": FABLE,
233
+ "why-investigators": GROK,
234
+ "why-synthesizer": FABLE,
235
+ "reflect-tooling": SOL,
236
+ "reflect-judgment": FABLE,
237
+ "swarm-workers": GROK,
238
+ "independent-verifier": "",
239
+ "poteto-agent": "",
240
+ "comment-sicko": "",
241
+ "how-critics": "",
242
+ "arena-runners": PANEL,
243
+ "arena-cross-judge-pool": PANEL,
244
+ "architect-runners": PANEL,
245
+ "interrogate-reviewers": PANEL
246
+ };
247
+ function potetoNoteCopy(role, prefix) {
248
+ const slugs = POTETO_DEFAULT_SLUGS[role];
249
+ return slugs.length === 0 ? "" : `${prefix}${slugs}`;
250
+ }
251
+ //#endregion
252
+ //#region src/client/PstackSettings.tsx
253
+ /** Plugin-owned pstack page inside the official Settings shell. */
254
+ const STYLE_ID = "pstack-dsh-settings-theme";
255
+ const GROUPS = [
256
+ {
257
+ id: "groupPlaybooks",
258
+ roles: [
259
+ "feature",
260
+ "refactoring",
261
+ "bug-fix",
262
+ "perf-issue",
263
+ "hillclimb",
264
+ "judgment-and-prose",
265
+ "hardest-tasks"
266
+ ]
267
+ },
268
+ {
269
+ id: "groupSkills",
270
+ roles: [
271
+ "how-explorer",
272
+ "how-explainer",
273
+ "why-investigators",
274
+ "why-synthesizer",
275
+ "reflect-tooling",
276
+ "reflect-judgment",
277
+ "swarm-workers"
278
+ ]
279
+ },
280
+ {
281
+ id: "groupVerify",
282
+ roles: [
283
+ "independent-verifier",
284
+ "poteto-agent",
285
+ "comment-sicko"
286
+ ]
287
+ },
288
+ {
289
+ id: "groupPanels",
290
+ roles: PANEL_ROLES.filter((role) => role !== "how-critics")
291
+ }
292
+ ];
293
+ const SETTINGS_CSS = `
294
+ .pstack-page { display:flex; flex-direction:column; gap:12px; max-width:720px; color:var(--dsw-alias-label-primary); }
295
+ .pstack-title { margin:0; font-size:16px; line-height:24px; font-weight:500; color:var(--dsw-alias-label-primary); }
296
+ .pstack-intro { margin:0; font-size:14px; line-height:22px; color:var(--dsw-alias-label-tertiary); }
297
+ .pstack-note { margin:0; font-size:12px; line-height:18px; color:var(--dsw-alias-label-tertiary); }
298
+ .pstack-warn { margin:0; font-size:12px; line-height:18px; color:var(--dsw-alias-state-warn-label); }
299
+ .pstack-error { margin:0; font-size:13px; line-height:20px; color:var(--dsw-alias-state-error-primary); }
300
+ .pstack-ok { margin:0; font-size:12px; line-height:18px; color:var(--dsw-alias-state-success-primary); }
301
+ .pstack-toolbar { display:flex; flex-wrap:wrap; gap:8px; align-items:center; }
302
+ .pstack-group { margin:12px 0 0; display:flex; flex-direction:column; gap:8px; }
303
+ .pstack-group-title { margin:0; font-size:12px; line-height:18px; font-weight:500; color:var(--dsw-alias-label-secondary); }
304
+ .pstack-card {
305
+ border:1px solid var(--dsw-alias-border-l2); border-radius:12px;
306
+ padding:12px 14px; display:flex; flex-direction:column; gap:10px;
307
+ background:var(--dsw-alias-bg-module-platform);
308
+ }
309
+ .pstack-card-head { display:flex; align-items:baseline; justify-content:space-between; gap:10px; flex-wrap:wrap; }
310
+ .pstack-role { margin:0; font-size:13px; line-height:20px; font-weight:500; color:var(--dsw-alias-label-primary); font-family:ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
311
+ .pstack-fields { display:flex; flex-wrap:wrap; gap:10px; align-items:flex-end; }
312
+ .pstack-field { display:flex; flex-direction:column; gap:4px; min-width:180px; flex:1; }
313
+ .pstack-label { font-size:12px; line-height:18px; color:var(--dsw-alias-label-secondary); }
314
+ .pstack-select {
315
+ height:34px; padding:0 12px; border:1px solid var(--dsw-alias-border-l2); border-radius:8px;
316
+ background:var(--dsw-alias-bg-layer-3); color:var(--dsw-alias-label-primary);
317
+ font:inherit; font-size:13px; line-height:20px;
318
+ }
319
+ .pstack-select:focus-visible { outline:none; border-color:var(--dsw-alias-brand-primary); }
320
+ .pstack-select:disabled { color:var(--dsw-alias-label-tertiary); cursor:default; }
321
+ .pstack-row { display:flex; flex-wrap:wrap; gap:10px; align-items:flex-end; }
322
+ .pstack-path { margin:0; font-size:12px; line-height:18px; color:var(--dsw-alias-label-tertiary); word-break:break-all; }
323
+ `;
324
+ function ensureThemeStyles() {
325
+ if (typeof document === "undefined") return;
326
+ if (document.getElementById(STYLE_ID) !== null) return;
327
+ const style = document.createElement("style");
328
+ style.id = STYLE_ID;
329
+ style.textContent = SETTINGS_CSS;
330
+ document.head.appendChild(style);
331
+ }
332
+ function overlaysEqual(left, right) {
333
+ return JSON.stringify(left) === JSON.stringify(right);
334
+ }
335
+ function RoleHead({ role, t }) {
336
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
337
+ className: "pstack-card-head",
338
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
339
+ className: "pstack-role",
340
+ children: role
341
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
342
+ className: "pstack-note",
343
+ children: potetoNoteCopy(role, t("potetoPrefix"))
344
+ })]
345
+ });
346
+ }
347
+ function firstSelectable(routes) {
348
+ const route = selectableRoutes(routes)[0];
349
+ if (route === void 0) return void 0;
350
+ return {
351
+ provider: route.provider,
352
+ model: route.model
353
+ };
354
+ }
355
+ function EffortSelect({ id, route, live, t, onChange }) {
356
+ const found = liveFor(live, route.provider, route.model);
357
+ if (found === void 0 || found.efforts.length === 0) return null;
358
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
359
+ className: "pstack-field",
360
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
361
+ className: "pstack-label",
362
+ htmlFor: id,
363
+ children: t("effort")
364
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
365
+ id,
366
+ className: "pstack-select",
367
+ value: route.reasoningEffort ?? "",
368
+ onChange: (event) => {
369
+ const idValue = event.target.value;
370
+ onChange(idValue.length === 0 ? {
371
+ provider: route.provider,
372
+ model: route.model
373
+ } : {
374
+ provider: route.provider,
375
+ model: route.model,
376
+ reasoningEffort: idValue
377
+ });
378
+ },
379
+ children: [
380
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
381
+ value: "",
382
+ children: t("effortOmit")
383
+ }),
384
+ route.reasoningEffort !== void 0 && !found.efforts.some((effort) => effort.id === route.reasoningEffort) ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("option", {
385
+ value: route.reasoningEffort,
386
+ disabled: true,
387
+ children: [
388
+ route.reasoningEffort,
389
+ " · ",
390
+ t("unavailable")
391
+ ]
392
+ }) : null,
393
+ found.efforts.map((effort) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
394
+ value: effort.id,
395
+ children: effort.name || effort.id
396
+ }, effort.id))
397
+ ]
398
+ })]
399
+ });
400
+ }
401
+ function RouteSelect({ id, value, live, t, disabled, onChange }) {
402
+ const selectable = selectableRoutes(live);
403
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
404
+ id,
405
+ className: "pstack-select",
406
+ value,
407
+ disabled,
408
+ onChange: (event) => {
409
+ onChange(event.target.value);
410
+ },
411
+ children: [
412
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
413
+ value: "inherit-parent",
414
+ children: t("inheritParent")
415
+ }),
416
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
417
+ value: "auto",
418
+ children: t("auto")
419
+ }),
420
+ value !== "inherit-parent" && value !== "auto" && !selectable.some((route) => routeKey(route.provider, route.model) === value) ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("option", {
421
+ value,
422
+ disabled: true,
423
+ children: [
424
+ value.replace("::", "/"),
425
+ " · ",
426
+ t("unavailable")
427
+ ]
428
+ }) : null,
429
+ selectable.map((route) => {
430
+ const key = routeKey(route.provider, route.model);
431
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("option", {
432
+ value: key,
433
+ children: [
434
+ route.provider,
435
+ "/",
436
+ route.model
437
+ ]
438
+ }, key);
439
+ })
440
+ ]
441
+ });
442
+ }
443
+ function PstackSettings({ t, subscribeCatalogChanges }) {
444
+ if (t === void 0) throw new Error("pstack settings requires its translation function");
445
+ const [drafts, setDrafts] = (0, react.useState)(void 0);
446
+ const [saved, setSaved] = (0, react.useState)(void 0);
447
+ const [live, setLive] = (0, react.useState)([]);
448
+ const [path, setPath] = (0, react.useState)("");
449
+ const [recommendOauth, setRecommendOauth] = (0, react.useState)(false);
450
+ const [selectableCount, setSelectableCount] = (0, react.useState)(0);
451
+ const [dropped, setDropped] = (0, react.useState)([]);
452
+ const [error, setError] = (0, react.useState)(void 0);
453
+ const [catalogError, setCatalogError] = (0, react.useState)(void 0);
454
+ const [notice, setNotice] = (0, react.useState)(void 0);
455
+ const [busy, setBusy] = (0, react.useState)(false);
456
+ const initialized = (0, react.useRef)(false);
457
+ const catalogRequest = (0, react.useRef)(void 0);
458
+ (0, react.useEffect)(() => {
459
+ ensureThemeStyles();
460
+ }, []);
461
+ const refresh = (0, react.useCallback)(async () => {
462
+ catalogRequest.current?.abort();
463
+ const request = new AbortController();
464
+ catalogRequest.current = request;
465
+ try {
466
+ const snapshot = await loadSettingsSnapshot(request.signal);
467
+ if (request.signal.aborted) return;
468
+ setLive(snapshot.catalog.routes);
469
+ setSelectableCount(snapshot.catalog.selectableCount);
470
+ setRecommendOauth(snapshot.catalog.recommendOauthLogin);
471
+ setPath(snapshot.path);
472
+ if (!initialized.current) {
473
+ setSaved(snapshot.overlay);
474
+ setDrafts(overlayToDraft(snapshot.overlay));
475
+ setDropped(snapshot.droppedRoles);
476
+ initialized.current = true;
477
+ }
478
+ setCatalogError(void 0);
479
+ } catch (caught) {
480
+ if (!request.signal.aborted) setCatalogError(caught instanceof Error ? caught.message : t("requestFailed"));
481
+ }
482
+ }, [t]);
483
+ (0, react.useEffect)(() => {
484
+ const reload = () => {
485
+ refresh();
486
+ };
487
+ const visible = () => {
488
+ if (document.visibilityState === "visible") reload();
489
+ };
490
+ const stop = subscribeCatalogChanges?.(reload);
491
+ window.addEventListener("focus", reload);
492
+ document.addEventListener("visibilitychange", visible);
493
+ reload();
494
+ return () => {
495
+ stop?.();
496
+ window.removeEventListener("focus", reload);
497
+ document.removeEventListener("visibilitychange", visible);
498
+ catalogRequest.current?.abort();
499
+ };
500
+ }, [refresh, subscribeCatalogChanges]);
501
+ const currentOverlay = (0, react.useMemo)(() => drafts === void 0 ? void 0 : draftToOverlay(drafts), [drafts]);
502
+ const dirty = saved !== void 0 && currentOverlay !== void 0 && !overlaysEqual(saved, currentOverlay);
503
+ const empty = selectableCount === 0;
504
+ const applyTargets = selectableRoutes(live);
505
+ const patchRole = (role, update) => {
506
+ setDrafts((current) => current?.map((draft) => draft.role === role ? update(draft) : draft));
507
+ setNotice(void 0);
508
+ };
509
+ const setScalarChoice = (role, value) => {
510
+ const parsed = parseRouteSelectValue(value, live);
511
+ patchRole(role, (draft) => {
512
+ if (parsed.inherit) return {
513
+ ...draft,
514
+ inherit: true,
515
+ inheritChoice: parsed.inheritChoice,
516
+ routes: []
517
+ };
518
+ return {
519
+ ...draft,
520
+ inherit: false,
521
+ inheritChoice: "inherit-parent",
522
+ routes: [stripIllegalEffort(parsed.route, live)]
523
+ };
524
+ });
525
+ };
526
+ const setPanelChoice = (role, index, value) => {
527
+ const parsed = parseRouteSelectValue(value, live);
528
+ patchRole(role, (draft) => {
529
+ if (parsed.inherit) return {
530
+ ...draft,
531
+ inherit: true,
532
+ inheritChoice: parsed.inheritChoice,
533
+ routes: []
534
+ };
535
+ const routes = draft.inherit ? [] : [...draft.routes];
536
+ routes[index] = stripIllegalEffort(parsed.route, live);
537
+ return {
538
+ ...draft,
539
+ inherit: false,
540
+ inheritChoice: "inherit-parent",
541
+ routes
542
+ };
543
+ });
544
+ };
545
+ const save = async () => {
546
+ if (currentOverlay === void 0) return;
547
+ setBusy(true);
548
+ setNotice(void 0);
549
+ setError(void 0);
550
+ try {
551
+ const result = await saveSettingsOverlay(currentOverlay);
552
+ setSaved(result.overlay);
553
+ setDrafts(overlayToDraft(result.overlay));
554
+ setDropped([]);
555
+ setError(void 0);
556
+ setNotice(t("saved"));
557
+ } catch (caught) {
558
+ setNotice(void 0);
559
+ setError(caught instanceof Error ? caught.message : t("requestFailed"));
560
+ } finally {
561
+ setBusy(false);
562
+ }
563
+ };
564
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
565
+ className: "pstack-page",
566
+ "aria-labelledby": "pstack-settings-title",
567
+ onFocusCapture: (event) => {
568
+ if (event.target instanceof HTMLSelectElement) refresh();
569
+ },
570
+ onPointerDownCapture: (event) => {
571
+ if (event.target instanceof HTMLSelectElement) refresh();
572
+ },
573
+ children: [
574
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
575
+ id: "pstack-settings-title",
576
+ className: "pstack-title",
577
+ children: t("title")
578
+ }),
579
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
580
+ className: "pstack-intro",
581
+ children: t("intro")
582
+ }),
583
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
584
+ className: "pstack-note",
585
+ children: t("catalogUpdates")
586
+ }),
587
+ error !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
588
+ className: "pstack-error",
589
+ children: error
590
+ }) : null,
591
+ catalogError !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
592
+ className: "pstack-error",
593
+ children: catalogError
594
+ }) : null,
595
+ notice !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
596
+ className: "pstack-ok",
597
+ role: "status",
598
+ children: notice
599
+ }) : null,
600
+ dropped.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
601
+ className: "pstack-warn",
602
+ children: t("dropped")
603
+ }) : null,
604
+ drafts === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
605
+ className: "pstack-note",
606
+ children: t("loading")
607
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
608
+ empty ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
609
+ className: "pstack-warn",
610
+ children: t("emptyCatalog")
611
+ }) : null,
612
+ recommendOauth ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
613
+ className: "pstack-note",
614
+ children: t("oauthRecommend")
615
+ }) : null,
616
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
617
+ className: "pstack-toolbar",
618
+ children: [
619
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
620
+ variant: "primary",
621
+ size: "sm",
622
+ disabled: busy || !dirty,
623
+ onClick: () => {
624
+ save();
625
+ },
626
+ children: busy ? t("saving") : t("save")
627
+ }),
628
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
629
+ variant: "outline",
630
+ size: "sm",
631
+ disabled: busy,
632
+ onClick: () => {
633
+ refresh();
634
+ },
635
+ children: t("reload")
636
+ }),
637
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
638
+ variant: "ghost",
639
+ size: "sm",
640
+ disabled: busy,
641
+ onClick: () => {
642
+ setDrafts((current) => current === void 0 ? current : applyInheritAll(current));
643
+ setNotice(void 0);
644
+ },
645
+ children: t("resetAll")
646
+ }),
647
+ applyTargets.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
648
+ className: "pstack-field",
649
+ style: { minWidth: 220 },
650
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
651
+ className: "pstack-label",
652
+ children: t("applyAll")
653
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
654
+ className: "pstack-select",
655
+ defaultValue: "",
656
+ disabled: busy,
657
+ onChange: (event) => {
658
+ const value = event.target.value;
659
+ event.target.value = "";
660
+ if (value.length === 0) return;
661
+ if (value === "inherit-parent") {
662
+ setDrafts((current) => current === void 0 ? current : applyInheritAll(current));
663
+ return;
664
+ }
665
+ const parsed = parseRouteSelectValue(value, live);
666
+ if (parsed.inherit) {
667
+ setDrafts((current) => current === void 0 ? current : applyInheritAll(current, parsed.inheritChoice));
668
+ return;
669
+ }
670
+ setDrafts((current) => current === void 0 ? current : applyRouteToAll(current, parsed.route, live));
671
+ },
672
+ children: [
673
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
674
+ value: "",
675
+ children: t("applyAll")
676
+ }),
677
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
678
+ value: "inherit-parent",
679
+ children: t("applyAllInherit")
680
+ }),
681
+ applyTargets.map((route) => {
682
+ const key = routeKey(route.provider, route.model);
683
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("option", {
684
+ value: key,
685
+ children: [
686
+ route.provider,
687
+ "/",
688
+ route.model
689
+ ]
690
+ }, key);
691
+ })
692
+ ]
693
+ })]
694
+ }) : null
695
+ ]
696
+ }),
697
+ GROUPS.map((group) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
698
+ className: "pstack-group",
699
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
700
+ className: "pstack-group-title",
701
+ children: t(group.id)
702
+ }), group.roles.map((role) => {
703
+ const draft = drafts.find((entry) => entry.role === role);
704
+ if (draft === void 0) return null;
705
+ if (!draft.panel) {
706
+ const route = draft.routes[0];
707
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("article", {
708
+ className: "pstack-card",
709
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(RoleHead, {
710
+ role,
711
+ t
712
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
713
+ className: "pstack-fields",
714
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
715
+ className: "pstack-field",
716
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
717
+ className: "pstack-label",
718
+ htmlFor: `pstack-role-${role}`,
719
+ children: role
720
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RouteSelect, {
721
+ id: `pstack-role-${role}`,
722
+ value: routeSelectValue(draft),
723
+ live,
724
+ t,
725
+ disabled: busy,
726
+ onChange: (value) => {
727
+ setScalarChoice(role, value);
728
+ }
729
+ })]
730
+ }), route !== void 0 && !draft.inherit ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EffortSelect, {
731
+ id: `pstack-effort-${role}`,
732
+ route,
733
+ live,
734
+ t,
735
+ onChange: (next) => {
736
+ patchRole(role, (current) => ({
737
+ ...current,
738
+ routes: [next]
739
+ }));
740
+ }
741
+ }) : null]
742
+ })]
743
+ }, role);
744
+ }
745
+ const rows = draft.inherit ? [] : draft.routes;
746
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("article", {
747
+ className: "pstack-card",
748
+ children: [
749
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RoleHead, {
750
+ role,
751
+ t
752
+ }),
753
+ draft.inherit ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
754
+ className: "pstack-field",
755
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
756
+ className: "pstack-label",
757
+ htmlFor: `pstack-role-${role}`,
758
+ children: t("inheritParent")
759
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RouteSelect, {
760
+ id: `pstack-role-${role}`,
761
+ value: draft.inheritChoice,
762
+ live: [],
763
+ t,
764
+ disabled: busy,
765
+ onChange: (value) => {
766
+ if (value === "inherit-parent" || value === "auto") patchRole(role, (current) => ({
767
+ ...current,
768
+ inherit: true,
769
+ inheritChoice: value,
770
+ routes: []
771
+ }));
772
+ }
773
+ })]
774
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
775
+ variant: "ghost",
776
+ size: "sm",
777
+ disabled: busy,
778
+ onClick: () => {
779
+ patchRole(role, (current) => ({
780
+ ...current,
781
+ inherit: true,
782
+ inheritChoice: "inherit-parent",
783
+ routes: []
784
+ }));
785
+ },
786
+ children: t("inheritParent")
787
+ }),
788
+ !draft.inherit ? rows.map((route, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
789
+ className: "pstack-row",
790
+ children: [
791
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
792
+ className: "pstack-field",
793
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
794
+ className: "pstack-label",
795
+ htmlFor: `pstack-panel-${role}-${index}`,
796
+ children: `${role}[${index}]`
797
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RouteSelect, {
798
+ id: `pstack-panel-${role}-${index}`,
799
+ value: routeSelectValue({
800
+ ...draft,
801
+ inherit: false,
802
+ routes: [route]
803
+ }),
804
+ live,
805
+ t,
806
+ disabled: busy || empty,
807
+ onChange: (value) => {
808
+ setPanelChoice(role, index, value);
809
+ }
810
+ })]
811
+ }),
812
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EffortSelect, {
813
+ id: `pstack-panel-effort-${role}-${index}`,
814
+ route,
815
+ live,
816
+ t,
817
+ onChange: (next) => {
818
+ patchRole(role, (current) => {
819
+ const nextRoutes = [...current.routes];
820
+ nextRoutes[index] = next;
821
+ return {
822
+ ...current,
823
+ inherit: false,
824
+ routes: nextRoutes
825
+ };
826
+ });
827
+ }
828
+ }),
829
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
830
+ variant: "ghost",
831
+ size: "sm",
832
+ disabled: busy,
833
+ onClick: () => {
834
+ patchRole(role, (current) => {
835
+ const nextRoutes = current.routes.filter((_, item) => item !== index);
836
+ return nextRoutes.length === 0 ? {
837
+ ...current,
838
+ inherit: true,
839
+ routes: []
840
+ } : {
841
+ ...current,
842
+ inherit: false,
843
+ routes: nextRoutes
844
+ };
845
+ });
846
+ },
847
+ children: t("removeRoute")
848
+ })
849
+ ]
850
+ }, `${role}-${index}`)) : null,
851
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
852
+ variant: "outline",
853
+ size: "sm",
854
+ disabled: busy || empty,
855
+ onClick: () => {
856
+ const added = firstSelectable(live);
857
+ if (added === void 0) return;
858
+ patchRole(role, (current) => ({
859
+ ...current,
860
+ inherit: false,
861
+ routes: [...current.inherit ? [] : current.routes, added]
862
+ }));
863
+ },
864
+ children: t("addRoute")
865
+ }) })
866
+ ]
867
+ }, role);
868
+ })]
869
+ }, group.id)),
870
+ path.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
871
+ className: "pstack-path",
872
+ children: [
873
+ t("overlayPath"),
874
+ ": ",
875
+ path
876
+ ]
877
+ }) : null
878
+ ] })
879
+ ]
880
+ });
881
+ }
882
+ //#endregion
883
+ //#region src/client/locales.ts
884
+ const en = {
885
+ nav: "pstack roles",
886
+ title: "pstack roles",
887
+ intro: "Map each pstack role onto a route that is already logged in on this DSH. Children inherit this conversation until you save a mapping. Writes $DSH_HOME/pstack-dsh.json, the same file spawn reads.",
888
+ loading: "Loading logged-in routes…",
889
+ save: "Save",
890
+ saving: "Saving…",
891
+ saved: "Saved. New pstack_spawn calls pick this up.",
892
+ reload: "Refresh models",
893
+ catalogUpdates: "Model choices update automatically after login or model changes. Unsaved role settings are preserved.",
894
+ unavailable: "currently unavailable",
895
+ resetAll: "Inherit for every role",
896
+ inheritParent: "inherit-parent",
897
+ auto: "auto",
898
+ potetoPrefix: "Poteto 0.15 recommendation: ",
899
+ emptyCatalog: "No logged-in route. Every role inherits this conversation. Add a provider API key in Settings → Models.",
900
+ oauthRecommend: "Subscription logins (ChatGPT, Claude, Grok, Copilot, OpenRouter, Kimi, Google Antigravity) show up here after you install and sign in with dsh-oauth-login or dsh-antigravity-oauth. Not required for API keys.",
901
+ effort: "Effort",
902
+ effortOmit: "omit (adapter default)",
903
+ addRoute: "Add route",
904
+ removeRoute: "Remove",
905
+ applyAll: "Apply to every role",
906
+ applyAllInherit: "Inherit parent for every role",
907
+ overlayPath: "Overlay",
908
+ dropped: "Some saved mappings pointed at routes that are no longer logged in. Those roles now inherit until you save again.",
909
+ requestFailed: "The settings request failed.",
910
+ groupPlaybooks: "Playbook delegates",
911
+ groupSkills: "Skill roles",
912
+ groupVerify: "Verify and helpers",
913
+ groupPanels: "Panel roles"
914
+ };
915
+ const zh = {
916
+ nav: "pstack 角色",
917
+ title: "pstack 角色",
918
+ intro: "把每个 pstack 角色映射到本机已经登录的路由。未保存前,子 agent 继承当前对话。写入 $DSH_HOME/pstack-dsh.json,与 spawn 读的是同一份文件。",
919
+ loading: "正在加载已登录路由…",
920
+ save: "保存",
921
+ saving: "保存中…",
922
+ saved: "已保存。之后的 pstack_spawn 会读到这份 overlay。",
923
+ reload: "刷新模型列表",
924
+ catalogUpdates: "登录或模型变更后自动更新列表,不会覆盖未保存的角色设置。",
925
+ unavailable: "暂不可用",
926
+ resetAll: "全部继承父对话",
927
+ inheritParent: "inherit-parent",
928
+ auto: "auto",
929
+ potetoPrefix: "Poteto 0.15 推荐:",
930
+ emptyCatalog: "没有已登录路由。每个角色都继承当前对话。请先在 设置 → 模型 里配置 API key。",
931
+ oauthRecommend: "订阅登录(ChatGPT / Claude / Grok / Copilot / OpenRouter / Kimi / Google Antigravity)要出现在这里,需要另装并登录 dsh-oauth-login 或 dsh-antigravity-oauth。只用 API key 可以不装。",
932
+ effort: "Effort",
933
+ effortOmit: "省略(适配器默认)",
934
+ addRoute: "添加路由",
935
+ removeRoute: "移除",
936
+ applyAll: "应用到全部角色",
937
+ applyAllInherit: "全部角色继承父对话",
938
+ overlayPath: "Overlay",
939
+ dropped: "有些已保存的映射指向了不再登录的路由。这些角色已改回继承,保存后才会写盘。",
940
+ requestFailed: "设置请求失败。",
941
+ groupPlaybooks: "玩法委派",
942
+ groupSkills: "技能角色",
943
+ groupVerify: "核验与助手",
944
+ groupPanels: "面板角色"
945
+ };
946
+ //#endregion
947
+ //#region src/client/index.tsx
948
+ const name = "pstack-dsh-client";
949
+ const inject = [
950
+ "slots",
951
+ "locale",
952
+ "remote"
953
+ ];
954
+ function apply(ctx) {
955
+ const namespace = "settings.pstack";
956
+ ctx.effect(() => ctx.locale.register(namespace, {
957
+ zh,
958
+ en
959
+ }), "pstack-dsh: settings copy");
960
+ const t = ctx.locale.bind(namespace);
961
+ const subscribeCatalogChanges = (listener) => listenForCatalogChanges(ctx, listener);
962
+ ctx.slots.inject("settings.section", () => ctx.slots.register({
963
+ name: "settings.section",
964
+ id: SETTINGS_SECTION_ID,
965
+ order: 16,
966
+ label: () => t("nav"),
967
+ inject: () => ({
968
+ t,
969
+ subscribeCatalogChanges
970
+ })
971
+ }, PstackSettings));
972
+ }
973
+ //#endregion
974
+ exports.apply = apply;
975
+ exports.inject = inject;
976
+ exports.name = name;
977
+ return module.exports;
978
+ }
979
+ });
980
+
981
+ //# sourceMappingURL=client.js.map