@yadsh/dsh-qa-surface 0.17.0 → 0.18.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.
- package/README.md +15 -3
- package/compatibility.json +1 -1
- package/lib/account-remotes.js +4 -0
- package/lib/account-remotes.js.map +1 -1
- package/lib/accounts/database.js +86 -1
- package/lib/accounts/database.js.map +1 -1
- package/lib/accounts/file.js.map +1 -1
- package/lib/accounts/store.js +111 -5
- package/lib/accounts/store.js.map +1 -1
- package/lib/accounts/token.js +8 -2
- package/lib/accounts/token.js.map +1 -1
- package/lib/admin/metrics.js +15 -2
- package/lib/admin/metrics.js.map +1 -1
- package/lib/admin/read-budget.js +28 -0
- package/lib/admin/read-budget.js.map +1 -0
- package/lib/admin/service.js +135 -40
- package/lib/admin/service.js.map +1 -1
- package/lib/admin/session-log.js +63 -4
- package/lib/admin/session-log.js.map +1 -1
- package/lib/chat-sharing/native-fence.js +20 -0
- package/lib/chat-sharing/native-fence.js.map +1 -1
- package/lib/chat-sharing/transport.js +8 -2
- package/lib/chat-sharing/transport.js.map +1 -1
- package/lib/chat-sharing/uploads.js +79 -6
- package/lib/chat-sharing/uploads.js.map +1 -1
- package/lib/cli.js +13 -0
- package/lib/cli.js.map +1 -1
- package/lib/client/QaAccountsController.js +61 -0
- package/lib/client/QaAccountsController.js.map +1 -1
- package/lib/client/QaRouteController.js +3 -1
- package/lib/client/QaRouteController.js.map +1 -1
- package/lib/client/QaSessionController.js +90 -26
- package/lib/client/QaSessionController.js.map +1 -1
- package/lib/client/QaSurface.js +40 -11
- package/lib/client/QaSurface.js.map +1 -1
- package/lib/client/account-sessions.js +74 -8
- package/lib/client/account-sessions.js.map +1 -1
- package/lib/client/admin/CapabilityPicker.js +50 -0
- package/lib/client/admin/CapabilityPicker.js.map +1 -0
- package/lib/client/admin/CoverageNotice.js +9 -0
- package/lib/client/admin/CoverageNotice.js.map +1 -0
- package/lib/client/admin/QaAdmin.js +3 -150
- package/lib/client/admin/QaAdmin.js.map +1 -1
- package/lib/client/admin/RoleEditor.js +46 -0
- package/lib/client/admin/RoleEditor.js.map +1 -0
- package/lib/client/admin/capability-selection.js +63 -0
- package/lib/client/admin/capability-selection.js.map +1 -0
- package/lib/client/admin/pages/Conversations.js +35 -17
- package/lib/client/admin/pages/Conversations.js.map +1 -1
- package/lib/client/admin/pages/Overview.js +3 -2
- package/lib/client/admin/pages/Overview.js.map +1 -1
- package/lib/client/admin/pages/Quality.js +77 -20
- package/lib/client/admin/pages/Quality.js.map +1 -1
- package/lib/client/admin/pages/SkillFiles.js +14 -3
- package/lib/client/admin/pages/SkillFiles.js.map +1 -1
- package/lib/client/admin/shared.js +68 -3
- package/lib/client/admin/shared.js.map +1 -1
- package/lib/client/components/QaAuthGate.js +31 -28
- package/lib/client/components/QaAuthGate.js.map +1 -1
- package/lib/client/components/QaChangelog.js +44 -0
- package/lib/client/components/QaChangelog.js.map +1 -1
- package/lib/client/components/QaComposer.js +27 -4
- package/lib/client/components/QaComposer.js.map +1 -1
- package/lib/client/components/QaFormItem.js +63 -0
- package/lib/client/components/QaFormItem.js.map +1 -0
- package/lib/client/components/QaInputForm.js +281 -0
- package/lib/client/components/QaInputForm.js.map +1 -0
- package/lib/client/components/QaModal.js +17 -4
- package/lib/client/components/QaModal.js.map +1 -1
- package/lib/client/forms-styles.js +14 -0
- package/lib/client/forms-styles.js.map +1 -0
- package/lib/client/forms.js +40 -0
- package/lib/client/forms.js.map +1 -0
- package/lib/client/index.js +15 -1
- package/lib/client/index.js.map +1 -1
- package/lib/client/oidc-browser.js +39 -0
- package/lib/client/oidc-browser.js.map +1 -0
- package/lib/client/panels/PanelHost.js +23 -1
- package/lib/client/panels/PanelHost.js.map +1 -1
- package/lib/client/settings/sections/interface.js +2 -1
- package/lib/client/settings/sections/interface.js.map +1 -1
- package/lib/client/settings/sections/status.js +3 -1
- package/lib/client/settings/sections/status.js.map +1 -1
- package/lib/client/styles.js +3 -3
- package/lib/client/types.js.map +1 -1
- package/lib/client.js +465 -72918
- package/lib/client.js.map +1 -1
- package/lib/config-resolvers/accounts.js +5 -4
- package/lib/config-resolvers/accounts.js.map +1 -1
- package/lib/config-resolvers/defaults.js +16 -0
- package/lib/config-resolvers/defaults.js.map +1 -1
- package/lib/config-resolvers/oidc.js +53 -0
- package/lib/config-resolvers/oidc.js.map +1 -0
- package/lib/config.js +71 -0
- package/lib/config.js.map +1 -1
- package/lib/forms/attachments.js +214 -0
- package/lib/forms/attachments.js.map +1 -0
- package/lib/forms/errors.js +37 -0
- package/lib/forms/errors.js.map +1 -0
- package/lib/forms/fingerprint.js +21 -0
- package/lib/forms/fingerprint.js.map +1 -0
- package/lib/forms/gate.js +125 -0
- package/lib/forms/gate.js.map +1 -0
- package/lib/forms/schema.js +182 -0
- package/lib/forms/schema.js.map +1 -0
- package/lib/forms/service.js +220 -0
- package/lib/forms/service.js.map +1 -0
- package/lib/forms/store.js +194 -0
- package/lib/forms/store.js.map +1 -0
- package/lib/forms/types.js +2 -0
- package/lib/forms/types.js.map +1 -0
- package/lib/forms/validation.js +113 -0
- package/lib/forms/validation.js.map +1 -0
- package/lib/index.js +227 -3
- package/lib/index.js.map +1 -1
- package/lib/oidc/http.js +30 -0
- package/lib/oidc/http.js.map +1 -0
- package/lib/oidc/service.js +250 -0
- package/lib/oidc/service.js.map +1 -0
- package/lib/qa-tools/activation-manager.js +24 -2
- package/lib/qa-tools/activation-manager.js.map +1 -1
- package/lib/qa-tools/catalog.js +11 -1
- package/lib/qa-tools/catalog.js.map +1 -1
- package/lib/qa-tools/index.js +27 -0
- package/lib/qa-tools/index.js.map +1 -1
- package/lib/qa-tools/request-user-form.js +121 -0
- package/lib/qa-tools/request-user-form.js.map +1 -0
- package/lib/resolve-config.js +2 -0
- package/lib/resolve-config.js.map +1 -1
- package/lib/secure-session.js +14 -8
- package/lib/secure-session.js.map +1 -1
- package/lib/typert.host.js +4587 -1101
- package/lib/typert.remote-client.d.ts +133 -3
- package/lib/typert.remote-client.js +4463 -1103
- package/lib/types/accounts/database.d.ts +8 -0
- package/lib/types/accounts/file.d.ts +2 -0
- package/lib/types/accounts/store.d.ts +17 -0
- package/lib/types/accounts/token.d.ts +3 -1
- package/lib/types/admin/metrics.d.ts +5 -1
- package/lib/types/admin/read-budget.d.ts +8 -0
- package/lib/types/admin/service.d.ts +17 -0
- package/lib/types/admin/session-log.d.ts +30 -1
- package/lib/types/chat-sharing/uploads.d.ts +2 -1
- package/lib/types/client/QaAccountsController.d.ts +4 -0
- package/lib/types/client/QaRouteController.d.ts +1 -0
- package/lib/types/client/QaSessionController.d.ts +12 -3
- package/lib/types/client/QaSurface.d.ts +2 -0
- package/lib/types/client/admin/CapabilityPicker.d.ts +14 -0
- package/lib/types/client/admin/CoverageNotice.d.ts +6 -0
- package/lib/types/client/admin/RoleEditor.d.ts +15 -0
- package/lib/types/client/admin/capability-selection.d.ts +27 -0
- package/lib/types/client/admin/shared.d.ts +39 -1
- package/lib/types/client/components/QaAuthGate.d.ts +2 -0
- package/lib/types/client/components/QaFormItem.d.ts +20 -0
- package/lib/types/client/components/QaInputForm.d.ts +18 -0
- package/lib/types/client/forms-styles.d.ts +2 -0
- package/lib/types/client/forms.d.ts +23 -0
- package/lib/types/client/oidc-browser.d.ts +12 -0
- package/lib/types/client/types.d.ts +7 -1
- package/lib/types/config-resolvers/oidc.d.ts +3 -0
- package/lib/types/forms/attachments.d.ts +48 -0
- package/lib/types/forms/errors.d.ts +11 -0
- package/lib/types/forms/fingerprint.d.ts +9 -0
- package/lib/types/forms/gate.d.ts +33 -0
- package/lib/types/forms/schema.d.ts +72 -0
- package/lib/types/forms/service.d.ts +15 -0
- package/lib/types/forms/store.d.ts +25 -0
- package/lib/types/forms/types.d.ts +215 -0
- package/lib/types/forms/validation.d.ts +20 -0
- package/lib/types/index.d.ts +28 -0
- package/lib/types/oidc/http.d.ts +5 -0
- package/lib/types/oidc/service.d.ts +30 -0
- package/lib/types/oidc.js +2 -0
- package/lib/types/oidc.js.map +1 -0
- package/lib/types/qa-tools/activation-manager.d.ts +5 -0
- package/lib/types/qa-tools/catalog.d.ts +4 -1
- package/lib/types/qa-tools/index.d.ts +5 -1
- package/lib/types/qa-tools/request-user-form.d.ts +5 -0
- package/lib/types/secure-session.d.ts +1 -0
- package/lib/types/types/accounts.d.ts +2 -0
- package/lib/types/types/admin.d.ts +6 -0
- package/lib/types/types/config.d.ts +6 -0
- package/lib/types/types/oidc.d.ts +36 -0
- package/lib/types/types.d.ts +2 -0
- package/package.json +57 -55
package/lib/index.js
CHANGED
|
@@ -58,12 +58,19 @@ import { QaApprovalGate } from "./approvals.js";
|
|
|
58
58
|
import { QaAttestationError, qaAttestationFailureMessage, } from "./attestation.js";
|
|
59
59
|
import { QaFileDeleteGate } from "./qa-tools/file-delete-gate.js";
|
|
60
60
|
import { QaQuestionGate } from "./questions.js";
|
|
61
|
+
import { QaFormStore } from "./forms/store.js";
|
|
62
|
+
import { QaFormService } from "./forms/service.js";
|
|
63
|
+
import { QaFormGate } from "./forms/gate.js";
|
|
64
|
+
import { QaFormAttachmentAdapter, } from "./forms/attachments.js";
|
|
65
|
+
import { formFailure, QaFormError } from "./forms/errors.js";
|
|
61
66
|
import { QaSessionOwnership } from "./session-ownership.js";
|
|
62
67
|
import { QaLlmIdentity } from "./llm-identity.js";
|
|
63
68
|
import { registerTurnFailureLog } from "./turn-failure-log.js";
|
|
64
69
|
import { entryRedirectRow } from "./entry-redirect.js";
|
|
65
70
|
import { qaKioskDeployment } from "./ui-mode.js";
|
|
66
71
|
import { registerQaNavigationRoute } from "./host-route.js";
|
|
72
|
+
import { QaOidcService, oidcRefusal } from "./oidc/service.js";
|
|
73
|
+
import { registerQaOidcRoute } from "./oidc/http.js";
|
|
67
74
|
import { makeLaunchTokenSource } from "./launch-token.js";
|
|
68
75
|
import { QaIntegrationPrincipalBindings } from "./integration-principals.js";
|
|
69
76
|
import { registerQaIntegrationRoutes } from "./integration/http.js";
|
|
@@ -139,6 +146,9 @@ let QaSurface = (() => {
|
|
|
139
146
|
let _instanceExtraInitializers = [];
|
|
140
147
|
let _accountsRegister_decorators;
|
|
141
148
|
let _accountsLogin_decorators;
|
|
149
|
+
let _accountsOidcStart_decorators;
|
|
150
|
+
let _accountsOidcComplete_decorators;
|
|
151
|
+
let _accountsOidcLogout_decorators;
|
|
142
152
|
let _accountsChangePassword_decorators;
|
|
143
153
|
let _accountsRequestPasswordReset_decorators;
|
|
144
154
|
let _accountsWhoami_decorators;
|
|
@@ -219,6 +229,12 @@ let QaSurface = (() => {
|
|
|
219
229
|
let _pendingApprovals_decorators;
|
|
220
230
|
let _answerApproval_decorators;
|
|
221
231
|
let _pendingQuestions_decorators;
|
|
232
|
+
let _listForms_decorators;
|
|
233
|
+
let _getForm_decorators;
|
|
234
|
+
let _mutateForm_decorators;
|
|
235
|
+
let _validateFormStep_decorators;
|
|
236
|
+
let _formCapabilities_decorators;
|
|
237
|
+
let _readFormAttachment_decorators;
|
|
222
238
|
let _answerQuestion_decorators;
|
|
223
239
|
let _cancelQuestion_decorators;
|
|
224
240
|
let _readSourceFile_decorators;
|
|
@@ -243,6 +259,9 @@ let QaSurface = (() => {
|
|
|
243
259
|
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
244
260
|
_accountsRegister_decorators = [Remote("accountsRegister")];
|
|
245
261
|
_accountsLogin_decorators = [Remote("accountsLogin")];
|
|
262
|
+
_accountsOidcStart_decorators = [Remote("accountsOidcStart")];
|
|
263
|
+
_accountsOidcComplete_decorators = [Remote("accountsOidcComplete")];
|
|
264
|
+
_accountsOidcLogout_decorators = [Remote("accountsOidcLogout")];
|
|
246
265
|
_accountsChangePassword_decorators = [Remote("accountsChangePassword")];
|
|
247
266
|
_accountsRequestPasswordReset_decorators = [Remote("accountsRequestPasswordReset")];
|
|
248
267
|
_accountsWhoami_decorators = [Remote("accountsWhoami")];
|
|
@@ -323,6 +342,12 @@ let QaSurface = (() => {
|
|
|
323
342
|
_pendingApprovals_decorators = [Remote("pendingApprovals")];
|
|
324
343
|
_answerApproval_decorators = [Remote("answerApproval")];
|
|
325
344
|
_pendingQuestions_decorators = [Remote("pendingQuestions")];
|
|
345
|
+
_listForms_decorators = [Remote("listForms")];
|
|
346
|
+
_getForm_decorators = [Remote("getForm")];
|
|
347
|
+
_mutateForm_decorators = [Remote("mutateForm")];
|
|
348
|
+
_validateFormStep_decorators = [Remote("validateFormStep")];
|
|
349
|
+
_formCapabilities_decorators = [Remote("formCapabilities")];
|
|
350
|
+
_readFormAttachment_decorators = [Remote("readFormAttachment")];
|
|
326
351
|
_answerQuestion_decorators = [Remote("answerQuestion")];
|
|
327
352
|
_cancelQuestion_decorators = [Remote("cancelQuestion")];
|
|
328
353
|
_readSourceFile_decorators = [Remote("readSourceFile")];
|
|
@@ -344,6 +369,9 @@ let QaSurface = (() => {
|
|
|
344
369
|
_slashExecute_decorators = [Remote("slashExecute")];
|
|
345
370
|
__esDecorate(this, null, _accountsRegister_decorators, { kind: "method", name: "accountsRegister", static: false, private: false, access: { has: obj => "accountsRegister" in obj, get: obj => obj.accountsRegister }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
346
371
|
__esDecorate(this, null, _accountsLogin_decorators, { kind: "method", name: "accountsLogin", static: false, private: false, access: { has: obj => "accountsLogin" in obj, get: obj => obj.accountsLogin }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
372
|
+
__esDecorate(this, null, _accountsOidcStart_decorators, { kind: "method", name: "accountsOidcStart", static: false, private: false, access: { has: obj => "accountsOidcStart" in obj, get: obj => obj.accountsOidcStart }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
373
|
+
__esDecorate(this, null, _accountsOidcComplete_decorators, { kind: "method", name: "accountsOidcComplete", static: false, private: false, access: { has: obj => "accountsOidcComplete" in obj, get: obj => obj.accountsOidcComplete }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
374
|
+
__esDecorate(this, null, _accountsOidcLogout_decorators, { kind: "method", name: "accountsOidcLogout", static: false, private: false, access: { has: obj => "accountsOidcLogout" in obj, get: obj => obj.accountsOidcLogout }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
347
375
|
__esDecorate(this, null, _accountsChangePassword_decorators, { kind: "method", name: "accountsChangePassword", static: false, private: false, access: { has: obj => "accountsChangePassword" in obj, get: obj => obj.accountsChangePassword }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
348
376
|
__esDecorate(this, null, _accountsRequestPasswordReset_decorators, { kind: "method", name: "accountsRequestPasswordReset", static: false, private: false, access: { has: obj => "accountsRequestPasswordReset" in obj, get: obj => obj.accountsRequestPasswordReset }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
349
377
|
__esDecorate(this, null, _accountsWhoami_decorators, { kind: "method", name: "accountsWhoami", static: false, private: false, access: { has: obj => "accountsWhoami" in obj, get: obj => obj.accountsWhoami }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
@@ -424,6 +452,12 @@ let QaSurface = (() => {
|
|
|
424
452
|
__esDecorate(this, null, _pendingApprovals_decorators, { kind: "method", name: "pendingApprovals", static: false, private: false, access: { has: obj => "pendingApprovals" in obj, get: obj => obj.pendingApprovals }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
425
453
|
__esDecorate(this, null, _answerApproval_decorators, { kind: "method", name: "answerApproval", static: false, private: false, access: { has: obj => "answerApproval" in obj, get: obj => obj.answerApproval }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
426
454
|
__esDecorate(this, null, _pendingQuestions_decorators, { kind: "method", name: "pendingQuestions", static: false, private: false, access: { has: obj => "pendingQuestions" in obj, get: obj => obj.pendingQuestions }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
455
|
+
__esDecorate(this, null, _listForms_decorators, { kind: "method", name: "listForms", static: false, private: false, access: { has: obj => "listForms" in obj, get: obj => obj.listForms }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
456
|
+
__esDecorate(this, null, _getForm_decorators, { kind: "method", name: "getForm", static: false, private: false, access: { has: obj => "getForm" in obj, get: obj => obj.getForm }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
457
|
+
__esDecorate(this, null, _mutateForm_decorators, { kind: "method", name: "mutateForm", static: false, private: false, access: { has: obj => "mutateForm" in obj, get: obj => obj.mutateForm }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
458
|
+
__esDecorate(this, null, _validateFormStep_decorators, { kind: "method", name: "validateFormStep", static: false, private: false, access: { has: obj => "validateFormStep" in obj, get: obj => obj.validateFormStep }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
459
|
+
__esDecorate(this, null, _formCapabilities_decorators, { kind: "method", name: "formCapabilities", static: false, private: false, access: { has: obj => "formCapabilities" in obj, get: obj => obj.formCapabilities }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
460
|
+
__esDecorate(this, null, _readFormAttachment_decorators, { kind: "method", name: "readFormAttachment", static: false, private: false, access: { has: obj => "readFormAttachment" in obj, get: obj => obj.readFormAttachment }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
427
461
|
__esDecorate(this, null, _answerQuestion_decorators, { kind: "method", name: "answerQuestion", static: false, private: false, access: { has: obj => "answerQuestion" in obj, get: obj => obj.answerQuestion }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
428
462
|
__esDecorate(this, null, _cancelQuestion_decorators, { kind: "method", name: "cancelQuestion", static: false, private: false, access: { has: obj => "cancelQuestion" in obj, get: obj => obj.cancelQuestion }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
429
463
|
__esDecorate(this, null, _readSourceFile_decorators, { kind: "method", name: "readSourceFile", static: false, private: false, access: { has: obj => "readSourceFile" in obj, get: obj => obj.readSourceFile }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
@@ -453,6 +487,13 @@ let QaSurface = (() => {
|
|
|
453
487
|
approvals;
|
|
454
488
|
fileDeleteGate;
|
|
455
489
|
userQuestions;
|
|
490
|
+
formService;
|
|
491
|
+
formGate;
|
|
492
|
+
formAttachments;
|
|
493
|
+
forms() {
|
|
494
|
+
return (this.formService ??= new QaFormService(new QaFormStore(path.join(path.dirname(defaultAccountsFilePath()), "qa-forms.db")), () => this.getConfig().forms, (session) => this.accountRemotes.resolve(this.getConfig())?.ownerIdOf(session) ??
|
|
495
|
+
session));
|
|
496
|
+
}
|
|
456
497
|
provenance;
|
|
457
498
|
notes;
|
|
458
499
|
/** Assigned after the admission gate; that gate only reads it per execution. */
|
|
@@ -481,6 +522,12 @@ let QaSurface = (() => {
|
|
|
481
522
|
integrationPrincipals = new QaIntegrationPrincipalBindings();
|
|
482
523
|
webServer;
|
|
483
524
|
disposeRoute;
|
|
525
|
+
oidc = new QaOidcService({
|
|
526
|
+
config: () => this.getConfig(),
|
|
527
|
+
accounts: () => this.accountRemotes.resolve(this.getConfig()),
|
|
528
|
+
});
|
|
529
|
+
disposeOidcRoute;
|
|
530
|
+
oidcRouteKey;
|
|
484
531
|
routeKey;
|
|
485
532
|
/**
|
|
486
533
|
* The HTTP API an external application asks questions through. Constructed
|
|
@@ -518,6 +565,7 @@ let QaSurface = (() => {
|
|
|
518
565
|
pluginId: "dsh-qa-surface",
|
|
519
566
|
consoleSink: createHostLoggerSink(ctx.logger),
|
|
520
567
|
});
|
|
568
|
+
this.formAttachments = new QaFormAttachmentAdapter(() => this.forms(), () => ctx.get("attachments"));
|
|
521
569
|
this.accountRemotes = createQaAccountRemotes({
|
|
522
570
|
getConfig: () => this.getConfig(),
|
|
523
571
|
logger: this.logger,
|
|
@@ -632,7 +680,7 @@ let QaSurface = (() => {
|
|
|
632
680
|
}, "dsh-qa-surface.chat-sharing");
|
|
633
681
|
ctx.inject(["typertGateway", "connection"], () => {
|
|
634
682
|
const dispose = installQaNativeFence(ctx, () => this.getConfig().accounts.enabled);
|
|
635
|
-
const disposeUploads = installQaChatUploads(ctx, () => this.sharing(), (token, id) => this.secureSession(token, id));
|
|
683
|
+
const disposeUploads = installQaChatUploads(ctx, () => this.sharing(), (token, id) => this.secureSession(token, id), this.formAttachments);
|
|
636
684
|
return async () => {
|
|
637
685
|
dispose();
|
|
638
686
|
await disposeUploads();
|
|
@@ -671,7 +719,20 @@ let QaSurface = (() => {
|
|
|
671
719
|
this.approvals = new QaApprovalGate(ctx, () => this.getConfig().interaction.approvals === "interactive", ownership, this.logger);
|
|
672
720
|
const integrationQuestionPolicy = new QaIntegrationQuestionPolicy(ctx, () => this.accountRemotes.resolve(this.getConfig()), (id) => ownership.rootOf(id));
|
|
673
721
|
ctx.effect(() => () => integrationQuestionPolicy.dispose(), "qa-surface: integration question policy");
|
|
674
|
-
this.userQuestions = new QaQuestionGate(ctx, () => this.getConfig().interaction.questions === "interactive", ownership, this.logger, (agent) => integrationQuestionPolicy.allowed(agent)
|
|
722
|
+
this.userQuestions = new QaQuestionGate(ctx, () => this.getConfig().interaction.questions === "interactive", ownership, this.logger, (agent) => integrationQuestionPolicy.allowed(agent) &&
|
|
723
|
+
!this.formGate?.hasSession(ownership.rootOf(String(agent.session.id)) ?? ""));
|
|
724
|
+
this.formGate = new QaFormGate(() => this.forms(), (id) => ownership.rootOf(id), (id) => this.userQuestions.list(id).length > 0 ||
|
|
725
|
+
this.approvals.list(id).length > 0, (exec) => this.getConfig().forms.enabled &&
|
|
726
|
+
exec.agent !== undefined &&
|
|
727
|
+
integrationQuestionPolicy.allowed(exec.agent) &&
|
|
728
|
+
this.admission.knowsSession(String(exec.agent.session.id)), () => this.getConfig().accounts.enabled &&
|
|
729
|
+
this.ctx.get("fileUploads") !== undefined &&
|
|
730
|
+
this.formAttachments.available());
|
|
731
|
+
this.formGate.install(ctx);
|
|
732
|
+
ctx.effect(() => () => {
|
|
733
|
+
this.formGate.dispose();
|
|
734
|
+
this.formService?.store.close();
|
|
735
|
+
}, "dsh-qa-surface.forms");
|
|
675
736
|
// The destructive tool of the QA catalog composes the same approval flow
|
|
676
737
|
// around itself: registered without `prepend`, it sits inside the approval
|
|
677
738
|
// gate and answers `ask` for every file_delete call of an attested chat,
|
|
@@ -722,6 +783,9 @@ let QaSurface = (() => {
|
|
|
722
783
|
// The QA tool catalog is attached per agent, never at boot: nothing here
|
|
723
784
|
// reaches the model until a managed agent loads the activation skill.
|
|
724
785
|
this.tools = new QaTools(ctx, {
|
|
786
|
+
forms: this.formGate,
|
|
787
|
+
formsEnabled: () => this.getConfig().forms.enabled,
|
|
788
|
+
formProjection: (submission) => this.formAttachments.readable(submission),
|
|
725
789
|
logger: this.logger,
|
|
726
790
|
dynamicActivation: this.getConfig().tools.dynamicActivation,
|
|
727
791
|
activationSkill: this.getConfig().tools.activationSkill,
|
|
@@ -734,6 +798,12 @@ let QaSurface = (() => {
|
|
|
734
798
|
docsDefaultVersion: () => docsDefaultVersionOf(this.getConfig().tools),
|
|
735
799
|
});
|
|
736
800
|
ctx.effect(() => () => this.tools.dispose(), "dsh-qa-surface.qa-tools");
|
|
801
|
+
const listenVolatile = ctx.on.bind(ctx);
|
|
802
|
+
ctx.effect(() => listenVolatile("loader/volatile-update", () => {
|
|
803
|
+
this.tools.refreshForms();
|
|
804
|
+
if (!this.getConfig().forms.enabled)
|
|
805
|
+
this.formGate.cancelAll();
|
|
806
|
+
}), "dsh-qa-surface.form-policy");
|
|
737
807
|
// The root index gains one head script: non-loopback hostnames continue
|
|
738
808
|
// into /qa, the loopback operator keeps the full harness UI. Not in the
|
|
739
809
|
// kiosk composition: there the index itself is served under /qa, so the
|
|
@@ -760,6 +830,7 @@ let QaSurface = (() => {
|
|
|
760
830
|
const config = this.getConfig();
|
|
761
831
|
this.refreshRoute();
|
|
762
832
|
this.refreshIntegrationRoutes();
|
|
833
|
+
this.refreshOidcRoute();
|
|
763
834
|
this.warnDocumentsMoved();
|
|
764
835
|
this.warnLegacySlashDefaults();
|
|
765
836
|
this.logger.info("config.updated", {
|
|
@@ -772,11 +843,16 @@ let QaSurface = (() => {
|
|
|
772
843
|
this.webServer = webContext.webServer;
|
|
773
844
|
this.refreshRoute();
|
|
774
845
|
this.refreshIntegrationRoutes();
|
|
846
|
+
this.refreshOidcRoute();
|
|
775
847
|
webContext.effect(() => () => {
|
|
776
848
|
this.disposeRoute?.();
|
|
777
849
|
this.disposeRoute = undefined;
|
|
778
850
|
this.routeKey = undefined;
|
|
779
851
|
this.disposeIntegrationRoutes?.();
|
|
852
|
+
this.disposeOidcRoute?.();
|
|
853
|
+
this.disposeOidcRoute = undefined;
|
|
854
|
+
this.oidcRouteKey = undefined;
|
|
855
|
+
this.oidc.clear();
|
|
780
856
|
this.disposeIntegrationRoutes = undefined;
|
|
781
857
|
this.integrationRouteKey = undefined;
|
|
782
858
|
this.webServer = undefined;
|
|
@@ -827,6 +903,10 @@ let QaSurface = (() => {
|
|
|
827
903
|
* cannot be opened must not fail the page that triggered it.
|
|
828
904
|
*/
|
|
829
905
|
dropVanishedChats(sessionIds) {
|
|
906
|
+
for (const id of sessionIds) {
|
|
907
|
+
this.formGate?.cancel(id);
|
|
908
|
+
this.formService?.store.cancelSession(id);
|
|
909
|
+
}
|
|
830
910
|
try {
|
|
831
911
|
const rows = this.quality().dropConversations(sessionIds);
|
|
832
912
|
this.logger.info("quality.vanished-conversations-dropped", {
|
|
@@ -927,6 +1007,17 @@ let QaSurface = (() => {
|
|
|
927
1007
|
accountsLogin(email, password) {
|
|
928
1008
|
return this.accountRemotes.login(email, password);
|
|
929
1009
|
}
|
|
1010
|
+
accountsOidcStart() {
|
|
1011
|
+
if (!this.disposeOidcRoute)
|
|
1012
|
+
return Promise.reject(oidcRefusal());
|
|
1013
|
+
return this.oidc.start();
|
|
1014
|
+
}
|
|
1015
|
+
accountsOidcComplete(handoff, completionKey) {
|
|
1016
|
+
return this.oidc.complete(handoff, completionKey);
|
|
1017
|
+
}
|
|
1018
|
+
accountsOidcLogout(token) {
|
|
1019
|
+
return this.oidc.logout(token);
|
|
1020
|
+
}
|
|
930
1021
|
/** Identity probe; safe to call with an empty or expired token. */
|
|
931
1022
|
accountsChangePassword(token, currentPassword, nextPassword) {
|
|
932
1023
|
return this.accountRemotes.changePassword(token, currentPassword, nextPassword);
|
|
@@ -1406,7 +1497,9 @@ let QaSurface = (() => {
|
|
|
1406
1497
|
}
|
|
1407
1498
|
async chatAudit(token, sessionId, full) {
|
|
1408
1499
|
this.requireChatOwner(token, sessionId);
|
|
1409
|
-
|
|
1500
|
+
// Sidebar summaries read stored audit metadata; they do not need an agent.
|
|
1501
|
+
if (full)
|
|
1502
|
+
await this.secureSession(token, sessionId);
|
|
1410
1503
|
this.requireChatOwner(token, sessionId);
|
|
1411
1504
|
const audit = this.ctx.get("sessionAudit");
|
|
1412
1505
|
if (audit === undefined)
|
|
@@ -1523,6 +1616,115 @@ let QaSurface = (() => {
|
|
|
1523
1616
|
return [];
|
|
1524
1617
|
return this.userQuestions.list(sessionId);
|
|
1525
1618
|
}
|
|
1619
|
+
/** Forms stay owner-scoped; UUIDs and a browser-supplied session never grant access. */
|
|
1620
|
+
async admitForm(token, sessionId) {
|
|
1621
|
+
try {
|
|
1622
|
+
this.requireChatOwner(token, sessionId);
|
|
1623
|
+
await this.secureSession(token, sessionId);
|
|
1624
|
+
this.requireChatOwner(token, sessionId);
|
|
1625
|
+
}
|
|
1626
|
+
catch {
|
|
1627
|
+
throw new QaFormError("ACCESS_DENIED", "Form access is unavailable.");
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1630
|
+
async listForms(token, sessionId) {
|
|
1631
|
+
try {
|
|
1632
|
+
await this.admitForm(token, sessionId);
|
|
1633
|
+
if (!this.getConfig().forms.enabled)
|
|
1634
|
+
return { ok: true, value: [] };
|
|
1635
|
+
this.formGate.touch(sessionId);
|
|
1636
|
+
const service = this.forms();
|
|
1637
|
+
return {
|
|
1638
|
+
ok: true,
|
|
1639
|
+
value: service.store
|
|
1640
|
+
.list(sessionId)
|
|
1641
|
+
.map((r) => service.view(r, this.formGate.waiting(r.id))),
|
|
1642
|
+
};
|
|
1643
|
+
}
|
|
1644
|
+
catch (error) {
|
|
1645
|
+
return formFailure(error);
|
|
1646
|
+
}
|
|
1647
|
+
}
|
|
1648
|
+
async getForm(token, sessionId, formId) {
|
|
1649
|
+
try {
|
|
1650
|
+
await this.admitForm(token, sessionId);
|
|
1651
|
+
const s = this.forms();
|
|
1652
|
+
return {
|
|
1653
|
+
ok: true,
|
|
1654
|
+
value: s.view(s.get(sessionId, formId), this.formGate.waiting(formId)),
|
|
1655
|
+
};
|
|
1656
|
+
}
|
|
1657
|
+
catch (error) {
|
|
1658
|
+
return formFailure(error);
|
|
1659
|
+
}
|
|
1660
|
+
}
|
|
1661
|
+
async mutateForm(token, sessionId, command) {
|
|
1662
|
+
try {
|
|
1663
|
+
await this.admitForm(token, sessionId);
|
|
1664
|
+
const s = this.forms(), r = s.command(sessionId, command);
|
|
1665
|
+
this.logger.info("form.mutated", {
|
|
1666
|
+
sessionId,
|
|
1667
|
+
formId: r.id,
|
|
1668
|
+
action: command.action,
|
|
1669
|
+
revision: r.revision,
|
|
1670
|
+
status: r.status,
|
|
1671
|
+
});
|
|
1672
|
+
this.formGate.notify(r, command.action === "pause");
|
|
1673
|
+
return { ok: true, value: s.view(r, this.formGate.waiting(r.id)) };
|
|
1674
|
+
}
|
|
1675
|
+
catch (error) {
|
|
1676
|
+
return formFailure(error);
|
|
1677
|
+
}
|
|
1678
|
+
}
|
|
1679
|
+
async validateFormStep(token, sessionId, formId, stepId, revision) {
|
|
1680
|
+
try {
|
|
1681
|
+
await this.admitForm(token, sessionId);
|
|
1682
|
+
this.forms().step(sessionId, formId, stepId, revision);
|
|
1683
|
+
return { ok: true, value: null };
|
|
1684
|
+
}
|
|
1685
|
+
catch (error) {
|
|
1686
|
+
return formFailure(error);
|
|
1687
|
+
}
|
|
1688
|
+
}
|
|
1689
|
+
async formCapabilities() {
|
|
1690
|
+
return {
|
|
1691
|
+
enabled: this.getConfig().forms.enabled,
|
|
1692
|
+
schemaVersion: 1,
|
|
1693
|
+
upload: this.getConfig().accounts.enabled &&
|
|
1694
|
+
this.ctx.get("fileUploads") !== undefined &&
|
|
1695
|
+
this.formAttachments.available(),
|
|
1696
|
+
};
|
|
1697
|
+
}
|
|
1698
|
+
async readFormAttachment(token, sessionId, formId, resourceId) {
|
|
1699
|
+
try {
|
|
1700
|
+
await this.admitForm(token, sessionId);
|
|
1701
|
+
const s = this.forms(), r = s.get(sessionId, formId);
|
|
1702
|
+
const file = Object.values(r.attachments)
|
|
1703
|
+
.flat()
|
|
1704
|
+
.find((f) => f.resource_id === resourceId);
|
|
1705
|
+
if (!file)
|
|
1706
|
+
return {
|
|
1707
|
+
ok: false,
|
|
1708
|
+
error: {
|
|
1709
|
+
code: "ACCESS_DENIED",
|
|
1710
|
+
message: "File access is unavailable.",
|
|
1711
|
+
},
|
|
1712
|
+
};
|
|
1713
|
+
const data = s.store.resource(formId, resourceId);
|
|
1714
|
+
this.requireChatOwner(token, sessionId);
|
|
1715
|
+
return {
|
|
1716
|
+
ok: true,
|
|
1717
|
+
value: {
|
|
1718
|
+
name: file.name,
|
|
1719
|
+
media_type: file.media_type,
|
|
1720
|
+
data: Buffer.from(data).toString("base64"),
|
|
1721
|
+
},
|
|
1722
|
+
};
|
|
1723
|
+
}
|
|
1724
|
+
catch (error) {
|
|
1725
|
+
return formFailure(error);
|
|
1726
|
+
}
|
|
1727
|
+
}
|
|
1526
1728
|
/**
|
|
1527
1729
|
* Apply the operator's answers to one parked question request. Every question
|
|
1528
1730
|
* of the request must be present in `answers`; one the browser omits reads as
|
|
@@ -1901,6 +2103,28 @@ let QaSurface = (() => {
|
|
|
1901
2103
|
});
|
|
1902
2104
|
}
|
|
1903
2105
|
}
|
|
2106
|
+
refreshOidcRoute() {
|
|
2107
|
+
const config = this.getConfig();
|
|
2108
|
+
const key = config.enabled && config.accounts.enabled && config.accounts.oidc.enabled
|
|
2109
|
+
? JSON.stringify([config.accounts.oidc, config.route.path])
|
|
2110
|
+
: undefined;
|
|
2111
|
+
if (key === this.oidcRouteKey)
|
|
2112
|
+
return;
|
|
2113
|
+
this.disposeOidcRoute?.();
|
|
2114
|
+
this.disposeOidcRoute = undefined;
|
|
2115
|
+
this.oidcRouteKey = undefined;
|
|
2116
|
+
this.oidc.clear();
|
|
2117
|
+
if (!key || !this.webServer)
|
|
2118
|
+
return;
|
|
2119
|
+
try {
|
|
2120
|
+
this.disposeOidcRoute = registerQaOidcRoute(this.webServer, config, this.oidc);
|
|
2121
|
+
this.oidcRouteKey = key;
|
|
2122
|
+
this.logger.info("oidc.route-registered", {});
|
|
2123
|
+
}
|
|
2124
|
+
catch {
|
|
2125
|
+
this.logger.error("oidc.route-unavailable", {});
|
|
2126
|
+
}
|
|
2127
|
+
}
|
|
1904
2128
|
refreshRoute() {
|
|
1905
2129
|
const config = this.getConfig();
|
|
1906
2130
|
// Kiosk: the harness route policy owns the QA paths and serves the
|