@yadsh/dsh-qa-surface 0.1.1 → 0.2.0

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 (89) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/README.md +162 -14
  3. package/SPEC-dsh-qa-surface.md +600 -96
  4. package/capability-policy.json +5 -0
  5. package/compatibility.json +7 -1
  6. package/cordis.patch.yml +11 -0
  7. package/docs/ARCHITECTURE.md +49 -7
  8. package/docs/COMPATIBILITY.md +5 -4
  9. package/docs/CONFIGURATION.md +96 -2
  10. package/lib/attestation.js +10 -0
  11. package/lib/attestation.js.map +1 -0
  12. package/lib/client/QaConfigController.js +111 -4
  13. package/lib/client/QaConfigController.js.map +1 -1
  14. package/lib/client/QaSessionController.js +501 -119
  15. package/lib/client/QaSessionController.js.map +1 -1
  16. package/lib/client/QaSurface.js +137 -20
  17. package/lib/client/QaSurface.js.map +1 -1
  18. package/lib/client/QaTranscriptAdapter.js +534 -45
  19. package/lib/client/QaTranscriptAdapter.js.map +1 -1
  20. package/lib/client/attestation.js +60 -0
  21. package/lib/client/attestation.js.map +1 -0
  22. package/lib/client/chat-index.js +86 -0
  23. package/lib/client/chat-index.js.map +1 -0
  24. package/lib/client/components/Markdown.js +75 -5
  25. package/lib/client/components/Markdown.js.map +1 -1
  26. package/lib/client/components/QaAgentsDrawer.js +40 -0
  27. package/lib/client/components/QaAgentsDrawer.js.map +1 -0
  28. package/lib/client/components/QaComposer.js +132 -15
  29. package/lib/client/components/QaComposer.js.map +1 -1
  30. package/lib/client/components/QaMessage.js +184 -10
  31. package/lib/client/components/QaMessage.js.map +1 -1
  32. package/lib/client/components/QaSidebar.js +124 -0
  33. package/lib/client/components/QaSidebar.js.map +1 -0
  34. package/lib/client/components/QaSourcesDrawer.js +46 -0
  35. package/lib/client/components/QaSourcesDrawer.js.map +1 -0
  36. package/lib/client/components/QaWorkGroup.js +135 -0
  37. package/lib/client/components/QaWorkGroup.js.map +1 -0
  38. package/lib/client/components/VariantSwitcher.js +29 -0
  39. package/lib/client/components/VariantSwitcher.js.map +1 -0
  40. package/lib/client/components/format.js +48 -0
  41. package/lib/client/components/format.js.map +1 -0
  42. package/lib/client/index.js +77 -34
  43. package/lib/client/index.js.map +1 -1
  44. package/lib/client/styles.js +308 -43
  45. package/lib/client/styles.js.map +1 -1
  46. package/lib/client/types.js +13 -0
  47. package/lib/client/types.js.map +1 -0
  48. package/lib/client/wait-for.js +49 -0
  49. package/lib/client/wait-for.js.map +1 -0
  50. package/lib/client.js +8228 -383
  51. package/lib/client.js.map +1 -1
  52. package/lib/config.js +61 -9
  53. package/lib/config.js.map +1 -1
  54. package/lib/index.js +166 -70
  55. package/lib/index.js.map +1 -1
  56. package/lib/lockdown-policy.js +20 -0
  57. package/lib/lockdown-policy.js.map +1 -0
  58. package/lib/resolve-config.js +122 -10
  59. package/lib/resolve-config.js.map +1 -1
  60. package/lib/secure-session.js +170 -0
  61. package/lib/secure-session.js.map +1 -0
  62. package/lib/typert.host.d.ts +3 -0
  63. package/lib/typert.host.js +191 -0
  64. package/lib/typert.remote-client.d.ts +24 -0
  65. package/lib/typert.remote-client.js +129 -0
  66. package/lib/types/attestation.d.ts +17 -0
  67. package/lib/types/client/QaConfigController.d.ts +34 -2
  68. package/lib/types/client/QaSessionController.d.ts +106 -19
  69. package/lib/types/client/QaSurface.d.ts +5 -4
  70. package/lib/types/client/QaTranscriptAdapter.d.ts +17 -2
  71. package/lib/types/client/attestation.d.ts +25 -0
  72. package/lib/types/client/chat-index.d.ts +28 -0
  73. package/lib/types/client/components/Markdown.d.ts +7 -3
  74. package/lib/types/client/components/QaAgentsDrawer.d.ts +25 -0
  75. package/lib/types/client/components/QaComposer.d.ts +12 -2
  76. package/lib/types/client/components/QaMessage.d.ts +14 -1
  77. package/lib/types/client/components/QaSidebar.d.ts +41 -0
  78. package/lib/types/client/components/QaSourcesDrawer.d.ts +8 -0
  79. package/lib/types/client/components/QaWorkGroup.d.ts +19 -0
  80. package/lib/types/client/components/VariantSwitcher.d.ts +19 -0
  81. package/lib/types/client/components/format.d.ts +9 -0
  82. package/lib/types/client/index.d.ts +1 -5
  83. package/lib/types/client/types.d.ts +29 -0
  84. package/lib/types/client/wait-for.d.ts +11 -0
  85. package/lib/types/index.d.ts +22 -6
  86. package/lib/types/lockdown-policy.d.ts +18 -0
  87. package/lib/types/secure-session.d.ts +22 -0
  88. package/lib/types/types.d.ts +148 -1
  89. package/package.json +29 -3
@@ -0,0 +1,5 @@
1
+ {
2
+ "version": 1,
3
+ "description": "Reviewed capabilities in the shipped default QA tool allow-list.",
4
+ "tools": []
5
+ }
@@ -8,7 +8,13 @@
8
8
  "connection.api.sessions",
9
9
  "sessions.binding",
10
10
  "settingsScope",
11
- "webServer.register"
11
+ "webServer.register",
12
+ "typert.remote",
13
+ "agentPresets.composedPreset",
14
+ "permissionPresets.set",
15
+ "tools.restrict",
16
+ "tools.guard",
17
+ "workspaceRegistry.get"
12
18
  ]
13
19
  },
14
20
  "node": "^22.19.0 || >=24.0.0"
package/cordis.patch.yml CHANGED
@@ -7,3 +7,14 @@
7
7
  route:
8
8
  path: /qa
9
9
  matchChildren: true
10
+ ui:
11
+ showReset: false
12
+ lockdown:
13
+ enabled: true
14
+ sandboxMode: read-only
15
+ approvalPolicy: never
16
+ permissionPreset: qa-read-only
17
+ allowSessionReset: false
18
+ toolPolicy:
19
+ mode: allow-list
20
+ allow: []
@@ -4,20 +4,62 @@ The Host half validates the Loader configuration, registers the `qa-surface`
4
4
  settings namespace and owns one narrow GET/HEAD route for the configured QA
5
5
  path. Published DSH `0.1.1-rc.2` returns 404 for unknown frontend paths, so the
6
6
  route redirects navigation through the canonical `/` index with an encoded
7
- same-origin path marker. It does not serve HTML, create another server, replace
8
- the frontend fallback, or touch API/plugin routes. The browser removes the
7
+ same-origin path marker. It also exposes one typed
8
+ `secureSession(sessionId)` operation whose policy is read only from Host
9
+ settings. The entry delegates that operation to `QaPolicyAdmission`
10
+ (`secure-session.ts`), the Host-side admission boundary. It does not serve
11
+ HTML, create another server, replace the frontend fallback, or touch
12
+ API/plugin routes. The browser removes the
9
13
  marker and restores the requested path with `history.replaceState` before
10
- route matching. The Host creates no sessions.
14
+ route matching. The Host creates no sessions itself.
11
15
 
12
16
  The browser half registers `QaSurface` in the root-scoped `shell.overlay` list.
13
17
  `QaRouteController` keeps that entry dormant outside the configured path and
14
18
  reversibly observes `pushState`, `replaceState` and `popstate`.
15
19
 
16
- `QaSessionController` is the only DSH session-coupled module. It uses
20
+ `QaSessionController` is the only browser-side DSH session-coupled module. It uses
17
21
  `connection.api.sessions.create/selectModel` for creation policy and the public
18
- `SessionFace` for prompt, cancel and snapshots. `QaTranscriptAdapter` projects
19
- those snapshots to plugin-local messages, excluding reasoning, tool arguments,
20
- tool results, system context and raw failures.
22
+ `SessionFace` for prompt, cancel and snapshots; the shared client contracts and
23
+ the idle state live in `client/types.ts`. Its supporting modules are pure
24
+ helpers: `client/wait-for.ts` waits on observable stores, `client/chat-index.ts`
25
+ (`QaChatIndex`) keeps the browser-local chat index and persisted active
26
+ session in storage, and `client/attestation.ts` parses Host reason markers and
27
+ validates proofs against the deployed lockdown config. `QaTranscriptAdapter`
28
+ projects session snapshots to plugin-local messages. "New chat" enters a
29
+ draft that materializes an attested session only when the first prompt is
30
+ sent, and the chat list orders by the host's `updatedAt`. The log is
31
+ append-only and there is no truncation seam, so regeneration prompts a
32
+ hidden instruction and projects the follow-up turns as variants of one
33
+ question; the same projection flattens tool activity into the sources
34
+ drawer (web targets, searches, files read). Subagent delegation, when the
35
+ deployment opts it in, renders launches and settlement notices inline, and
36
+ the agents drawer opens a child session as a read-only live transcript: the
37
+ binding skips attestation and every send path stays closed. By default it excludes
38
+ reasoning, tool arguments and tool results. When explicitly enabled, it
39
+ correlates assistant blocks, paired tool results, running calls and turn
40
+ timings into one plugin-local work group per turn; `QaWorkGroup` owns
41
+ disclosure state and collapses the group when the turn completes. System
42
+ context and raw failures remain excluded.
43
+
44
+ In locked mode the Host operation verifies immutable session composition,
45
+ refuses to adopt a non-QA session with user history, validates the named
46
+ permission preset, installs `ToolRestriction.allow`, installs an agent-scoped
47
+ monotonic execution guard, selects the permission preset, and returns only a
48
+ sanitized proof. The controller remains non-writable until every proof field
49
+ matches its Host-delivered config and repeats the check before prompt
50
+ admission. No private RPC handler, slash command, direct provider API, or DSH
51
+ core patch is used.
52
+
53
+ This narrows a QA agent's effective session/tool policy, but a route overlay on
54
+ a shared privileged Host is not an authorization boundary for other DSH
55
+ clients. Strong isolation requires a dedicated process/profile, restricted
56
+ identity and network boundary.
57
+
58
+ All interaction colors come from the company interaction palette
59
+ ("Цвета взаимодействия"), defined once as the `QA_BRAND_PALETTE` object at the
60
+ top of `styles.ts` and emitted as `--dsh-qa-*` custom properties on the
61
+ overlay root; surfaces and typography keep using the themed `--dsw-alias-*`
62
+ tokens so light and dark hosts stay coherent.
21
63
 
22
64
  The overlay locks document scrolling and contains keyboard focus while active.
23
65
  It does not locate AppFrame through generated CSS classes and does not dispose
@@ -1,12 +1,13 @@
1
1
  # Compatibility
2
2
 
3
- | Plugin version | Tested DSH release | Required public contracts |
4
- | -------------- | ------------------ | ----------------------------------------------------------------------------------------------------- |
5
- | 0.1.x | 0.1.1-rc.2 | `shell.overlay`, `settingsScope`, `connection.api.sessions`, `sessions.binding`, `webServer.register` |
3
+ | Plugin version | Tested DSH release | Required public contracts |
4
+ | -------------- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
5
+ | 0.1.x | 0.1.1-rc.2 | `shell.overlay`, Typert remote, `agentPresets.composedPreset`, `permissionPresets`, agent-scoped `tools.restrict/guard`, `workspaceRegistry`, session/model APIs, `webServer.register` |
6
6
 
7
7
  DSH is developer-preview software. Compatibility-sensitive calls are isolated
8
8
  in `QaSessionController`, `QaTranscriptAdapter`, `QaConfigController` and
9
- `QaRouteController`. The Host navigation adapter also works around this tested
9
+ `QaRouteController`; Host lockdown coupling is isolated in
10
+ `QaSurface.secureSession`. The Host navigation adapter also works around this tested
10
11
  release's exact-index static serving: `/qa` is redirected through `/`, then the
11
12
  client restores the original pathname. Missing settings fall back to default
12
13
  browser config; missing required client services prevent the browser plugin
@@ -10,9 +10,103 @@ rules are:
10
10
  - `maxContentWidth` is an integer from 480 through 1600;
11
11
  - duplicate/blank suggested questions are removed;
12
12
  - approval and question policies are fixed to safe blocking behavior;
13
- - reasoning display cannot be enabled in the 0.1.x MVP.
13
+ - reasoning and tool details are opt-in through `ui.showReasoning` and
14
+ `ui.showToolActivity`; enable them only where those contents are appropriate
15
+ for the QA audience;
16
+ - lockdown defaults to enabled and requires a non-empty permission preset;
17
+ - the preset must resolve on the Host to exactly `read-only` + `never`;
18
+ - permission, slash-command, settings, rename, delete and arbitrary-open
19
+ capability flags cannot be enabled;
20
+ - `showReset` requires the independent `allowSessionReset` opt-in;
21
+ - the tool policy is an allow-list; unknown configured tool names fail closed.
22
+ A name only resolves while its tool is actually mounted: MCP tools
23
+ (`mcp__<server>__*`) exist only while their server is reachable, so keep
24
+ them out of the allow list on hosts that cannot reach the server. Tools
25
+ mounted by an agent preset live in that preset's ancestor scope; the Host
26
+ validates and restricts the complete agent-scoped view, not just globals.
27
+
28
+ ## Pinning chats to a directory
29
+
30
+ By default a QA chat is created against the Host working directory. Two
31
+ mutually exclusive pins anchor every new chat (and its subagents) to the
32
+ deployment's own directory:
33
+
34
+ - `session.cwd: "D:/qa-docs"` - an absolute directory used directly as the
35
+ session cwd; no registration needed. Attestation compares the session's
36
+ recorded cwd case- and separator-insensitively on Windows.
37
+ - `session.workspaceId: "<uuid>"` - a registered DSH workspace (created in
38
+ the web UI or via the workspace API; the id is a generated uuid, not the
39
+ path). Sessions attach to the workspace, so they group under it in the
40
+ host UI. When the id does not resolve, attestation refuses with
41
+ `reason: workspace-unavailable` instead of an opaque mismatch.
42
+
43
+ With `lockdown.enforceFixedWorkspace: true` (the default) a chat created
44
+ anywhere else refuses to attest, so the QA audience can never pull the
45
+ assistant out of the pinned directory.
14
46
 
15
47
  Browser persistence stores only the DSH session id under
16
- `<storageKey>:v1:<route>:session`. Transcript content, credentials and tool
48
+ `<storageKey>:v1:<route>:session`, plus — when `ui.showSessionList` is
49
+ enabled — a per-browser chat index under `<storageKey>:v1:<route>:chats`
50
+ (session ids only, capped at 50). Transcript content, credentials and tool
17
51
  results remain in the Host-owned DSH Session and are never copied to browser
18
52
  storage.
53
+
54
+ When either work-detail flag is enabled, the QA transcript groups reasoning,
55
+ intermediate assistant progress, and tool rows by DSH turn. Running work is
56
+ expanded. Completed work is collapsed behind a duration summary and can be
57
+ reopened; each tool row can separately reveal its formatted input and output.
58
+ These controls change presentation only and never widen the Host allow-list.
59
+
60
+ The browser cannot override lockdown settings. Before binding and immediately
61
+ before every prompt, it requests a Host attestation for the selected session.
62
+ Any unproved agent preset, workspace, model, permission bundle or tool policy
63
+ disables Send with the generic message `Настройки помощника недоступны.`
64
+ Detailed mismatch facts are written only to Host logs; the
65
+ browser console additionally prints one line with a stable coarse reason code
66
+ (`reason: unknown-tools`, `workspace-unavailable`, `composition-mismatch`, `permission-preset`,
67
+ `adoption-refused`, `proof-mismatch` or `attestation-failed`) plus an operator
68
+ hint, so a refused surface can be diagnosed without Host log access.
69
+
70
+ The built-in branding, controls, status messages and accessibility labels are
71
+ Russian. The default quick questions are rendered directly above the composer
72
+ only while the current chat is empty. Set `suggestedQuestions: []` to hide
73
+ them, or provide a deployment-specific list to replace them.
74
+
75
+ When adding tools, update the deployment's reviewed capability inventory as
76
+ part of the same change. The package's
77
+ [default inventory](../capability-policy.json) is intentionally empty, matching
78
+ the default `toolPolicy.allow`.
79
+
80
+ ## Configuration channel over the LAN
81
+
82
+ The browser normally reads the effective configuration from the Host-owned
83
+ `qa-surface` settings namespace. DSH pins settings RPCs to loopback, so a
84
+ browser served over the LAN always sees that namespace as unavailable. In
85
+ that case the client calls the plugin's `qaSurface/describe` Host Remote and
86
+ uses the returned effective configuration; a rejected call falls back to the
87
+ client defaults with the same `unavailable` status as before. Only one
88
+ describe request runs per page load, and a settled answer survives scope
89
+ updates — the namespace (when readable) stays the authority and keeps
90
+ delivering live changes.
91
+
92
+ Host-side enforcement never depended on the browser's read path: `secureSession`
93
+ attestation re-derives everything from the Host-owned configuration on every
94
+ bind and every prompt.
95
+
96
+ ## Skill catalog scope
97
+
98
+ The deployment's agent preset controls which skills the QA assistant sees.
99
+ The shipped `qa-research` preset mounts the skill filesystem with
100
+ `includeDefaultRoots: false`: project-root skills (for example the harness
101
+ checkout's own `.dsh/skills`) and user-home skills stay out of the catalog,
102
+ and skills enter only through plugin providers or an explicit
103
+ `customSkillDirs` list in the preset. Keep the QA catalog to exactly the
104
+ skills the audience is meant to use.
105
+
106
+ ## Deleting chats
107
+
108
+ The sidebar delete control removes a chat from this browser's index only;
109
+ the Host session stays on disk. Deleting the chat that is currently open
110
+ continues in a fresh attested session when `lockdown.allowSessionReset` is
111
+ enabled. There is no Host session-deletion API in DSH 0.1.x for the plugin
112
+ to call.
@@ -0,0 +1,10 @@
1
+ /** Host rejection whose wire message carries the coarse reason marker. */
2
+ export class QaAttestationError extends Error {
3
+ reason;
4
+ constructor(reason, message) {
5
+ super(message);
6
+ this.reason = reason;
7
+ this.name = "QaAttestationError";
8
+ }
9
+ }
10
+ //# sourceMappingURL=attestation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attestation.js","sourceRoot":"","sources":["../src/attestation.ts"],"names":[],"mappings":"AAmBA,0EAA0E;AAC1E,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAEhC,MAAM;IADjB,YACW,MAA2B,EACpC,OAAe;QAEf,KAAK,CAAC,OAAO,CAAC,CAAC;sBAHN,MAAM;QAIf,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACnC,CAAC;CACF"}
@@ -1,14 +1,29 @@
1
1
  import { DEFAULT_QA_SURFACE_CONFIG, resolveConfig } from "../resolve-config.js";
2
- /** Browser projection of the Host-owned qa-surface settings namespace. */
2
+ /**
3
+ * Browser projection of the Host-owned qa-surface settings namespace.
4
+ *
5
+ * The DSH gateway pins settings RPCs to loopback, so a browser served over the
6
+ * LAN always sees the namespace as `unavailable`. When the caller supplies the
7
+ * `qaSurface/describe` Remote as a fallback, that channel answers instead: the
8
+ * projection waits in `loading` until it settles, then reports the Host-owned
9
+ * configuration as `ready`. A rejected fallback returns the projection to
10
+ * `unavailable`, exactly as when no fallback exists.
11
+ */
3
12
  export class QaConfigController {
4
13
  scope;
5
14
  listeners = new Set();
6
15
  snapshot;
7
16
  unsubscribe;
8
- constructor(scope) {
17
+ fallback;
18
+ fallbackState = "idle";
19
+ fallbackConfig;
20
+ disposed = false;
21
+ constructor(scope, fallback) {
9
22
  this.scope = scope;
23
+ this.fallback = fallback;
10
24
  this.snapshot = this.project();
11
25
  this.unsubscribe = scope.subscribe(() => this.refresh());
26
+ this.refresh();
12
27
  }
13
28
  getSnapshot = () => this.snapshot;
14
29
  subscribe = (listener) => {
@@ -16,6 +31,7 @@ export class QaConfigController {
16
31
  return () => this.listeners.delete(listener);
17
32
  };
18
33
  dispose() {
34
+ this.disposed = true;
19
35
  this.unsubscribe();
20
36
  this.listeners.clear();
21
37
  }
@@ -29,6 +45,22 @@ export class QaConfigController {
29
45
  };
30
46
  }
31
47
  if (settings.status === "unavailable") {
48
+ if ((this.fallbackState === "ready" ||
49
+ this.fallbackState === "refreshing") &&
50
+ this.fallbackConfig !== undefined) {
51
+ return {
52
+ status: "ready",
53
+ config: this.fallbackConfig,
54
+ error: null,
55
+ };
56
+ }
57
+ if (this.fallbackState === "pending") {
58
+ return {
59
+ status: "loading",
60
+ config: DEFAULT_QA_SURFACE_CONFIG,
61
+ error: null,
62
+ };
63
+ }
32
64
  return {
33
65
  status: "unavailable",
34
66
  config: DEFAULT_QA_SURFACE_CONFIG,
@@ -46,12 +78,16 @@ export class QaConfigController {
46
78
  return {
47
79
  status: "error",
48
80
  config: DEFAULT_QA_SURFACE_CONFIG,
49
- error: "The assistant configuration is unavailable.",
81
+ error: "Настройки помощника недоступны.",
50
82
  };
51
83
  }
52
84
  }
53
85
  refresh() {
54
- const next = this.project();
86
+ this.requestFallbackIfNeeded();
87
+ const projected = this.project();
88
+ const next = JSON.stringify(projected.config) === JSON.stringify(this.snapshot.config)
89
+ ? { ...projected, config: this.snapshot.config }
90
+ : projected;
55
91
  if (next.status === this.snapshot.status &&
56
92
  next.config === this.snapshot.config &&
57
93
  next.error === this.snapshot.error) {
@@ -61,5 +97,76 @@ export class QaConfigController {
61
97
  for (const listener of this.listeners)
62
98
  listener();
63
99
  }
100
+ /**
101
+ * Re-read the Host configuration after a Host reconnect. Without this, an
102
+ * open page keeps the configuration it fetched at load time: after the Host
103
+ * restarts with a changed deployment config, the next attestation compares
104
+ * its proof against the stale client copy and refuses. While re-reading,
105
+ * the previous answer stays projected — no loading flicker; the snapshot
106
+ * updates only when the answer actually changed.
107
+ */
108
+ refreshFallback() {
109
+ if (this.disposed ||
110
+ this.fallback === undefined ||
111
+ this.fallbackState === "idle" ||
112
+ this.fallbackState === "pending" ||
113
+ this.scope.getSnapshot().status === "ready") {
114
+ return;
115
+ }
116
+ this.fallbackState = "refreshing";
117
+ void this.fallback().then((config) => {
118
+ if (this.disposed)
119
+ return;
120
+ try {
121
+ this.fallbackConfig = resolveConfig(config);
122
+ }
123
+ catch {
124
+ // A malformed answer must not wipe a working previous one.
125
+ }
126
+ this.fallbackState = "ready";
127
+ // refresh() keeps the old projection when the answer is unchanged.
128
+ this.refresh();
129
+ }, (error) => {
130
+ if (this.disposed)
131
+ return;
132
+ console.warn("dsh-qa-surface: Host configuration refresh failed", error);
133
+ this.fallbackState = "ready";
134
+ });
135
+ }
136
+ /**
137
+ * The fallback trigger rides every refresh: the scope flips to
138
+ * `unavailable` whenever the browser is served over the LAN, which a
139
+ * constructor-time check can miss. The state guard makes repeats a no-op,
140
+ * so one fetch runs per controller lifetime; the recursive refresh lets the
141
+ * pending state surface before the first notification pass.
142
+ */
143
+ requestFallbackIfNeeded() {
144
+ if (this.disposed ||
145
+ this.fallback === undefined ||
146
+ this.fallbackState !== "idle" ||
147
+ this.scope.getSnapshot().status !== "unavailable") {
148
+ return;
149
+ }
150
+ this.fallbackState = "pending";
151
+ this.refresh();
152
+ void this.fallback().then((config) => {
153
+ if (this.disposed)
154
+ return;
155
+ try {
156
+ this.fallbackConfig = resolveConfig(config);
157
+ this.fallbackState = "ready";
158
+ }
159
+ catch {
160
+ this.fallbackState = "failed";
161
+ }
162
+ this.refresh();
163
+ }, (error) => {
164
+ if (this.disposed)
165
+ return;
166
+ console.warn("dsh-qa-surface: Host configuration is unavailable", error);
167
+ this.fallbackState = "failed";
168
+ this.refresh();
169
+ });
170
+ }
64
171
  }
65
172
  //# sourceMappingURL=QaConfigController.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"QaConfigController.js","sourceRoot":"","sources":["../../src/client/QaConfigController.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,yBAAyB,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAShF,0EAA0E;AAC1E,MAAM,OAAO,kBAAkB;IAKA,KAAK;IAJjB,SAAS,GAAG,IAAI,GAAG,EAAc,CAAC;IAC3C,QAAQ,CAAmB;IAClB,WAAW,CAAa;IAEzC,YAA6B,KAAqC;qBAArC,KAAK;QAChC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAC/B,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;IAC3D,CAAC;IAED,WAAW,GAAG,GAAqB,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC;IAEpD,SAAS,GAAG,CAAC,QAAoB,EAAgB,EAAE;QACjD,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC7B,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC/C,CAAC,CAAC;IAEF,OAAO;QACL,IAAI,CAAC,WAAW,EAAE,CAAC;QACnB,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;IACzB,CAAC;IAEO,OAAO;QACb,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC;QAC1C,IAAI,QAAQ,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAClC,OAAO;gBACL,MAAM,EAAE,SAAS;gBACjB,MAAM,EAAE,yBAAyB;gBACjC,KAAK,EAAE,IAAI;aACZ,CAAC;QACJ,CAAC;QACD,IAAI,QAAQ,CAAC,MAAM,KAAK,aAAa,EAAE,CAAC;YACtC,OAAO;gBACL,MAAM,EAAE,aAAa;gBACrB,MAAM,EAAE,yBAAyB;gBACjC,KAAK,EAAE,IAAI;aACZ,CAAC;QACJ,CAAC;QACD,IAAI,CAAC;YACH,OAAO;gBACL,MAAM,EAAE,OAAO;gBACf,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,KAAK,IAAI,EAAE,CAAC;gBAC3C,KAAK,EAAE,IAAI;aACZ,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC;YACP,OAAO;gBACL,MAAM,EAAE,OAAO;gBACf,MAAM,EAAE,yBAAyB;gBACjC,KAAK,EAAE,6CAA6C;aACrD,CAAC;QACJ,CAAC;IACH,CAAC;IAEO,OAAO;QACb,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAC5B,IACE,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,QAAQ,CAAC,MAAM;YACpC,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,QAAQ,CAAC,MAAM;YACpC,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,QAAQ,CAAC,KAAK,EAClC,CAAC;YACD,OAAO;QACT,CAAC;QACD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,SAAS;YAAE,QAAQ,EAAE,CAAC;IACpD,CAAC;CACF"}
1
+ {"version":3,"file":"QaConfigController.js","sourceRoot":"","sources":["../../src/client/QaConfigController.ts"],"names":[],"mappings":"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"}