@yadsh/dsh-qa-surface 0.6.1 → 0.7.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 (281) hide show
  1. package/README.md +136 -7
  2. package/capability-policy.json +1 -1
  3. package/lib/access/capability-catalog.js +144 -0
  4. package/lib/access/capability-catalog.js.map +1 -0
  5. package/lib/access/model.js +379 -0
  6. package/lib/access/model.js.map +1 -0
  7. package/lib/access/role-repository.js +195 -0
  8. package/lib/access/role-repository.js.map +1 -0
  9. package/lib/access/service.js +380 -0
  10. package/lib/access/service.js.map +1 -0
  11. package/lib/access/skill-metadata.js +234 -0
  12. package/lib/access/skill-metadata.js.map +1 -0
  13. package/lib/account-remotes.js +20 -10
  14. package/lib/account-remotes.js.map +1 -1
  15. package/lib/accounts/errors.js.map +1 -1
  16. package/lib/accounts/file.js.map +1 -1
  17. package/lib/accounts/store.js +202 -3
  18. package/lib/accounts/store.js.map +1 -1
  19. package/lib/admin/conversation-log.js +256 -0
  20. package/lib/admin/conversation-log.js.map +1 -0
  21. package/lib/admin/index.js +17 -0
  22. package/lib/admin/index.js.map +1 -0
  23. package/lib/admin/metrics.js +103 -0
  24. package/lib/admin/metrics.js.map +1 -0
  25. package/lib/admin/paging.js +23 -0
  26. package/lib/admin/paging.js.map +1 -0
  27. package/lib/admin/permissions.js +50 -0
  28. package/lib/admin/permissions.js.map +1 -0
  29. package/lib/admin/quality-store.js +485 -0
  30. package/lib/admin/quality-store.js.map +1 -0
  31. package/lib/admin/queue.js +107 -0
  32. package/lib/admin/queue.js.map +1 -0
  33. package/lib/admin/redaction.js +45 -0
  34. package/lib/admin/redaction.js.map +1 -0
  35. package/lib/admin/service.js +897 -0
  36. package/lib/admin/service.js.map +1 -0
  37. package/lib/admin/session-log.js +142 -0
  38. package/lib/admin/session-log.js.map +1 -0
  39. package/lib/cli.js +9 -6
  40. package/lib/cli.js.map +1 -1
  41. package/lib/client/QaSessionController.js +28 -2
  42. package/lib/client/QaSessionController.js.map +1 -1
  43. package/lib/client/QaSurface.js +143 -5
  44. package/lib/client/QaSurface.js.map +1 -1
  45. package/lib/client/QaTranscriptAdapter.js +1 -0
  46. package/lib/client/QaTranscriptAdapter.js.map +1 -1
  47. package/lib/client/admin/QaAdmin.js +458 -0
  48. package/lib/client/admin/QaAdmin.js.map +1 -0
  49. package/lib/client/admin/format.js +177 -0
  50. package/lib/client/admin/format.js.map +1 -0
  51. package/lib/client/admin/pages/Conversations.js +114 -0
  52. package/lib/client/admin/pages/Conversations.js.map +1 -0
  53. package/lib/client/admin/pages/Overview.js +24 -0
  54. package/lib/client/admin/pages/Overview.js.map +1 -0
  55. package/lib/client/admin/pages/Quality.js +71 -0
  56. package/lib/client/admin/pages/Quality.js.map +1 -0
  57. package/lib/client/admin/pages/Review.js +93 -0
  58. package/lib/client/admin/pages/Review.js.map +1 -0
  59. package/lib/client/admin/pages/Users.js +95 -0
  60. package/lib/client/admin/pages/Users.js.map +1 -0
  61. package/lib/client/admin/routes.js +127 -0
  62. package/lib/client/admin/routes.js.map +1 -0
  63. package/lib/client/admin/shared.js +91 -0
  64. package/lib/client/admin/shared.js.map +1 -0
  65. package/lib/client/admin/styles.js +111 -0
  66. package/lib/client/admin/styles.js.map +1 -0
  67. package/lib/client/components/QaChangelog.js +35 -0
  68. package/lib/client/components/QaChangelog.js.map +1 -1
  69. package/lib/client/components/QaHeader.js +3 -3
  70. package/lib/client/components/QaHeader.js.map +1 -1
  71. package/lib/client/components/QaMessage.js +61 -2
  72. package/lib/client/components/QaMessage.js.map +1 -1
  73. package/lib/client/create-session.js +1 -1
  74. package/lib/client/create-session.js.map +1 -1
  75. package/lib/client/index.js +33 -1
  76. package/lib/client/index.js.map +1 -1
  77. package/lib/client/role/RoleSelector.js +31 -0
  78. package/lib/client/role/RoleSelector.js.map +1 -0
  79. package/lib/client/session-sources.js +37 -1
  80. package/lib/client/session-sources.js.map +1 -1
  81. package/lib/client/settings/card.js +2 -2
  82. package/lib/client/settings/card.js.map +1 -1
  83. package/lib/client/settings/sections.js +0 -1
  84. package/lib/client/settings/sections.js.map +1 -1
  85. package/lib/client/styles.js +31 -0
  86. package/lib/client/styles.js.map +1 -1
  87. package/lib/client/types.js.map +1 -1
  88. package/lib/client.js +9908 -4857
  89. package/lib/client.js.map +1 -1
  90. package/lib/config-resolvers/defaults.js +0 -2
  91. package/lib/config-resolvers/defaults.js.map +1 -1
  92. package/lib/config.js +0 -249
  93. package/lib/config.js.map +1 -1
  94. package/lib/enforcement/skill-policy.js +172 -0
  95. package/lib/enforcement/skill-policy.js.map +1 -0
  96. package/lib/enforcement/tool-grants.js +151 -0
  97. package/lib/enforcement/tool-grants.js.map +1 -0
  98. package/lib/index.js +224 -42
  99. package/lib/index.js.map +1 -1
  100. package/lib/personal-skills/service.js +10 -3
  101. package/lib/personal-skills/service.js.map +1 -1
  102. package/lib/qa-tools/index.js +4 -0
  103. package/lib/qa-tools/index.js.map +1 -1
  104. package/lib/resolve-config.js +0 -2
  105. package/lib/resolve-config.js.map +1 -1
  106. package/lib/secure-session.js +71 -17
  107. package/lib/secure-session.js.map +1 -1
  108. package/lib/typert.host.js +2237 -202
  109. package/lib/typert.remote-client.d.ts +49 -3
  110. package/lib/typert.remote-client.js +1863 -183
  111. package/lib/types/access/capability-catalog.d.ts +37 -0
  112. package/lib/types/access/model.d.ts +60 -0
  113. package/lib/types/access/role-repository.d.ts +32 -0
  114. package/lib/types/access/service.d.ts +57 -0
  115. package/lib/types/access/skill-metadata.d.ts +53 -0
  116. package/lib/types/account-remotes.d.ts +6 -0
  117. package/lib/types/accounts/errors.d.ts +1 -1
  118. package/lib/types/accounts/file.d.ts +16 -5
  119. package/lib/types/accounts/store.d.ts +83 -3
  120. package/lib/types/admin/conversation-log.d.ts +39 -0
  121. package/lib/types/admin/index.d.ts +24 -0
  122. package/lib/types/admin/metrics.d.ts +29 -0
  123. package/lib/types/admin/paging.d.ts +33 -0
  124. package/lib/types/admin/permissions.d.ts +10 -0
  125. package/lib/types/admin/quality-store.d.ts +82 -0
  126. package/lib/types/admin/queue.d.ts +21 -0
  127. package/lib/types/admin/redaction.d.ts +29 -0
  128. package/lib/types/admin/service.d.ts +105 -0
  129. package/lib/types/admin/session-log.d.ts +53 -0
  130. package/lib/types/client/QaSessionController.d.ts +12 -1
  131. package/lib/types/client/QaSurface.d.ts +7 -1
  132. package/lib/types/client/admin/QaAdmin.d.ts +17 -0
  133. package/lib/types/client/admin/format.d.ts +43 -0
  134. package/lib/types/client/admin/pages/Conversations.d.ts +21 -0
  135. package/lib/types/client/admin/pages/Overview.d.ts +13 -0
  136. package/lib/types/client/admin/pages/Quality.d.ts +18 -0
  137. package/lib/types/client/admin/pages/Review.d.ts +15 -0
  138. package/lib/types/client/admin/pages/Users.d.ts +22 -0
  139. package/lib/types/client/admin/routes.d.ts +50 -0
  140. package/lib/types/client/admin/shared.d.ts +53 -0
  141. package/lib/types/client/admin/styles.d.ts +11 -0
  142. package/lib/types/client/components/QaHeader.d.ts +5 -1
  143. package/lib/types/client/components/QaMessage.d.ts +14 -1
  144. package/lib/types/client/create-session.d.ts +2 -0
  145. package/lib/types/client/role/RoleSelector.d.ts +14 -0
  146. package/lib/types/client/session-sources.d.ts +9 -0
  147. package/lib/types/client/settings/sections.d.ts +0 -1
  148. package/lib/types/client/types.d.ts +39 -2
  149. package/lib/types/enforcement/skill-policy.d.ts +29 -0
  150. package/lib/types/enforcement/tool-grants.d.ts +84 -0
  151. package/lib/types/index.d.ts +62 -14
  152. package/lib/types/qa-tools/index.d.ts +2 -0
  153. package/lib/types/secure-session.d.ts +10 -1
  154. package/lib/types/types.d.ts +568 -5
  155. package/package.json +1 -1
  156. package/lib/client/settings/sections/documents.js +0 -88
  157. package/lib/client/settings/sections/documents.js.map +0 -1
  158. package/lib/documents/artifacts/ids.js +0 -43
  159. package/lib/documents/artifacts/ids.js.map +0 -1
  160. package/lib/documents/artifacts/manifest.js +0 -66
  161. package/lib/documents/artifacts/manifest.js.map +0 -1
  162. package/lib/documents/artifacts/store.js +0 -169
  163. package/lib/documents/artifacts/store.js.map +0 -1
  164. package/lib/documents/capabilities.js +0 -93
  165. package/lib/documents/capabilities.js.map +0 -1
  166. package/lib/documents/config.js +0 -302
  167. package/lib/documents/config.js.map +0 -1
  168. package/lib/documents/defaults.js +0 -78
  169. package/lib/documents/defaults.js.map +0 -1
  170. package/lib/documents/errors.js +0 -101
  171. package/lib/documents/errors.js.map +0 -1
  172. package/lib/documents/index.js +0 -80
  173. package/lib/documents/index.js.map +0 -1
  174. package/lib/documents/inspect/facts.js +0 -161
  175. package/lib/documents/inspect/facts.js.map +0 -1
  176. package/lib/documents/inspect/zip.js +0 -108
  177. package/lib/documents/inspect/zip.js.map +0 -1
  178. package/lib/documents/markdown/directives.js +0 -135
  179. package/lib/documents/markdown/directives.js.map +0 -1
  180. package/lib/documents/markdown/frontmatter.js +0 -35
  181. package/lib/documents/markdown/frontmatter.js.map +0 -1
  182. package/lib/documents/markdown/normalize.js +0 -113
  183. package/lib/documents/markdown/normalize.js.map +0 -1
  184. package/lib/documents/orchestrator/assets.js +0 -243
  185. package/lib/documents/orchestrator/assets.js.map +0 -1
  186. package/lib/documents/orchestrator/convert-document.js +0 -186
  187. package/lib/documents/orchestrator/convert-document.js.map +0 -1
  188. package/lib/documents/orchestrator/create-document.js +0 -292
  189. package/lib/documents/orchestrator/create-document.js.map +0 -1
  190. package/lib/documents/orchestrator/extract-document.js +0 -162
  191. package/lib/documents/orchestrator/extract-document.js.map +0 -1
  192. package/lib/documents/orchestrator/inspect-document.js +0 -89
  193. package/lib/documents/orchestrator/inspect-document.js.map +0 -1
  194. package/lib/documents/orchestrator/runtime-deps.js +0 -59
  195. package/lib/documents/orchestrator/runtime-deps.js.map +0 -1
  196. package/lib/documents/orchestrator/scope.js +0 -132
  197. package/lib/documents/orchestrator/scope.js.map +0 -1
  198. package/lib/documents/providers/docling.js +0 -247
  199. package/lib/documents/providers/docling.js.map +0 -1
  200. package/lib/documents/providers/libreoffice.js +0 -130
  201. package/lib/documents/providers/libreoffice.js.map +0 -1
  202. package/lib/documents/providers/markitdown.js +0 -89
  203. package/lib/documents/providers/markitdown.js.map +0 -1
  204. package/lib/documents/providers/pandoc.js +0 -161
  205. package/lib/documents/providers/pandoc.js.map +0 -1
  206. package/lib/documents/providers/process.js +0 -164
  207. package/lib/documents/providers/process.js.map +0 -1
  208. package/lib/documents/providers/registry.js +0 -152
  209. package/lib/documents/providers/registry.js.map +0 -1
  210. package/lib/documents/providers/shared.js +0 -75
  211. package/lib/documents/providers/shared.js.map +0 -1
  212. package/lib/documents/runtime.js +0 -114
  213. package/lib/documents/runtime.js.map +0 -1
  214. package/lib/documents/security/file-types.js +0 -188
  215. package/lib/documents/security/file-types.js.map +0 -1
  216. package/lib/documents/security/limits.js +0 -78
  217. package/lib/documents/security/limits.js.map +0 -1
  218. package/lib/documents/security/mime.js +0 -43
  219. package/lib/documents/security/mime.js.map +0 -1
  220. package/lib/documents/security/paths.js +0 -133
  221. package/lib/documents/security/paths.js.map +0 -1
  222. package/lib/documents/templates/registry.js +0 -147
  223. package/lib/documents/templates/registry.js.map +0 -1
  224. package/lib/documents/templates/resolver.js +0 -59
  225. package/lib/documents/templates/resolver.js.map +0 -1
  226. package/lib/documents/tools/convert.js +0 -125
  227. package/lib/documents/tools/convert.js.map +0 -1
  228. package/lib/documents/tools/create.js +0 -187
  229. package/lib/documents/tools/create.js.map +0 -1
  230. package/lib/documents/tools/index.js +0 -41
  231. package/lib/documents/tools/index.js.map +0 -1
  232. package/lib/documents/tools/inspect.js +0 -135
  233. package/lib/documents/tools/inspect.js.map +0 -1
  234. package/lib/documents/tools/shared.js +0 -88
  235. package/lib/documents/tools/shared.js.map +0 -1
  236. package/lib/documents/tools/to-markdown.js +0 -125
  237. package/lib/documents/tools/to-markdown.js.map +0 -1
  238. package/lib/documents/types.js +0 -12
  239. package/lib/documents/types.js.map +0 -1
  240. package/lib/types/client/settings/sections/documents.d.ts +0 -13
  241. package/lib/types/documents/artifacts/ids.d.ts +0 -14
  242. package/lib/types/documents/artifacts/manifest.d.ts +0 -32
  243. package/lib/types/documents/artifacts/store.d.ts +0 -67
  244. package/lib/types/documents/capabilities.d.ts +0 -32
  245. package/lib/types/documents/config.d.ts +0 -27
  246. package/lib/types/documents/defaults.d.ts +0 -161
  247. package/lib/types/documents/errors.d.ts +0 -42
  248. package/lib/types/documents/index.d.ts +0 -63
  249. package/lib/types/documents/inspect/facts.d.ts +0 -43
  250. package/lib/types/documents/inspect/zip.d.ts +0 -28
  251. package/lib/types/documents/markdown/directives.d.ts +0 -39
  252. package/lib/types/documents/markdown/frontmatter.d.ts +0 -15
  253. package/lib/types/documents/markdown/normalize.d.ts +0 -30
  254. package/lib/types/documents/orchestrator/assets.d.ts +0 -55
  255. package/lib/types/documents/orchestrator/convert-document.d.ts +0 -25
  256. package/lib/types/documents/orchestrator/create-document.d.ts +0 -18
  257. package/lib/types/documents/orchestrator/extract-document.d.ts +0 -24
  258. package/lib/types/documents/orchestrator/inspect-document.d.ts +0 -12
  259. package/lib/types/documents/orchestrator/runtime-deps.d.ts +0 -43
  260. package/lib/types/documents/orchestrator/scope.d.ts +0 -52
  261. package/lib/types/documents/providers/docling.d.ts +0 -54
  262. package/lib/types/documents/providers/libreoffice.d.ts +0 -40
  263. package/lib/types/documents/providers/markitdown.d.ts +0 -28
  264. package/lib/types/documents/providers/pandoc.d.ts +0 -42
  265. package/lib/types/documents/providers/process.d.ts +0 -54
  266. package/lib/types/documents/providers/registry.d.ts +0 -68
  267. package/lib/types/documents/providers/shared.d.ts +0 -27
  268. package/lib/types/documents/runtime.d.ts +0 -59
  269. package/lib/types/documents/security/file-types.d.ts +0 -39
  270. package/lib/types/documents/security/limits.d.ts +0 -24
  271. package/lib/types/documents/security/mime.d.ts +0 -13
  272. package/lib/types/documents/security/paths.d.ts +0 -38
  273. package/lib/types/documents/templates/registry.d.ts +0 -50
  274. package/lib/types/documents/templates/resolver.d.ts +0 -30
  275. package/lib/types/documents/tools/convert.d.ts +0 -9
  276. package/lib/types/documents/tools/create.d.ts +0 -14
  277. package/lib/types/documents/tools/index.d.ts +0 -33
  278. package/lib/types/documents/tools/inspect.d.ts +0 -9
  279. package/lib/types/documents/tools/shared.d.ts +0 -77
  280. package/lib/types/documents/tools/to-markdown.d.ts +0 -12
  281. package/lib/types/documents/types.d.ts +0 -294
@@ -0,0 +1,37 @@
1
+ import type { Agent } from "@deepseek-ai/dsh-agent";
2
+ import type { Context } from "@deepseek-ai/cordis";
3
+ import type { SkillSummary } from "@deepseek-ai/dsh-skill";
4
+ import type { QaCapabilityDescriptor, QaSkillDescriptor } from "../types.js";
5
+ export interface CapabilityCatalogSnapshot {
6
+ readonly descriptors: readonly QaCapabilityDescriptor[];
7
+ readonly toolIds: ReadonlySet<string>;
8
+ /** Installed skills a model-facing catalog may list. */
9
+ readonly skillIds: ReadonlySet<string>;
10
+ /** Installed skills a person may invoke, including model-hidden ones. */
11
+ readonly userSkillIds: ReadonlySet<string>;
12
+ readonly skills: ReadonlyMap<string, SkillSummary>;
13
+ /** Normalized `metadata.qa-surface` of every discovered skill. */
14
+ readonly skillMetadata: ReadonlyMap<string, QaSkillDescriptor>;
15
+ }
16
+ /** Read-only adapter over the current DSH registries. */
17
+ export declare class QaCapabilityCatalog {
18
+ private readonly ctx;
19
+ private readonly additionalToolNames;
20
+ /** Role ids used to report unknown subrole ids in skill metadata. */
21
+ private readonly knownSubroles;
22
+ constructor(ctx: Context, additionalToolNames?: () => readonly string[],
23
+ /** Role ids used to report unknown subrole ids in skill metadata. */
24
+ knownSubroles?: () => readonly string[]);
25
+ snapshot(agent?: Agent): Promise<CapabilityCatalogSnapshot>;
26
+ /**
27
+ * Read `metadata.qa-surface` of every discovered skill.
28
+ *
29
+ * The registry exposes metadata on loaded definitions only, so discovery has
30
+ * to fetch each body once. A provider that fails or a skill that disappears
31
+ * between the two reads degrades to the fail-closed descriptor instead of
32
+ * failing the whole catalog.
33
+ */
34
+ private readSkillMetadata;
35
+ }
36
+ export declare function withMissingCapabilities(descriptors: readonly QaCapabilityDescriptor[], configuredTools: readonly string[], configuredSkills: readonly string[]): readonly QaCapabilityDescriptor[];
37
+ //# sourceMappingURL=capability-catalog.d.ts.map
@@ -0,0 +1,60 @@
1
+ import type { QaCapabilityConfig, QaCapabilityDescriptor, QaCapabilitySelection, QaEffectiveCapabilityPolicy, QaSkillAccess, QaSkillAssignmentOverride, QaSkillDescriptor, QaSubrole, QaToolSelection, QaUserAccess } from "../types.js";
2
+ /**
3
+ * Normalize one Tool selection, accepting the pre-split flat list.
4
+ *
5
+ * A flat list predates skill grants and can only mean "always visible": the
6
+ * legacy reading is the narrower one, so an upgraded deployment never hands
7
+ * out a tool it did not hand out before.
8
+ * @param value - split selection, legacy string list, or nothing.
9
+ * @param label - prefix for validation errors.
10
+ */
11
+ export declare function normalizeToolSelection(value: QaToolSelection | readonly string[] | undefined, label?: string): QaToolSelection;
12
+ export declare function normalizeCapabilitySelection(value: Partial<QaCapabilitySelection> | undefined): QaCapabilitySelection;
13
+ export declare function normalizeSubrole(value: QaSubrole): QaSubrole;
14
+ export declare function normalizeSkillOverrides(value: readonly QaSkillAssignmentOverride[] | undefined): readonly QaSkillAssignmentOverride[];
15
+ export declare function normalizeCapabilityConfig(value: QaCapabilityConfig): QaCapabilityConfig;
16
+ export declare function defaultCapabilityConfig(): QaCapabilityConfig;
17
+ export declare function enabledSubroles(config: QaCapabilityConfig): readonly QaSubrole[];
18
+ export declare function enabledSubroleIds(config: QaCapabilityConfig): readonly string[];
19
+ /** The Common and subrole Tool selections that apply to one subrole. */
20
+ export declare function roleToolSelection(config: QaCapabilityConfig, subroleId: string): QaToolSelection;
21
+ /** The ceiling that bounds what one activated skill may add to the toolset. */
22
+ export declare function roleGrantCeiling(config: QaCapabilityConfig, subroleId: string): readonly string[];
23
+ /** Missing assignments migrate to the first enabled role, never to all roles. */
24
+ export declare function normalizeUserAccess(value: Partial<QaUserAccess> | undefined, config: QaCapabilityConfig): QaUserAccess;
25
+ export interface CapabilityAvailability {
26
+ readonly tools: ReadonlySet<string>;
27
+ /** Installed skills a model-facing catalog may list. */
28
+ readonly skills: ReadonlySet<string>;
29
+ /** Installed skills a person may invoke; defaults to the model-facing set. */
30
+ readonly userSkills?: ReadonlySet<string>;
31
+ }
32
+ export interface ResolveCapabilityPolicyInput {
33
+ readonly config: QaCapabilityConfig;
34
+ readonly subroleId: string;
35
+ readonly systemTools: readonly string[];
36
+ readonly systemSkills: readonly string[];
37
+ readonly available: CapabilityAvailability;
38
+ /** Normalized `metadata.qa-surface` of every discovered skill. */
39
+ readonly skillMetadata?: ReadonlyMap<string, QaSkillDescriptor>;
40
+ /** Revision recorded with the session snapshot; opaque to enforcement. */
41
+ readonly revision?: string;
42
+ }
43
+ export declare function resolveCapabilityPolicy({ config, subroleId, systemTools, systemSkills, available: installed, skillMetadata, revision, }: ResolveCapabilityPolicyInput): QaEffectiveCapabilityPolicy;
44
+ export interface ResolveSkillAccessInput {
45
+ readonly config: QaCapabilityConfig;
46
+ /** Every discovered skill with its normalized metadata. */
47
+ readonly descriptors: ReadonlyMap<string, QaSkillDescriptor>;
48
+ /** Catalog rows for skills, used for description, source and presence. */
49
+ readonly rows: readonly QaCapabilityDescriptor[];
50
+ readonly installedTools: ReadonlySet<string>;
51
+ }
52
+ /**
53
+ * Project every skill for the administration surface.
54
+ *
55
+ * The declared audience is reported next to the effective one, so an
56
+ * administrator can see which roles a skill asked for and which it got.
57
+ * @param input - configuration, resolved metadata and the installed catalog.
58
+ */
59
+ export declare function resolveSkillAccess(input: ResolveSkillAccessInput): readonly QaSkillAccess[];
60
+ //# sourceMappingURL=model.d.ts.map
@@ -0,0 +1,32 @@
1
+ import type { QaAccessAuditEvent, QaCapabilityConfig, QaCapabilitySelection, QaSkillAssignmentOverride, QaSubrole } from "../types.js";
2
+ export declare function defaultCapabilityFilePath(): string;
3
+ /** Atomic, externally reloadable source of truth for roles and their audit. */
4
+ export declare class QaRoleRepository {
5
+ readonly filePath: string;
6
+ private file;
7
+ private fileStamp;
8
+ constructor(filePath?: string);
9
+ snapshot(): QaCapabilityConfig;
10
+ audit(): readonly QaAccessAuditEvent[];
11
+ create(actorId: string, input: QaSubrole): QaSubrole;
12
+ update(actorId: string, id: string, input: QaSubrole): QaSubrole;
13
+ delete(actorId: string, id: string): void;
14
+ updateCommon(actorId: string, input: QaCapabilitySelection): QaCapabilitySelection;
15
+ /**
16
+ * Replace one skill's administrator overlay.
17
+ *
18
+ * An overlay with nothing left to declare is removed outright, so clearing a
19
+ * row in the administration surface leaves the file as if it was never set.
20
+ * @param actorId - the administrator performing the change.
21
+ * @param input - the overlay as edited in the browser.
22
+ * @returns every overlay in force after the change.
23
+ */
24
+ updateSkillOverride(actorId: string, input: QaSkillAssignmentOverride): readonly QaSkillAssignmentOverride[];
25
+ recordAssignment(actorId: string, targetId: string, before: unknown, after: unknown): void;
26
+ private replace;
27
+ private appendAudit;
28
+ private reload;
29
+ private load;
30
+ private persist;
31
+ }
32
+ //# sourceMappingURL=role-repository.d.ts.map
@@ -0,0 +1,57 @@
1
+ import type { Agent } from "@deepseek-ai/dsh-agent";
2
+ import type { Context } from "@deepseek-ai/cordis";
3
+ import type { PluginLogger } from "@yadsh/dsh-plugin-log";
4
+ import type { QaAccounts } from "../accounts/store.js";
5
+ import type { QaAgentToolGrants } from "../enforcement/tool-grants.js";
6
+ import type { QaAccessAdminSnapshot, QaCapabilityConfig, QaCapabilityDescriptor, QaCapabilitySelection, QaCurrentAccess, QaEffectiveCapabilityPolicy, QaSessionAccess, QaSkillActivationRecord, QaSkillAssignmentOverride, QaSubrole, QaUserAccess, ResolvedQaSurfaceConfig } from "../types.js";
7
+ import { QaCapabilityCatalog, type CapabilityCatalogSnapshot } from "./capability-catalog.js";
8
+ import { QaRoleRepository } from "./role-repository.js";
9
+ export interface QaResolvedSessionPolicy {
10
+ readonly policy: QaEffectiveCapabilityPolicy;
11
+ readonly skills: CapabilityCatalogSnapshot["skills"];
12
+ readonly skillMetadata: CapabilityCatalogSnapshot["skillMetadata"];
13
+ /** Preview sessions label their own activation records. */
14
+ readonly adminPreview: boolean;
15
+ /**
16
+ * Build the live tool policy of one agent. The admission calls this only
17
+ * when it installs a policy, so a repeated attestation never stacks a second
18
+ * scoped restriction.
19
+ */
20
+ readonly createGrants: () => QaAgentToolGrants;
21
+ }
22
+ /** Server-only orchestration of roles, assignments, discovery and snapshots. */
23
+ export declare class QaAccessService {
24
+ private readonly options;
25
+ readonly roles: QaRoleRepository;
26
+ readonly catalog: QaCapabilityCatalog;
27
+ constructor(ctx: Context, options: {
28
+ readonly accounts: () => QaAccounts | undefined;
29
+ readonly config: () => ResolvedQaSurfaceConfig;
30
+ readonly logger: PluginLogger;
31
+ readonly repository?: QaRoleRepository;
32
+ readonly dynamicToolNames?: () => readonly string[];
33
+ });
34
+ current(token: string): QaCurrentAccess;
35
+ session(token: string, sessionId: string): QaSessionAccess;
36
+ reserveSession(token: string, sessionId: string, requestedSubrole: string | null, adminPreview: boolean): import("../types.js").QaAccountUserPublic;
37
+ policyForSession(token: string, sessionId: string, agent: Agent): Promise<QaResolvedSessionPolicy | undefined>;
38
+ /** Activation history of one session, for review and quality analysis. */
39
+ skillActivations(token: string, sessionId: string): readonly QaSkillActivationRecord[];
40
+ /** Append one activation attempt; a lost record never fails the session. */
41
+ private recordSkillActivation;
42
+ adminSnapshot(token: string): Promise<QaAccessAdminSnapshot>;
43
+ /** Replace or clear one skill's administrator overlay. */
44
+ updateSkillOverride(token: string, input: QaSkillAssignmentOverride): readonly QaSkillAssignmentOverride[];
45
+ createSubrole(token: string, input: QaSubrole): QaSubrole;
46
+ updateSubrole(token: string, id: string, input: QaSubrole): QaSubrole;
47
+ deleteSubrole(token: string, id: string, replacementId: string | null): void;
48
+ updateCommon(token: string, input: QaCapabilitySelection): QaCapabilitySelection;
49
+ updateAssignment(token: string, userId: string, input: QaUserAccess): QaUserAccess;
50
+ private requireAccounts;
51
+ /** The activation diagnostic is runtime plumbing, not an administrator grant. */
52
+ private systemRequiredTools;
53
+ private requireAdmin;
54
+ }
55
+ export declare function validateCapabilityConfig(config: QaCapabilityConfig): QaCapabilityConfig;
56
+ export type { QaCapabilityDescriptor };
57
+ //# sourceMappingURL=service.d.ts.map
@@ -0,0 +1,53 @@
1
+ import type { QaSkillAssignmentOverride, QaSkillDescriptor, QaSkillHealth } from "../types.js";
2
+ /** The fail-closed descriptor of a skill that declares nothing. */
3
+ export declare function unassignedSkill(name: string): QaSkillDescriptor;
4
+ /**
5
+ * Read and normalize one skill's `metadata.qa-surface` block.
6
+ *
7
+ * The block is advisory input, never an authority: it decides who may see the
8
+ * skill and which tools the skill needs, while the role ceiling still decides
9
+ * whether a tool can ever be granted. Malformed input degrades to the
10
+ * fail-closed default and is reported instead of throwing, because one broken
11
+ * skill must not take down discovery for the whole deployment.
12
+ * @param name - the skill name the registry resolved, not the metadata's.
13
+ * @param metadata - the raw frontmatter `metadata` object, if any.
14
+ * @param knownSubroles - role ids that currently exist, for typo reporting.
15
+ * @returns the normalized descriptor with every complaint in `warnings`.
16
+ */
17
+ export declare function parseQaSkillMetadata(name: string, metadata: Readonly<Record<string, unknown>> | undefined, knownSubroles: ReadonlySet<string>): QaSkillDescriptor;
18
+ /** Validate one administrator overlay row before it reaches the policy file. */
19
+ export declare function normalizeSkillOverride(value: QaSkillAssignmentOverride): QaSkillAssignmentOverride;
20
+ /** One skill's effective audience after the administrator overlay. */
21
+ export interface QaSkillVisibility {
22
+ readonly declaredTo: readonly string[];
23
+ readonly visibleTo: readonly string[];
24
+ readonly addedByAdmin: readonly string[];
25
+ readonly removedByAdmin: readonly string[];
26
+ readonly disabled: boolean;
27
+ /** Whether the overlay actually changed the declared outcome. */
28
+ readonly overridden: boolean;
29
+ }
30
+ /**
31
+ * Merge one skill's declared audience with its administrator overlay.
32
+ *
33
+ * The declared list is only a default: an administrator may extend it, force
34
+ * the skill on for every role, or withdraw it. A withdrawal always wins over
35
+ * an addition, so a contradictory pair of edits can only narrow access.
36
+ * @param descriptor - normalized metadata of the skill.
37
+ * @param override - administrator overlay, when one exists.
38
+ * @param enabledRoles - ids of subroles that are currently enabled.
39
+ */
40
+ export declare function resolveSkillVisibility(descriptor: QaSkillDescriptor, override: QaSkillAssignmentOverride | undefined, enabledRoles: readonly string[]): QaSkillVisibility;
41
+ /**
42
+ * Computed health of one skill for the administration table.
43
+ *
44
+ * `blocked` and `degraded` differ only in what `requireAll` promises: a strict
45
+ * skill refuses to activate at all, a best-effort one activates with a warning.
46
+ * @param descriptor - normalized metadata carrying the requirement list.
47
+ * @param available - required tools that are installed and grantable for at
48
+ * least one role that can see the skill.
49
+ * @param missing - required tools no visible role could ever grant.
50
+ * @param visibleTo - roles that currently see the skill.
51
+ */
52
+ export declare function skillHealth(descriptor: QaSkillDescriptor, available: number, missing: number, visibleTo: readonly string[]): QaSkillHealth;
53
+ //# sourceMappingURL=skill-metadata.d.ts.map
@@ -13,6 +13,12 @@ export interface QaAccountRemotes {
13
13
  resolve(config: ResolvedQaSurfaceConfig): QaAccounts | undefined;
14
14
  /** Map a store failure onto the shared `(reason: <code>)` wire marker. */
15
15
  run<T>(operation: () => T, sessionIdForLog?: string): T;
16
+ /**
17
+ * The same mapping for an asynchronous body. A refusal thrown after an
18
+ * `await` never reaches a synchronous `run`, and the administrative reads
19
+ * await stored logs before they can decide anything.
20
+ */
21
+ runAsync<T>(operation: () => Promise<T>, sessionIdForLog?: string): Promise<T>;
16
22
  register(email: string, password: string): QaAccountSession;
17
23
  login(email: string, password: string): QaAccountSession;
18
24
  /** Identity probe; safe to call with an empty or expired token. */
@@ -3,7 +3,7 @@
3
3
  * marker pattern the attestation path established; the browser maps them to
4
4
  * audience-safe copy and the precise cause stays in the Host logs.
5
5
  */
6
- export type QaAccountsErrorReason = "auth-required" | "admin-required" | "invalid-credentials" | "account-disabled" | "email-taken" | "invalid-email" | "invalid-display-name" | "invalid-profile" | "profile-disabled" | "invalid-starters" | "starters-disabled" | "invalid-role" | "weak-password" | "registration-disabled" | "rate-limited" | "session-owned-elsewhere";
6
+ export type QaAccountsErrorReason = "auth-required" | "admin-required" | "forbidden" | "invalid-credentials" | "account-disabled" | "email-taken" | "invalid-email" | "invalid-display-name" | "invalid-profile" | "profile-disabled" | "invalid-starters" | "starters-disabled" | "invalid-role" | "weak-password" | "registration-disabled" | "rate-limited" | "session-owned-elsewhere";
7
7
  export declare class QaAccountsError extends Error {
8
8
  readonly reason: QaAccountsErrorReason;
9
9
  constructor(reason: QaAccountsErrorReason, message: string);
@@ -1,5 +1,5 @@
1
1
  import type { Stats } from "node:fs";
2
- import type { QaAccountRole } from "../types.js";
2
+ import type { QaAccountRole, QaEffectiveCapabilityPolicy, QaSkillActivationRecord, QaUserAccess } from "../types.js";
3
3
  /** One account's self-declared profile as it rests in the accounts file. */
4
4
  export interface StoredProfile {
5
5
  fullName?: string;
@@ -38,16 +38,27 @@ export interface StoredUser {
38
38
  profile?: StoredProfile;
39
39
  /** Absent until the owner customizes the starter buttons. */
40
40
  starters?: StoredStarters;
41
+ /** Agent capability profiles assigned by an administrator. */
42
+ qaAccess?: QaUserAccess;
43
+ }
44
+ export interface StoredOwnership {
45
+ readonly userId: string;
46
+ readonly claimedAt: string;
47
+ /** Pinned at creation; absent only on sessions predating subroles. */
48
+ readonly subroleId?: string;
49
+ /** Admin preview is an explicit session fact, never inferred from role=admin. */
50
+ readonly adminPreview?: boolean;
51
+ /** First successful admission freezes the actually installed capabilities. */
52
+ readonly capabilitySnapshot?: QaEffectiveCapabilityPolicy;
53
+ /** Skill activations in order: what the model gained, and when it gained it. */
54
+ readonly skillActivations?: readonly QaSkillActivationRecord[];
41
55
  }
42
56
  export interface AccountsFile {
43
57
  readonly version: 1;
44
58
  /** HMAC key for account tokens; rotated on password change by rewriting it. */
45
59
  readonly secret: string;
46
60
  readonly users: StoredUser[];
47
- readonly ownership: Record<string, {
48
- readonly userId: string;
49
- readonly claimedAt: string;
50
- }>;
61
+ readonly ownership: Record<string, StoredOwnership>;
51
62
  }
52
63
  /** mtime+size pair identifying one on-disk version of the accounts file. */
53
64
  export interface FileStamp {
@@ -1,5 +1,5 @@
1
- import type { QaAccountIdentityField, QaAccountProfile, QaAccountProfileInput, QaAccountRole, QaAccountSession, QaAccountStartersInput, QaAccountUserPublic, QaClaimResult, QaOwnershipEntry, QaWhoamiResult } from "../types.js";
2
- import type { StoredUser } from "./file.js";
1
+ import type { QaAccountIdentityField, QaAccountProfile, QaAccountProfileInput, QaAccountRole, QaAccountSession, QaAccountStartersInput, QaAccountUserPublic, QaAccessUser, QaAdminAccountRow, QaClaimResult, QaEffectiveCapabilityPolicy, QaOwnershipEntry, QaSkillActivationRecord, QaUserAccess, QaWhoamiResult } from "../types.js";
2
+ import type { StoredOwnership, StoredUser } from "./file.js";
3
3
  export { QaAccountsError } from "./errors.js";
4
4
  export type { QaAccountsErrorReason } from "./errors.js";
5
5
  export { defaultAccountsFilePath } from "./file.js";
@@ -58,6 +58,8 @@ export declare class QaAccounts {
58
58
  private mintToken;
59
59
  /** The account behind a token, or an auth-required refusal. */
60
60
  requireUser(token: string): StoredUser;
61
+ /** Public identity behind a token; used by server-side access services. */
62
+ currentUser(token: string): QaAccountUserPublic;
61
63
  /**
62
64
  * Ownership gate for one session: claim unowned sessions for the requesting
63
65
  * user (first come, first served — the pre-accounts migration path), refuse
@@ -69,7 +71,10 @@ export declare class QaAccounts {
69
71
  * the Session exists. Browser callers therefore never get a race window in
70
72
  * which they can claim another user's newly created chat.
71
73
  */
72
- reserveSession(token: string, sessionId: string): QaAccountUserPublic;
74
+ reserveSession(token: string, sessionId: string, access?: {
75
+ readonly subroleId: string;
76
+ readonly adminPreview?: boolean;
77
+ }): QaAccountUserPublic;
73
78
  /** Roll back a reservation if Host creation failed before a chat existed. */
74
79
  releaseSessionReservation(userId: string, sessionId: string): void;
75
80
  /** Bulk-claim a browser's local chat index; foreign ids come back as conflicts. */
@@ -91,12 +96,87 @@ export declare class QaAccounts {
91
96
  readonly createdAt: string;
92
97
  readonly lastLoginAt: string | null;
93
98
  }[];
99
+ /** Browser-safe administration rows with capability assignments. */
100
+ listAccessUsers(resolve: (stored: QaUserAccess | undefined) => QaUserAccess): readonly QaAccessUser[];
101
+ /**
102
+ * Every account with the administrative columns the admin console renders:
103
+ * identity, status, authorization role, assignment and the timestamps of the
104
+ * account's own life. Credentials and token material are never projected.
105
+ */
106
+ listAdminUsers(resolve: (stored: QaUserAccess | undefined) => QaUserAccess): readonly QaAdminAccountRow[];
107
+ /**
108
+ * Identity columns of every account, without their capability assignment.
109
+ * The console's name lookup: an audit row or a queue entry names an account
110
+ * by id, and the table needs a label for it.
111
+ */
112
+ directory(): readonly {
113
+ readonly id: string;
114
+ readonly email: string;
115
+ readonly displayName: string;
116
+ readonly role: QaAccountRole;
117
+ readonly disabled: boolean;
118
+ }[];
119
+ /** One account's administrative row, or undefined for an unknown id. */
120
+ adminUser(userId: string, resolve: (stored: QaUserAccess | undefined) => QaUserAccess): QaAdminAccountRow | undefined;
121
+ /**
122
+ * Every session reservation with its pinned role and capability snapshot.
123
+ * This is the deployment's own conversation index: a QA chat exists here
124
+ * from the moment its id is reserved, before any message is written.
125
+ */
126
+ listOwnershipRecords(): readonly {
127
+ readonly sessionId: string;
128
+ readonly userId: string;
129
+ readonly claimedAt: string;
130
+ readonly subroleId?: string;
131
+ readonly adminPreview?: boolean;
132
+ readonly capabilitySnapshot?: QaEffectiveCapabilityPolicy;
133
+ }[];
134
+ /** Replace one account's authorization role, addressed by stable id. */
135
+ setAccessRole(userId: string, role: QaAccountRole): QaAccountUserPublic;
136
+ /**
137
+ * Disable or enable one account by id. Same semantics as the operator
138
+ * {@link setUserDisabled}: disabling also invalidates every live token, and
139
+ * enabling does not bring the old ones back.
140
+ */
141
+ setAccessDisabled(userId: string, disabled: boolean): QaAccountUserPublic;
142
+ /** Stored assignment for one account; callers normalize missing legacy rows. */
143
+ accessOf(userId: string): QaUserAccess | undefined;
144
+ /** Admin-owned assignment write addressed by stable account id. */
145
+ setAccess(userId: string, access: QaUserAccess): QaUserAccess;
146
+ /** Persisted role and immutable policy record for one Host session. */
147
+ sessionAccess(sessionId: string): StoredOwnership | undefined;
148
+ /** Migrate a pre-subrole session or finalize its first policy snapshot. */
149
+ updateSessionAccess(sessionId: string, update: {
150
+ readonly subroleId?: string;
151
+ readonly adminPreview?: boolean;
152
+ readonly capabilitySnapshot?: QaEffectiveCapabilityPolicy;
153
+ }): StoredOwnership;
154
+ /**
155
+ * Append one skill activation attempt to a session's history.
156
+ *
157
+ * The record is the reviewable half of a dynamic tool grant: it names what
158
+ * the skill asked for, what it received and what it was refused. The list is
159
+ * bounded, because a long session may activate skills many times and the
160
+ * oldest entries stop being interesting long before the file does.
161
+ * @param sessionId - the session the activation belongs to.
162
+ * @param entry - the attempt to append.
163
+ * @param limit - how many entries to keep, newest last.
164
+ * @returns the stored history after the append.
165
+ */
166
+ recordSkillActivation(sessionId: string, entry: QaSkillActivationRecord, limit: number): readonly QaSkillActivationRecord[];
94
167
  /** Create an account outside the self-registration gate. */
95
168
  addUser(email: string, password: string, options?: {
96
169
  displayName?: string;
97
170
  role?: QaAccountRole;
98
171
  }): QaAccountUserPublic;
99
172
  private editUser;
173
+ /**
174
+ * Same read-modify-write as {@link editUser}, addressed by account id. The
175
+ * administrative console works in ids: an email is a credential-shaped
176
+ * handle the operator may change, while the id is what conversations,
177
+ * feedback and audit rows already reference.
178
+ */
179
+ private editUserById;
100
180
  /** Grant or revoke the admin role. */
101
181
  setUserRole(email: string, role: QaAccountRole): QaAccountUserPublic;
102
182
  /**
@@ -0,0 +1,39 @@
1
+ import type { QaConversationMessage } from "../types.js";
2
+ import type { QaAdminRedactor } from "./redaction.js";
3
+ /**
4
+ * Projection of a stored session log into the reviewer's transcript.
5
+ *
6
+ * The admin viewer reads the event log rather than the live agent state: a
7
+ * conversation is reviewed weeks after it happened, usually on a process that
8
+ * has never had it open. The projection therefore walks the raw event order and
9
+ * shows what the log recorded — it does not re-derive model history, so a
10
+ * compaction or a surface replacement never hides evidence from a reviewer.
11
+ *
12
+ * Messages are identified by their event `seq`, the one identity both the
13
+ * durable log and the browser transcript agree on. A rating recorded against
14
+ * `seq` keeps pointing at the same assistant message after the log is replayed.
15
+ */
16
+ /** The events read back from durable storage; only these fields are used. */
17
+ export interface StoredSessionEvent {
18
+ readonly seq: number;
19
+ readonly time?: number;
20
+ readonly type: string;
21
+ readonly data?: unknown;
22
+ }
23
+ export interface QaProjectedTranscript {
24
+ readonly title?: string;
25
+ readonly messages: readonly QaConversationMessage[];
26
+ readonly model?: string;
27
+ readonly provider?: string;
28
+ /** Skills the model loaded, in first-use order, from its skill tool calls. */
29
+ readonly loadedSkills: readonly string[];
30
+ /** Newest event time in the log, when the log carried one. */
31
+ readonly lastActivity?: number;
32
+ }
33
+ /**
34
+ * Project one log into the review transcript. Unknown event types are skipped,
35
+ * not refused: a deployment may carry plugin events this package has never
36
+ * heard of, and a review console must still show the conversation.
37
+ */
38
+ export declare function projectTranscript(events: readonly StoredSessionEvent[], redactor: QaAdminRedactor): QaProjectedTranscript;
39
+ //# sourceMappingURL=conversation-log.d.ts.map
@@ -0,0 +1,24 @@
1
+ /**
2
+ * The administrative console's server side: authorization, conversation
3
+ * queries over stored session logs, the quality records (feedback, reviews,
4
+ * the derived queue, the audit trail) and their aggregations.
5
+ */
6
+ export { QaAdminService } from "./service.js";
7
+ export type { QaAdminServiceOptions } from "./service.js";
8
+ export { QA_ADMIN_PAGE_DEFAULT, QA_ADMIN_PAGE_MAX, QA_ADMIN_SCAN_LIMIT, } from "./service.js";
9
+ export { allows, permissionsOf, readsEveryConversation, } from "./permissions.js";
10
+ export { QaQualityStore, defaultQualityFilePath } from "./quality-store.js";
11
+ export type { QaManualQueueEntry } from "./quality-store.js";
12
+ export { QA_FEEDBACK_REASONS, QA_FEEDBACK_RATINGS, QA_QUALITY_ISSUES, QA_QUALITY_SEVERITIES, QA_REMEDIATION_TARGETS, } from "./quality-store.js";
13
+ export { aggregateQuality } from "./metrics.js";
14
+ export type { QaConversationFact } from "./metrics.js";
15
+ export { deriveQueue } from "./queue.js";
16
+ export type { QaQueueInput, QaToolFailureSignal } from "./queue.js";
17
+ export { paginate } from "./paging.js";
18
+ export { projectTranscript } from "./conversation-log.js";
19
+ export type { QaProjectedTranscript, StoredSessionEvent, } from "./conversation-log.js";
20
+ export { createSessionLogReader, staticSessionLogReader, } from "./session-log.js";
21
+ export type { QaSessionLogReader, QaSessionReadResult, QaStoredSessionHeader, } from "./session-log.js";
22
+ export { defaultAdminRedactor, maskSecrets } from "./redaction.js";
23
+ export type { QaAdminRedactor } from "./redaction.js";
24
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,29 @@
1
+ import type { QaConversationReview, QaFeedbackRating, QaMessageFeedback, QaQualityMetrics } from "../types.js";
2
+ /**
3
+ * Quality aggregation.
4
+ *
5
+ * The numbers here are named for what they are. A thumbs-up is a user
6
+ * satisfaction signal, not an accuracy measurement: this module never reports
7
+ * a rate that reads as ground truth, and the API surfaces carry the same
8
+ * wording (spec §26).
9
+ */
10
+ /** What one conversation contributes, however cheaply it was obtained. */
11
+ export interface QaConversationFact {
12
+ readonly conversationId: string;
13
+ readonly userId: string;
14
+ readonly subroleId: string;
15
+ readonly assistantMessages: number;
16
+ /** Epoch ms of the conversation's creation, for the activity window. */
17
+ readonly createdAt: number;
18
+ }
19
+ export interface QaAggregationInput {
20
+ readonly conversations: readonly QaConversationFact[];
21
+ readonly feedback: readonly QaMessageFeedback[];
22
+ readonly reviews: readonly QaConversationReview[];
23
+ /** Days of feedback history the trend shows; older buckets are dropped. */
24
+ readonly trendDays?: number;
25
+ }
26
+ export declare function aggregateQuality({ conversations, feedback, reviews, trendDays, }: QaAggregationInput): QaQualityMetrics;
27
+ /** One rating's contribution to a conversation row, without re-reading logs. */
28
+ export declare function countRatings(feedback: readonly QaMessageFeedback[]): Readonly<Record<QaFeedbackRating, number>>;
29
+ //# sourceMappingURL=metrics.d.ts.map
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Cursor paging shared by every administrative list. Admin tables read from
3
+ * append-only files whose newest entries arrive last, so a list is always
4
+ * materialized newest-first and a cursor names the last row the caller saw.
5
+ *
6
+ * The cursor is the row's sort key plus its identity, never an offset: rows
7
+ * keep arriving while a reviewer pages, and an offset would then skip or
8
+ * repeat entries.
9
+ */
10
+ export interface QaPage<T> {
11
+ readonly items: readonly T[];
12
+ readonly nextCursor: string | null;
13
+ readonly total: number;
14
+ }
15
+ export interface QaPageRequest<T> {
16
+ /** Rows in their final order, newest first. */
17
+ readonly rows: readonly T[];
18
+ /** The composite sort key of one row; must be unique together with the id. */
19
+ readonly keyOf: (row: T) => string;
20
+ /** The row's stable identity. */
21
+ readonly idOf: (row: T) => string;
22
+ /** Cursor returned by the previous page; absent for the first page. */
23
+ readonly cursor?: string | undefined;
24
+ /** Requested page size, clamped by the caller's own bounds. */
25
+ readonly limit: number;
26
+ }
27
+ /**
28
+ * Slice one page out of an already-sorted list. An unknown cursor is treated as
29
+ * the start of the list: it can only mean the row was trimmed away since the
30
+ * caller last paged, in which case restarting is the honest answer.
31
+ */
32
+ export declare function paginate<T>({ rows, keyOf, idOf, cursor, limit, }: QaPageRequest<T>): QaPage<T>;
33
+ //# sourceMappingURL=paging.d.ts.map
@@ -0,0 +1,10 @@
1
+ import type { QaAccountRole, QaPermission } from "../types.js";
2
+ /** Every permission this package knows; the Remote surface validates against it. */
3
+ export declare const QA_PERMISSIONS: readonly QaPermission[];
4
+ /** The permissions one authorization role grants, deduplicated. */
5
+ export declare function permissionsOf(role: QaAccountRole): readonly QaPermission[];
6
+ /** Whether one role grants one permission. */
7
+ export declare function allows(role: QaAccountRole, permission: QaPermission): boolean;
8
+ /** Whether this role may read conversations it does not own. */
9
+ export declare function readsEveryConversation(role: QaAccountRole): boolean;
10
+ //# sourceMappingURL=permissions.d.ts.map
@@ -0,0 +1,82 @@
1
+ import type { QaAdminAuditAction, QaAdminAuditEvent, QaConversationReview, QaConversationReviewInput, QaFeedbackReason, QaFeedbackRating, QaMessageFeedback, QaMessageFeedbackInput, QaQualityIssueType, QaQualitySeverity, QaRemediationTarget } from "../types.js";
2
+ /**
3
+ * The durable quality file: user feedback, reviewer results, the manual review
4
+ * queue and the administrative audit trail.
5
+ *
6
+ * It is deliberately separate from the capability policy file: role
7
+ * configuration is a deployment artifact an operator may replace wholesale,
8
+ * while feedback and reviews are user data that must survive such a reset.
9
+ */
10
+ export declare const QA_FEEDBACK_RATINGS: readonly QaFeedbackRating[];
11
+ export declare const QA_FEEDBACK_REASONS: readonly QaFeedbackReason[];
12
+ export declare const QA_QUALITY_ISSUES: readonly QaQualityIssueType[];
13
+ export declare const QA_QUALITY_SEVERITIES: readonly QaQualitySeverity[];
14
+ export declare const QA_REMEDIATION_TARGETS: readonly QaRemediationTarget[];
15
+ export interface QaManualQueueEntry {
16
+ readonly conversationId: string;
17
+ readonly messageId?: string;
18
+ /** The reviewer who parked it; a queue entry is a deliberate act. */
19
+ readonly userId: string;
20
+ readonly createdAt: string;
21
+ }
22
+ export declare function defaultQualityFilePath(): string;
23
+ /**
24
+ * Atomic, externally reloadable store for the quality layer. Writes are
25
+ * synchronous and persisted with a temp file plus rename, matching the accounts
26
+ * and capability files: LAN scale keeps this trivial, and a reload probe keeps
27
+ * a second process's write visible.
28
+ *
29
+ * Rows are re-validated on read rather than trusted: a hand-edited file cannot
30
+ * inject a record the writers would have refused. A malformed row is reported
31
+ * instead of dropped — writes are atomic, so it can only mean someone edited
32
+ * the file, and silently discarding a user's record would hide that.
33
+ */
34
+ export declare class QaQualityStore {
35
+ readonly filePath: string;
36
+ private file;
37
+ private fileStamp;
38
+ constructor(filePath?: string);
39
+ /**
40
+ * Record or replace one user's rating of one message. Re-rating the same
41
+ * message overwrites in place rather than appending: a reviewer reads the
42
+ * user's current verdict, and the first-seen time stays with it.
43
+ */
44
+ rateFeedback(input: {
45
+ readonly conversationId: string;
46
+ readonly messageId: string;
47
+ readonly userId: string;
48
+ }, feedback: QaMessageFeedbackInput): QaMessageFeedback;
49
+ allFeedback(): readonly QaMessageFeedback[];
50
+ /** Ratings of one conversation, newest first. */
51
+ feedbackOfConversation(conversationId: string): readonly QaMessageFeedback[];
52
+ /** One exact rating, for the viewer's per-message thumbs state. */
53
+ feedbackOf(conversationId: string, messageId: string, userId: string): QaMessageFeedback | undefined;
54
+ /** Save a reviewer's result, replacing that reviewer's earlier verdict. */
55
+ saveReview(reviewerId: string, input: QaConversationReviewInput): {
56
+ readonly review: QaConversationReview;
57
+ readonly created: boolean;
58
+ };
59
+ allReviews(): readonly QaConversationReview[];
60
+ reviewsOfConversation(conversationId: string): readonly QaConversationReview[];
61
+ /** Park one conversation for review; re-parking the same target is a no-op. */
62
+ enqueueReview(userId: string, conversationId: string, messageId?: string): QaManualQueueEntry;
63
+ /** Drop a manual queue entry once a reviewer has answered it. */
64
+ dequeueReview(conversationId: string, messageId?: string): boolean;
65
+ manualQueue(): readonly QaManualQueueEntry[];
66
+ /** Append one administrative action to the audit trail. */
67
+ appendAudit(input: {
68
+ readonly actorId: string;
69
+ readonly action: QaAdminAuditAction;
70
+ readonly targetType?: string | undefined;
71
+ readonly targetId?: string | undefined;
72
+ readonly before?: unknown;
73
+ readonly after?: unknown;
74
+ }): QaAdminAuditEvent;
75
+ auditEvents(): readonly QaAdminAuditEvent[];
76
+ /** Serialize one before/after value, refusing what no reader could use. */
77
+ private snapshot;
78
+ private reload;
79
+ private load;
80
+ private persist;
81
+ }
82
+ //# sourceMappingURL=quality-store.d.ts.map