@yadsh/dsh-qa-surface 0.7.4 → 0.9.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 (247) hide show
  1. package/README.md +169 -12
  2. package/compatibility.json +5 -0
  3. package/lib/access/capability-catalog.js +32 -3
  4. package/lib/access/capability-catalog.js.map +1 -1
  5. package/lib/access/model.js +24 -4
  6. package/lib/access/model.js.map +1 -1
  7. package/lib/access/role-repository.js +199 -91
  8. package/lib/access/role-repository.js.map +1 -1
  9. package/lib/access/service.js +223 -7
  10. package/lib/access/service.js.map +1 -1
  11. package/lib/account-remotes.js +2 -4
  12. package/lib/account-remotes.js.map +1 -1
  13. package/lib/accounts/database.js +447 -0
  14. package/lib/accounts/database.js.map +1 -0
  15. package/lib/accounts/errors.js.map +1 -1
  16. package/lib/accounts/file.js +27 -90
  17. package/lib/accounts/file.js.map +1 -1
  18. package/lib/accounts/store.js +224 -59
  19. package/lib/accounts/store.js.map +1 -1
  20. package/lib/admin/permissions.js +4 -0
  21. package/lib/admin/permissions.js.map +1 -1
  22. package/lib/admin/quality-store.js +270 -54
  23. package/lib/admin/quality-store.js.map +1 -1
  24. package/lib/admin/service.js +145 -7
  25. package/lib/admin/service.js.map +1 -1
  26. package/lib/admin/session-log.js +66 -5
  27. package/lib/admin/session-log.js.map +1 -1
  28. package/lib/cli.js +2 -1
  29. package/lib/cli.js.map +1 -1
  30. package/lib/client/QaSessionController.js +379 -39
  31. package/lib/client/QaSessionController.js.map +1 -1
  32. package/lib/client/QaSurface.js +94 -34
  33. package/lib/client/QaSurface.js.map +1 -1
  34. package/lib/client/QaTranscriptAdapter.js +40 -0
  35. package/lib/client/QaTranscriptAdapter.js.map +1 -1
  36. package/lib/client/admin/QaAdmin.js +26 -8
  37. package/lib/client/admin/QaAdmin.js.map +1 -1
  38. package/lib/client/admin/{format.js → copy.js} +1 -1
  39. package/lib/client/admin/copy.js.map +1 -0
  40. package/lib/client/admin/pages/Conversations.js +34 -8
  41. package/lib/client/admin/pages/Conversations.js.map +1 -1
  42. package/lib/client/admin/pages/Overview.js +1 -1
  43. package/lib/client/admin/pages/Overview.js.map +1 -1
  44. package/lib/client/admin/pages/Quality.js +1 -1
  45. package/lib/client/admin/pages/Quality.js.map +1 -1
  46. package/lib/client/admin/pages/Review.js +1 -1
  47. package/lib/client/admin/pages/Review.js.map +1 -1
  48. package/lib/client/admin/pages/Users.js +6 -2
  49. package/lib/client/admin/pages/Users.js.map +1 -1
  50. package/lib/client/admin/shared.js +10 -1
  51. package/lib/client/admin/shared.js.map +1 -1
  52. package/lib/client/admin/styles.js +2 -0
  53. package/lib/client/admin/styles.js.map +1 -1
  54. package/lib/client/audit/QaAuditDialog.js +74 -0
  55. package/lib/client/audit/QaAuditDialog.js.map +1 -0
  56. package/lib/client/audit/QaAuditRowBadge.js +17 -0
  57. package/lib/client/audit/QaAuditRowBadge.js.map +1 -0
  58. package/lib/client/audit/controller.js +39 -0
  59. package/lib/client/audit/controller.js.map +1 -0
  60. package/lib/client/audit/types.js +36 -0
  61. package/lib/client/audit/types.js.map +1 -0
  62. package/lib/client/audit/use-chat-audits.js +139 -0
  63. package/lib/client/audit/use-chat-audits.js.map +1 -0
  64. package/lib/client/components/Markdown.js +14 -206
  65. package/lib/client/components/Markdown.js.map +1 -1
  66. package/lib/client/components/QaChangelog.js +91 -0
  67. package/lib/client/components/QaChangelog.js.map +1 -1
  68. package/lib/client/components/QaComposer.js +63 -3
  69. package/lib/client/components/QaComposer.js.map +1 -1
  70. package/lib/client/components/QaHeader.js +1 -3
  71. package/lib/client/components/QaHeader.js.map +1 -1
  72. package/lib/client/components/QaMessage.js +25 -4
  73. package/lib/client/components/QaMessage.js.map +1 -1
  74. package/lib/client/components/QaQuestions.js +1 -1
  75. package/lib/client/components/QaQuestions.js.map +1 -1
  76. package/lib/client/components/QaSidebar.js +17 -3
  77. package/lib/client/components/QaSidebar.js.map +1 -1
  78. package/lib/client/components/QaSourcesPanel.js +3 -18
  79. package/lib/client/components/QaSourcesPanel.js.map +1 -1
  80. package/lib/client/components/QaWorkGroup.js +4 -8
  81. package/lib/client/components/QaWorkGroup.js.map +1 -1
  82. package/lib/client/components/source-icon.js +26 -0
  83. package/lib/client/components/source-icon.js.map +1 -0
  84. package/lib/client/components/thinking-phrases.js +2 -11
  85. package/lib/client/components/thinking-phrases.js.map +1 -1
  86. package/lib/client/components/use-now.js +21 -0
  87. package/lib/client/components/use-now.js.map +1 -0
  88. package/lib/client/index.js +33 -5
  89. package/lib/client/index.js.map +1 -1
  90. package/lib/client/lineage.js +18 -0
  91. package/lib/client/lineage.js.map +1 -0
  92. package/lib/client/markdown/CodeBlock.js +28 -0
  93. package/lib/client/markdown/CodeBlock.js.map +1 -0
  94. package/lib/client/markdown/blocks.js +342 -0
  95. package/lib/client/markdown/blocks.js.map +1 -0
  96. package/lib/client/markdown/highlight.js +1089 -0
  97. package/lib/client/markdown/highlight.js.map +1 -0
  98. package/lib/client/markdown/inline.js +377 -0
  99. package/lib/client/markdown/inline.js.map +1 -0
  100. package/lib/client/markdown/render.js +147 -0
  101. package/lib/client/markdown/render.js.map +1 -0
  102. package/lib/client/markdown/source-chip.js +55 -0
  103. package/lib/client/markdown/source-chip.js.map +1 -0
  104. package/lib/client/markdown/use-transient-flag.js +27 -0
  105. package/lib/client/markdown/use-transient-flag.js.map +1 -0
  106. package/lib/client/project-session-state.js +15 -2
  107. package/lib/client/project-session-state.js.map +1 -1
  108. package/lib/client/prompt-content.js +26 -0
  109. package/lib/client/prompt-content.js.map +1 -1
  110. package/lib/client/role/RoleSelector.js +11 -2
  111. package/lib/client/role/RoleSelector.js.map +1 -1
  112. package/lib/client/role/preview.js +123 -0
  113. package/lib/client/role/preview.js.map +1 -0
  114. package/lib/client/settings/card.js +2 -2
  115. package/lib/client/settings/card.js.map +1 -1
  116. package/lib/client/settings/sections/lockdown.js +1 -6
  117. package/lib/client/settings/sections/lockdown.js.map +1 -1
  118. package/lib/client/settings/sections/slash.js +57 -0
  119. package/lib/client/settings/sections/slash.js.map +1 -0
  120. package/lib/client/settings/sections/status.js +9 -1
  121. package/lib/client/settings/sections/status.js.map +1 -1
  122. package/lib/client/settings/sections.js +1 -0
  123. package/lib/client/settings/sections.js.map +1 -1
  124. package/lib/client/slash/SlashPalette.js +48 -0
  125. package/lib/client/slash/SlashPalette.js.map +1 -0
  126. package/lib/client/slash/copy.js +54 -0
  127. package/lib/client/slash/copy.js.map +1 -0
  128. package/lib/client/slash/slash-router.js +49 -0
  129. package/lib/client/slash/slash-router.js.map +1 -0
  130. package/lib/client/slash/useSlashNavigation.js +95 -0
  131. package/lib/client/slash/useSlashNavigation.js.map +1 -0
  132. package/lib/client/styles.js +124 -20
  133. package/lib/client/styles.js.map +1 -1
  134. package/lib/client/types.js +11 -0
  135. package/lib/client/types.js.map +1 -1
  136. package/lib/client.js +7615 -1567
  137. package/lib/client.js.map +1 -1
  138. package/lib/config-resolvers/accounts.js +15 -0
  139. package/lib/config-resolvers/accounts.js.map +1 -1
  140. package/lib/config-resolvers/basics.js +11 -2
  141. package/lib/config-resolvers/basics.js.map +1 -1
  142. package/lib/config-resolvers/defaults.js +30 -0
  143. package/lib/config-resolvers/defaults.js.map +1 -1
  144. package/lib/config-resolvers/lockdown.js +8 -2
  145. package/lib/config-resolvers/lockdown.js.map +1 -1
  146. package/lib/config-resolvers/slash-commands.js +60 -0
  147. package/lib/config-resolvers/slash-commands.js.map +1 -0
  148. package/lib/config-resolvers/sources.js +16 -0
  149. package/lib/config-resolvers/sources.js.map +1 -1
  150. package/lib/config.js +118 -2
  151. package/lib/config.js.map +1 -1
  152. package/lib/index.js +183 -11
  153. package/lib/index.js.map +1 -1
  154. package/lib/lockdown-policy.js +19 -0
  155. package/lib/lockdown-policy.js.map +1 -1
  156. package/lib/personal-skills/service.js +16 -3
  157. package/lib/personal-skills/service.js.map +1 -1
  158. package/lib/provenance/host-store.js +25 -4
  159. package/lib/provenance/host-store.js.map +1 -1
  160. package/lib/provenance/retention.js +25 -0
  161. package/lib/provenance/retention.js.map +1 -0
  162. package/lib/provenance/snapshot-store.js +290 -35
  163. package/lib/provenance/snapshot-store.js.map +1 -1
  164. package/lib/questions.js +98 -38
  165. package/lib/questions.js.map +1 -1
  166. package/lib/resolve-config.js +5 -0
  167. package/lib/resolve-config.js.map +1 -1
  168. package/lib/secure-session.js +139 -21
  169. package/lib/secure-session.js.map +1 -1
  170. package/lib/slash/catalog.js +77 -0
  171. package/lib/slash/catalog.js.map +1 -0
  172. package/lib/slash/matcher.js +100 -0
  173. package/lib/slash/matcher.js.map +1 -0
  174. package/lib/slash/parser.js +79 -0
  175. package/lib/slash/parser.js.map +1 -0
  176. package/lib/slash/policy.js +72 -0
  177. package/lib/slash/policy.js.map +1 -0
  178. package/lib/slash/remotes.js +272 -0
  179. package/lib/slash/remotes.js.map +1 -0
  180. package/lib/typert.host.js +348 -56
  181. package/lib/typert.remote-client.d.ts +7 -1
  182. package/lib/typert.remote-client.js +274 -51
  183. package/lib/types/access/capability-catalog.d.ts +28 -1
  184. package/lib/types/access/role-repository.d.ts +38 -7
  185. package/lib/types/access/service.d.ts +106 -3
  186. package/lib/types/account-remotes.d.ts +8 -4
  187. package/lib/types/accounts/database.d.ts +84 -0
  188. package/lib/types/accounts/errors.d.ts +7 -1
  189. package/lib/types/accounts/file.d.ts +17 -39
  190. package/lib/types/accounts/store.d.ts +110 -19
  191. package/lib/types/admin/quality-store.d.ts +38 -2
  192. package/lib/types/admin/service.d.ts +34 -2
  193. package/lib/types/admin/session-log.d.ts +65 -1
  194. package/lib/types/client/QaSessionController.d.ts +84 -2
  195. package/lib/types/client/QaSurface.d.ts +14 -1
  196. package/lib/types/client/admin/{format.d.ts → copy.d.ts} +1 -1
  197. package/lib/types/client/admin/pages/Conversations.d.ts +4 -0
  198. package/lib/types/client/audit/QaAuditDialog.d.ts +21 -0
  199. package/lib/types/client/audit/QaAuditRowBadge.d.ts +18 -0
  200. package/lib/types/client/audit/controller.d.ts +27 -0
  201. package/lib/types/client/audit/types.d.ts +72 -0
  202. package/lib/types/client/audit/use-chat-audits.d.ts +20 -0
  203. package/lib/types/client/components/Markdown.d.ts +7 -8
  204. package/lib/types/client/components/QaComposer.d.ts +12 -2
  205. package/lib/types/client/components/QaQuestions.d.ts +7 -0
  206. package/lib/types/client/components/QaSidebar.d.ts +11 -1
  207. package/lib/types/client/components/QaSourcesPanel.d.ts +1 -3
  208. package/lib/types/client/components/source-icon.d.ts +12 -0
  209. package/lib/types/client/components/use-now.d.ts +8 -0
  210. package/lib/types/client/lineage.d.ts +15 -0
  211. package/lib/types/client/markdown/CodeBlock.d.ts +14 -0
  212. package/lib/types/client/markdown/blocks.d.ts +74 -0
  213. package/lib/types/client/markdown/highlight.d.ts +29 -0
  214. package/lib/types/client/markdown/inline.d.ts +40 -0
  215. package/lib/types/client/markdown/render.d.ts +13 -0
  216. package/lib/types/client/markdown/source-chip.d.ts +32 -0
  217. package/lib/types/client/markdown/use-transient-flag.d.ts +12 -0
  218. package/lib/types/client/project-session-state.d.ts +3 -1
  219. package/lib/types/client/prompt-content.d.ts +9 -1
  220. package/lib/types/client/role/RoleSelector.d.ts +11 -1
  221. package/lib/types/client/role/preview.d.ts +109 -0
  222. package/lib/types/client/settings/sections/slash.d.ts +16 -0
  223. package/lib/types/client/settings/sections.d.ts +1 -0
  224. package/lib/types/client/slash/SlashPalette.d.ts +24 -0
  225. package/lib/types/client/slash/copy.d.ts +30 -0
  226. package/lib/types/client/slash/slash-router.d.ts +67 -0
  227. package/lib/types/client/slash/useSlashNavigation.d.ts +47 -0
  228. package/lib/types/client/styles.d.ts +9 -0
  229. package/lib/types/client/types.d.ts +16 -1
  230. package/lib/types/config-resolvers/slash-commands.d.ts +20 -0
  231. package/lib/types/index.d.ts +83 -2
  232. package/lib/types/lockdown-policy.d.ts +16 -0
  233. package/lib/types/personal-skills/service.d.ts +5 -0
  234. package/lib/types/provenance/host-store.d.ts +20 -3
  235. package/lib/types/provenance/retention.d.ts +46 -0
  236. package/lib/types/provenance/snapshot-store.d.ts +63 -7
  237. package/lib/types/questions.d.ts +13 -0
  238. package/lib/types/secure-session.d.ts +27 -1
  239. package/lib/types/slash/catalog.d.ts +56 -0
  240. package/lib/types/slash/matcher.d.ts +51 -0
  241. package/lib/types/slash/parser.d.ts +46 -0
  242. package/lib/types/slash/policy.d.ts +40 -0
  243. package/lib/types/slash/remotes.d.ts +35 -0
  244. package/lib/types/types.d.ts +254 -5
  245. package/package.json +9 -5
  246. package/scripts/attach-workspace-sessions.mjs +472 -0
  247. package/lib/client/admin/format.js.map +0 -1
@@ -1,7 +1,7 @@
1
1
  import type { ClientRemote } from "@deepseek-ai/dsh-api-gateway/client";
2
2
  import type { ISessions, SessionFace } from "@deepseek-ai/dsh-api-session-controller/client";
3
3
  import type { UiConversation } from "@deepseek-ai/dsh-client-ui-conversation/client";
4
- import type { QaAccountProfileInput, QaAccountSession, QaAccountStartersInput, QaAccountStarter, QaAccountUserPublic, QaAccessAdminSnapshot, QaApprovalDecision, QaClaimResult, QaLockdownProof, QaOwnershipEntry, QaPendingApproval, QaPendingQuestion, QaQuestionAnswerItem, QaSessionState, QaSkillDocument, QaSkillDraftInput, QaSkillRemoval, QaSkillSummary, QaSkillToolDescriptor, QaSkillValidation, QaSourceFilePreview, QaTurnSources, QaWhoamiResult, QaCapabilitySelection, QaCurrentAccess, QaSessionAccess, QaSkillActivationRecord, QaSkillAssignmentOverride, QaSubrole, QaUserAccess, QaAdminAuditEvent, QaAdminOverview, QaAdminPage, QaAdminUserDetail, QaAdminUserRow, QaAdminUserUpdate, QaAuditQuery, QaConversationDetail, QaConversationQuery, QaConversationReview, QaConversationReviewInput, QaConversationSummary, QaFeedbackQuery, QaFeedbackRow, QaMessageFeedback, QaMessageFeedbackInput, QaQualityMetrics, QaReviewQueueItem, QaReviewQueueRow, QaUserQuery } from "../types.js";
4
+ import type { QaAccountProfileInput, QaAccountSession, QaAccountStartersInput, QaAccountStarter, QaAccountUserPublic, QaAccessAdminSnapshot, QaApprovalDecision, QaClaimResult, QaLockdownProof, QaOwnershipEntry, QaPendingApproval, QaPendingQuestion, QaQuestionAnswerItem, QaSessionState, QaSkillDocument, QaSkillDraftInput, QaSkillRemoval, QaSkillSummary, QaSkillToolDescriptor, QaSkillValidation, QaSourceFilePreview, QaTurnSources, QaWhoamiResult, QaCapabilitySelection, QaCurrentAccess, QaSessionAccess, QaSkillActivationRecord, QaSkillAssignmentOverride, QaSubrole, QaUserAccess, QaAdminAuditEvent, QaAdminOverview, QaAdminPage, QaAdminUserDetail, QaAdminUserRow, QaAdminUserUpdate, QaAuditQuery, QaConversationDetail, QaConversationDeletion, QaConversationQuery, QaConversationReview, QaConversationReviewInput, QaConversationSummary, QaFeedbackQuery, QaFeedbackRow, QaMessageFeedback, QaMessageFeedbackInput, QaQualityMetrics, QaReviewQueueItem, QaReviewQueueRow, QaSlashCatalog, QaSlashExecution, QaSlashSubmitAttachment, QaUserQuery } from "../types.js";
5
5
  /** Wire content one prompt carries: text plus base64 image uploads. */
6
6
  export type QaPromptContent = Parameters<SessionFace["prompt"]>[0];
7
7
  /** DSH session runtime surface the QA controller is allowed to touch. */
@@ -58,6 +58,11 @@ export interface QaAdminApi {
58
58
  updateUser(token: string, userId: string, update: QaAdminUserUpdate): Promise<RemoteResult<QaAdminUserDetail>>;
59
59
  conversations(token: string, query: QaConversationQuery, cursor: string | null, limit: number | null): Promise<RemoteResult<QaAdminPage<QaConversationSummary>>>;
60
60
  conversation(token: string, conversationId: string): Promise<RemoteResult<QaConversationDetail>>;
61
+ /**
62
+ * Remove the conversation from the deployment, stored logs included. Only an
63
+ * administrator may call it; the sidebar's own delete is unrelated.
64
+ */
65
+ deleteConversation(token: string, conversationId: string): Promise<RemoteResult<QaConversationDeletion>>;
61
66
  feedback(token: string, query: QaFeedbackQuery, cursor: string | null, limit: number | null): Promise<RemoteResult<QaAdminPage<QaFeedbackRow>>>;
62
67
  /** The signed-in user's own verdict on one of their assistant messages. */
63
68
  rateMessage(token: string, conversationId: string, messageId: string, input: QaMessageFeedbackInput): Promise<RemoteResult<QaMessageFeedback>>;
@@ -107,6 +112,16 @@ export interface QaSourceApi {
107
112
  readonly error: unknown;
108
113
  }>;
109
114
  }
115
+ /**
116
+ * The slash half of the Host namespace. The catalog comes back already cut
117
+ * down by the deployment policy and the chat's role; `execute` takes the raw
118
+ * line, because admission re-derives the name from it rather than trusting
119
+ * anything the browser says about which entry it means.
120
+ */
121
+ export interface QaSlashApi {
122
+ catalog(token: string, sessionId: string): Promise<RemoteResult<QaSlashCatalog>>;
123
+ execute(token: string, sessionId: string, line: string, attachments: readonly QaSlashSubmitAttachment[]): Promise<RemoteResult<QaSlashExecution>>;
124
+ }
110
125
  /** A source API with the account token already bound at the call site. */
111
126
  export type QaBoundSourceApi = {
112
127
  sources(sessionId: string): Promise<{
@@ -0,0 +1,20 @@
1
+ import type { QaSurfaceConfig, ResolvedQaSlashCommands } from "../types.js";
2
+ /** Palette ceilings; a palette longer than the viewport is unusable on mobile. */
3
+ export declare const QA_SLASH_MAX_VISIBLE_MIN = 1;
4
+ export declare const QA_SLASH_MAX_VISIBLE_MAX = 100;
5
+ /**
6
+ * Resolve the slash interface policy.
7
+ *
8
+ * The master switch lives in lockdown, so it arrives as a neighbor rather than
9
+ * being re-read here — one owner per decision. Two consequences are deliberate:
10
+ *
11
+ * - An upgrade from a deployment that had already set
12
+ * `lockdown.allowSlashCommands: true` but knows nothing about this section
13
+ * keeps working: skills fall back to `all` (every user-invocable skill the
14
+ * session already exposed) and commands stay denied. The flag is reported as
15
+ * `legacyDefaults` so the Host can say so once, out loud.
16
+ * - A deployment that declares the section and leaves the switch off changes
17
+ * nothing at all: the resolved policy is inert until the switch is on.
18
+ */
19
+ export declare function resolveSlashCommands(input: QaSurfaceConfig, allowSlashCommands: boolean): ResolvedQaSlashCommands;
20
+ //# sourceMappingURL=slash-commands.d.ts.map
@@ -1,7 +1,7 @@
1
1
  import { TypertRemoteService } from "@deepseek-ai/dsh-typert-protocol";
2
2
  import type { Context } from "@deepseek-ai/cordis";
3
3
  import type { QaTurnSources } from "./provenance/types.js";
4
- import type { QaAccountProfileInput, QaAccountSession, QaAccountStartersInput, QaAccountUserPublic, QaApprovalDecision, QaClaimResult, QaLockdownProof, QaOwnershipEntry, QaPendingApproval, QaPendingQuestion, QaQuestionAnswerItem, QaSurfaceConfig, ResolvedQaSurfaceConfig, QaSkillDocument, QaSkillDraftInput, QaSkillRemoval, QaSkillSummary, QaSkillToolDescriptor, QaSkillValidation, QaSourceFilePreview, QaWhoamiResult, QaPrincipal, QaAccessAdminSnapshot, QaAdminAuditEvent, QaAdminOverview, QaAdminPage, QaAdminUserDetail, QaAdminUserRow, QaAdminUserUpdate, QaAuditQuery, QaCapabilitySelection, QaConversationDetail, QaConversationQuery, QaConversationReview, QaConversationReviewInput, QaConversationSummary, QaCurrentAccess, QaFeedbackQuery, QaFeedbackRow, QaMessageFeedback, QaMessageFeedbackInput, QaQualityMetrics, QaReviewQueueItem, QaReviewQueueRow, QaSessionAccess, QaSkillActivationRecord, QaSkillAssignmentOverride, QaSubrole, QaUserAccess, QaUserQuery } from "./types.js";
4
+ import type { QaAccountProfileInput, QaAccountSession, QaAccountStartersInput, QaAccountUserPublic, QaApprovalDecision, QaClaimResult, QaLockdownProof, QaOwnershipEntry, QaPendingApproval, QaPendingQuestion, QaQuestionAnswerItem, QaSurfaceConfig, ResolvedQaSurfaceConfig, QaSkillDocument, QaSkillDraftInput, QaSkillRemoval, QaSkillSummary, QaSkillToolDescriptor, QaSkillValidation, QaSourceFilePreview, QaWhoamiResult, QaPrincipal, QaAccessAdminSnapshot, QaAdminAuditEvent, QaAdminOverview, QaAdminPage, QaAdminUserDetail, QaAdminUserRow, QaAdminUserUpdate, QaAuditQuery, QaCapabilitySelection, QaConversationDetail, QaConversationDeletion, QaConversationQuery, QaConversationReview, QaConversationReviewInput, QaConversationSummary, QaCurrentAccess, QaFeedbackQuery, QaFeedbackRow, QaMessageFeedback, QaMessageFeedbackInput, QaQualityMetrics, QaReviewQueueItem, QaReviewQueueRow, QaSessionAccess, QaSlashCatalog, QaSlashExecution, QaSlashSubmitAttachment, QaSkillActivationRecord, QaSkillAssignmentOverride, QaSubrole, QaUserAccess, QaUserQuery } from "./types.js";
5
5
  export declare const name = "qa-surface";
6
6
  export declare const inject: string[];
7
7
  import { QA_SURFACE_SETTINGS_NAMESPACE } from "./shared/settings.js";
@@ -38,6 +38,12 @@ export declare class QaSurface extends TypertRemoteService {
38
38
  private readonly personalSkills;
39
39
  /** Personal-skill remote bodies; the wire signatures stay on this class. */
40
40
  private readonly skillRemotes;
41
+ /**
42
+ * Slash-catalog and command-admission bodies. Admission, not execution:
43
+ * the native skill and command runtimes stay the only things that know what
44
+ * a `/name` means.
45
+ */
46
+ private readonly slashRemotes;
41
47
  private readonly launchToken;
42
48
  /** Root session principals attested for their owner, never for admin viewing. */
43
49
  private readonly integrationPrincipals;
@@ -52,6 +58,25 @@ export declare class QaSurface extends TypertRemoteService {
52
58
  constructor(ctx: Context, entry?: QaSurfaceConfig);
53
59
  /** The quality store, opening its file the first time anyone needs it. */
54
60
  private quality;
61
+ /**
62
+ * The standing scope of the preset QA chats run under, so an administrator's
63
+ * capability catalog is read the way a chat reads it. Everything a preset
64
+ * mounts — its skill catalog, its tool family — is registered in that scope,
65
+ * and a global-only read showed the operator an almost empty page. Resolving
66
+ * the preset composes it but starts no agent, no session and no turn;
67
+ * without a pinned preset there is nothing to borrow, and the read stays
68
+ * global.
69
+ */
70
+ private qaPresetScope;
71
+ /**
72
+ * Drop what the quality layer kept about chats that no longer exist in the
73
+ * Harness. The ownership sweep calls this with the ids it reclaimed: the
74
+ * record it removes is one thing the deployment held about a chat, and
75
+ * ratings, reviews and queue entries are the rest. Failure is logged and
76
+ * swallowed — housekeeping runs inside a review read, and a store that
77
+ * cannot be opened must not fail the page that triggered it.
78
+ */
79
+ private dropVanishedChats;
55
80
  /** Resolve browser authentication to the caller only; never accepts an id. */
56
81
  principalForToken(token: string): QaPrincipal | undefined;
57
82
  /** Resolve only a directly QA-owned root session; delegated children fail closed. */
@@ -59,6 +84,21 @@ export declare class QaSurface extends TypertRemoteService {
59
84
  /** Admit tools that independently enforce the same QA principal boundary. */
60
85
  registerPrincipalScopedTools(names: readonly string[]): () => void;
61
86
  getConfig(): ResolvedQaSurfaceConfig;
87
+ /**
88
+ * Ownership plus the role's user-skill grant for one slash read.
89
+ *
90
+ * Ownership comes first and for the same reason the rest of the plugin does
91
+ * it: a catalog names the skills a chat can reach, and a foreign browser has
92
+ * no business enumerating that. With accounts off there is no identity to
93
+ * check and the deployment's lockdown is the boundary, exactly as it is for
94
+ * every other remote.
95
+ *
96
+ * The grant mirrors `installQaSkillPolicy` to the letter — an empty
97
+ * `userSkills` list means the role keeps no separate user list, not that it
98
+ * grants nothing — so the palette can never offer a skill the typed gesture
99
+ * would refuse, nor hide one it would accept.
100
+ */
101
+ private slashSessionGrant;
62
102
  /**
63
103
  * Self-service signup; the first account ever created becomes admin. The
64
104
  * display name derives from the email: the generated client enforces exact
@@ -68,7 +108,11 @@ export declare class QaSurface extends TypertRemoteService {
68
108
  accountsLogin(email: string, password: string): QaAccountSession;
69
109
  /** Identity probe; safe to call with an empty or expired token. */
70
110
  accountsWhoami(token: string): QaWhoamiResult;
71
- /** Migrate a browser's local chat index into server-side ownership. */
111
+ /**
112
+ * Migrate a browser's local chat index into server-side ownership. The
113
+ * access service owns the filter: a delegated session in that index is not a
114
+ * chat and is never claimed.
115
+ */
72
116
  accountsClaimSessions(token: string, sessionIds: readonly string[]): QaClaimResult;
73
117
  /** The token user's owned session ids; the sidebar list authority. */
74
118
  accountsOwnedSessions(token: string): {
@@ -135,6 +179,12 @@ export declare class QaSurface extends TypertRemoteService {
135
179
  adminConversations(token: string, query: QaConversationQuery, cursor: string | null, limit: number | null): Promise<QaAdminPage<QaConversationSummary>>;
136
180
  /** One conversation with its messages, tool calls and review state. */
137
181
  adminConversation(token: string, conversationId: string): Promise<QaConversationDetail>;
182
+ /**
183
+ * Remove one conversation from the deployment. Admin-only, audited, and the
184
+ * only path that deletes what a person wrote — the sidebar's own delete
185
+ * stays what it always was, a per-browser row.
186
+ */
187
+ adminDeleteConversation(token: string, conversationId: string): Promise<QaConversationDeletion>;
138
188
  adminFeedback(token: string, query: QaFeedbackQuery, cursor: string | null, limit: number | null): Promise<QaAdminPage<QaFeedbackRow>>;
139
189
  /**
140
190
  * Rate one of the caller's own assistant messages. The token names the only
@@ -212,7 +262,38 @@ export declare class QaSurface extends TypertRemoteService {
212
262
  skillsTools(token: string): {
213
263
  readonly tools: readonly QaSkillToolDescriptor[];
214
264
  };
265
+ /**
266
+ * The slash entries this browser may offer for one chat: the session's
267
+ * user-invocable skills and its agent's effective commands, already cut down
268
+ * by the deployment policy and by the chat's role. The browser filters and
269
+ * ranks this list; it never widens it.
270
+ *
271
+ * Enabled is reported rather than assumed, so a page that loaded before the
272
+ * operator flipped the master switch learns the truth instead of showing an
273
+ * empty palette forever.
274
+ */
275
+ slashCatalog(token: string, sessionId: string): Promise<QaSlashCatalog>;
276
+ /**
277
+ * Run one human command line. The line is the whole request — the browser
278
+ * sends no name, no kind and no descriptor, so there is nothing for it to
279
+ * forge; admission re-derives the name and re-checks the policy against the
280
+ * deployment's own config.
281
+ *
282
+ * A command never becomes a model message: the native runtime answers it and
283
+ * writes `command/run`/`command/done` into the session log, which is where
284
+ * the transcript row is read from.
285
+ */
286
+ slashExecute(token: string, sessionId: string, line: string, attachments: readonly QaSlashSubmitAttachment[]): Promise<QaSlashExecution>;
215
287
  private refreshRoute;
288
+ /**
289
+ * A deployment that set `lockdown.allowSlashCommands: true` before this
290
+ * section existed keeps the behaviour it asked for — skills at `all`,
291
+ * commands denied — and is told so once per configuration change, because
292
+ * "skills appeared after the upgrade" is otherwise indistinguishable from a
293
+ * defect. Commands are never part of that fallback: an upgrade must not hand
294
+ * the user a control-plane command nobody named.
295
+ */
296
+ private warnLegacySlashDefaults;
216
297
  /**
217
298
  * The document pipeline moved out of this plugin into `@yadsh/dsh-documents`.
218
299
  * A deployment whose profile still carries the old `documents` section would
@@ -25,4 +25,20 @@ export declare function qaToolPolicyPlan(allow: readonly string[], isMounted: (t
25
25
  * stays as unchecked as any allow-listed one, and no less.
26
26
  */
27
27
  export declare function qaToolDenial(allowed: ReadonlySet<string>, toolName: string, dynamicNames?: readonly string[]): string | undefined;
28
+ /**
29
+ * The conversation-wide ceiling, applied to every agent of an attested chat.
30
+ *
31
+ * A scoped restriction and a scoped guard cover the scope that owns them and
32
+ * that scope's descendants. A delegated child is composed from the parent's
33
+ * PRESET, so the parent agent's own layers never enter the child's chain: the
34
+ * child is bounded by its preset `toolFilter` alone, and an expert can
35
+ * therefore hold — and call — a tool the subrole never granted the chat. This
36
+ * check is the ceiling the whole conversation shares: the subrole's reach,
37
+ * visible tools plus the grantable ones, so a skill may still hand a tool to a
38
+ * delegated assistant, but nothing may exceed what the role could ever grant.
39
+ * @param ceiling - names reachable anywhere in this conversation.
40
+ * @param toolName - the tool the model is trying to call.
41
+ * @returns the denial reason, or `undefined` when the call is within reach.
42
+ */
43
+ export declare function qaCeilingDenial(ceiling: ReadonlySet<string>, toolName: string): string | undefined;
28
44
  //# sourceMappingURL=lockdown-policy.d.ts.map
@@ -92,6 +92,11 @@ export declare class QaPersonalSkills {
92
92
  * The skills one session cwd exposes to DSH. A file the parser rejects, or
93
93
  * one whose name disagrees with its directory, is reported in the editor and
94
94
  * never handed to the model as a half-valid skill.
95
+ *
96
+ * This is the model-facing discovery path, so it degrades to empty instead
97
+ * of throwing: a provider that throws marks the whole catalog snapshot
98
+ * incomplete, and the harness then withholds the available-skills section
99
+ * from every session — not just this account's skills.
95
100
  */
96
101
  discover(cwd: string): readonly QaStoredSkill[];
97
102
  /** Re-read one skill of a session cwd, re-checking the same boundary. */
@@ -35,11 +35,28 @@ export declare class QaProvenanceHost {
35
35
  constructor(ctx: Context, config: () => ResolvedQaSurfaceConfig, store?: QaProvenanceSnapshotStore, onPersistenceError?: (error: unknown) => void);
36
36
  dispose(): void;
37
37
  /**
38
- * Drop every per-session record of one chat. Long-lived servers outlive
39
- * their sessions by weeks; without this the collector, snapshot, call and
40
- * lineage maps grow with every chat and turn forever.
38
+ * Drop the in-memory per-session records of one chat. Long-lived servers
39
+ * outlive their sessions by weeks; without this the collector, snapshot,
40
+ * call and lineage maps grow with every chat and turn forever. The durable
41
+ * snapshot file is intentionally kept: `session/disposed` also fires for
42
+ * runtime teardown of a chat that still exists and will be reopened, and
43
+ * its stored turns are what let the transcript show sources after a Host
44
+ * restart. Growth of the file is bounded by the snapshot store's caps.
41
45
  */
42
46
  private forget;
47
+ private forgetById;
48
+ /**
49
+ * Drop everything kept about one chat, in memory and in storage alike.
50
+ *
51
+ * Unlike {@link forget}, which runs on every teardown of a chat that still
52
+ * exists and deliberately keeps its stored turns, this is for a chat that is
53
+ * gone: nothing will reopen it, so the durable shard goes with it. The
54
+ * administrative deletion calls this in the same act that removes the
55
+ * session's logs.
56
+ *
57
+ * @param sessionId - the chat whose collected sources are dropped.
58
+ */
59
+ dropSession(sessionId: string): void;
43
60
  private forgetAll;
44
61
  bundles(sessionId: string): readonly QaTurnSources[];
45
62
  sourceAllowed(sessionId: string, path: string): boolean;
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Retention contract for durable provenance.
3
+ *
4
+ * This module is deliberately free of Node imports: the resolved default
5
+ * config reaches the browser bundle through `resolve-config`, and a single
6
+ * `node:fs` import here would break that bundle at runtime.
7
+ */
8
+ /**
9
+ * What a sharded provenance store keeps. Every bound counts turns, shards or
10
+ * days; zero means "keep everything" for that bound.
11
+ */
12
+ export interface QaProvenanceRetention {
13
+ /** Newest turns kept per chat. */
14
+ readonly maxTurnsPerSession: number;
15
+ /** Chats kept, most recently written first. */
16
+ readonly maxSessions: number;
17
+ /** Chats untouched for longer than this are dropped. */
18
+ readonly maxAgeDays: number;
19
+ /** How often a write may trigger the directory sweep. */
20
+ readonly sweepIntervalMinutes: number;
21
+ }
22
+ /**
23
+ * Defaults sized for a QA deployment: one chat is worth a few hundred turns, a
24
+ * fortnight of chats is worth keeping, and an untouched month is finished.
25
+ */
26
+ export declare const DEFAULT_QA_PROVENANCE_RETENTION: QaProvenanceRetention;
27
+ /** Bounds the configuration validator enforces, mirrored for the CLI. */
28
+ export declare const QA_PROVENANCE_RETENTION_LIMITS: Readonly<{
29
+ maxTurnsPerSession: {
30
+ min: number;
31
+ max: number;
32
+ };
33
+ maxSessions: {
34
+ min: number;
35
+ max: number;
36
+ };
37
+ maxAgeDays: {
38
+ min: number;
39
+ max: number;
40
+ };
41
+ sweepIntervalMinutes: {
42
+ min: number;
43
+ max: number;
44
+ };
45
+ }>;
46
+ //# sourceMappingURL=retention.d.ts.map
@@ -1,23 +1,79 @@
1
+ import { type QaProvenanceRetention } from "./retention.js";
1
2
  import type { QaTurnSources } from "./types.js";
2
3
  export interface QaProvenanceSnapshotStore {
3
4
  list(sessionId: string): readonly QaTurnSources[];
4
5
  put(bundle: QaTurnSources): void;
6
+ /**
7
+ * Drop one session's snapshots. The host store wires this to the session's
8
+ * disposal, which is what keeps the durable file from growing with every
9
+ * chat a long-lived server ever served.
10
+ */
11
+ drop(sessionId: string): void;
12
+ }
13
+ /**
14
+ * Retention bounds and their defaults live in a Node-free module: the resolved
15
+ * default config reaches the browser bundle, and this file does not.
16
+ */
17
+ export { DEFAULT_QA_PROVENANCE_RETENTION, QA_PROVENANCE_RETENTION_LIMITS, } from "./retention.js";
18
+ export type { QaProvenanceRetention } from "./retention.js";
19
+ /** What one directory sweep did, for the maintenance command and the tests. */
20
+ export interface QaProvenanceSweepResult {
21
+ readonly scanned: number;
22
+ readonly droppedByAge: number;
23
+ readonly droppedByCount: number;
5
24
  }
6
25
  /** Process-local store used by tests and explicit ephemeral deployments. */
7
26
  export declare class MemoryQaProvenanceSnapshotStore implements QaProvenanceSnapshotStore {
8
27
  private readonly sessions;
9
28
  list(sessionId: string): readonly QaTurnSources[];
10
29
  put(bundle: QaTurnSources): void;
30
+ drop(sessionId: string): void;
11
31
  }
12
- /** Default durable provenance path, deliberately outside Harness journals. */
13
- export declare function defaultQaProvenanceFilePath(): string;
14
- /** Atomically persists per-turn QA source snapshots in plugin-owned storage. */
32
+ /** Default durable provenance directory, deliberately outside Harness journals. */
33
+ export declare function defaultQaProvenanceDirectoryPath(): string;
34
+ /** The pre-sharding monolith, migrated on first use and then left alone. */
35
+ export declare function defaultLegacyProvenanceFilePath(): string;
36
+ /**
37
+ * Durable provenance, one file per chat.
38
+ *
39
+ * The read API is per-session and nothing enumerates every chat, so a shard is
40
+ * exactly the unit a writer touches: a turn rewrites one chat's history rather
41
+ * than every chat's. Empty turns collapse to their numbers and each shard is
42
+ * bounded by `QaProvenanceRetention`, so neither a long chat nor a long-lived
43
+ * deployment can make a single write grow without limit.
44
+ *
45
+ * The store is the only writer of its directory, and no cache sits in front of
46
+ * it: every read goes to disk.
47
+ */
15
48
  export declare class FileQaProvenanceSnapshotStore implements QaProvenanceSnapshotStore {
16
- private readonly filePath;
17
- constructor(filePath?: string);
49
+ private readonly directoryPath;
50
+ private readonly retention;
51
+ private readonly legacyFilePath;
52
+ private migrated;
53
+ private lastSweepAt;
54
+ constructor(directoryPath?: string, retention?: () => QaProvenanceRetention, legacyFilePath?: string);
18
55
  list(sessionId: string): readonly QaTurnSources[];
19
56
  put(bundle: QaTurnSources): void;
20
- private load;
21
- private persist;
57
+ drop(sessionId: string): void;
58
+ /**
59
+ * Drop shards the retention policy no longer covers: untouched for
60
+ * `maxAgeDays`, then everything past the `maxSessions` most recent ones.
61
+ *
62
+ * `keep` names the chat whose shard must survive the sweep — a caller that
63
+ * swept right after writing it would otherwise be able to delete the very
64
+ * bundle it just stored.
65
+ */
66
+ sweep(keep?: string): QaProvenanceSweepResult;
67
+ /**
68
+ * Split the pre-sharding monolith into shards exactly once, then rename it
69
+ * out of the way. A shard that already exists wins the merge, so a retried
70
+ * migration cannot lose turns that arrived after the first attempt.
71
+ */
72
+ private migrateLegacyOnce;
73
+ private shardPath;
74
+ private readShard;
75
+ private writeShard;
76
+ private removeShard;
77
+ private maybeSweep;
22
78
  }
23
79
  //# sourceMappingURL=snapshot-store.d.ts.map
@@ -33,6 +33,12 @@ export interface QaQuestionAnswer {
33
33
  }
34
34
  /** What the model reads when the deployment does not answer questions. */
35
35
  export declare const QA_QUESTIONS_UNSUPPORTED = "questions are not answered in this assistant view; ask the user in plain text instead";
36
+ /**
37
+ * The harness tool that produces these requests. A deployment that parks
38
+ * questions still has to let the attested session call it: this plugin never
39
+ * adds the name to a tool policy on its own.
40
+ */
41
+ export declare const QA_ASK_QUESTION_TOOL = "ask_user_question";
36
42
  /**
37
43
  * User questions in the QA view.
38
44
  *
@@ -68,6 +74,11 @@ export declare class QaQuestionGate {
68
74
  * parked request is authoritative: a label the question never offered is
69
75
  * dropped, and a free-text answer replaces the choice in a single-select
70
76
  * rather than accompanying it, so the model only ever reads a real answer.
77
+ *
78
+ * The payload arrives over the wire from the browser, so its shape is
79
+ * untrusted: a non-array, a non-object entry, or a non-array/non-string
80
+ * selection is folded into the refusal/skip semantics instead of crashing
81
+ * the gate with a TypeError.
71
82
  */
72
83
  answer(sessionId: string, requestId: string, answers: readonly QaQuestionAnswerItem[]): boolean;
73
84
  /** Close a request without answering it. */
@@ -79,5 +90,7 @@ export declare class QaQuestionGate {
79
90
  private park;
80
91
  /** Fail the questions one session's agent owns; a disposed agent cannot ask. */
81
92
  private settleOwner;
93
+ /** Fail the questions one agent parked; an idle agent cannot receive them. */
94
+ private settleAgent;
82
95
  }
83
96
  //# sourceMappingURL=questions.d.ts.map
@@ -1,6 +1,7 @@
1
1
  import type { Agent } from "@deepseek-ai/dsh-agent";
2
2
  import type { Context } from "@deepseek-ai/cordis";
3
3
  import type { PluginLogger } from "@yadsh/dsh-plugin-log";
4
+ import { type QaSessionFacts } from "./accounts/store.js";
4
5
  import type { QaResolvedSessionPolicy } from "./access/service.js";
5
6
  import type { QaLockdownProof, ResolvedQaSurfaceConfig } from "./types.js";
6
7
  /**
@@ -9,7 +10,7 @@ import type { QaLockdownProof, ResolvedQaSurfaceConfig } from "./types.js";
9
10
  * pair or throw the coarse `QaAttestationError`; see {@link QaAccounts}.
10
11
  */
11
12
  export interface QaAccountsGate {
12
- enforceSessionAccess(token: string, sessionId: string): {
13
+ enforceSessionAccess(token: string, sessionId: string, facts?: QaSessionFacts): {
13
14
  readonly id: string;
14
15
  } | undefined;
15
16
  userWorkspace(userId: string, registeredWorkspacePath: string): string;
@@ -47,7 +48,17 @@ export declare class QaPolicyAdmission {
47
48
  */
48
49
  private readonly attested;
49
50
  private readonly workspaceAccess;
51
+ /**
52
+ * Every name reachable anywhere in one QA conversation, keyed by session id.
53
+ *
54
+ * The chat's agent and the agents delegated from it share one entry —
55
+ * children inherit it when their session is created — because the ceiling is
56
+ * a property of the conversation, not of one scope. See
57
+ * {@link qaCeilingDenial} for why a scoped restriction cannot express it.
58
+ */
59
+ private readonly ceilings;
50
60
  private readonly disposeWorkspaceGuard;
61
+ private readonly disposeCeilingGuard;
51
62
  constructor(ctx: Context, config: () => ResolvedQaSurfaceConfig, logger: PluginLogger, accounts?: QaAccountsGate | undefined,
52
63
  /**
53
64
  * Names the QA tool catalog attached to one agent after its activation
@@ -100,6 +111,21 @@ export declare class QaPolicyAdmission {
100
111
  * mismatch"), and the adoption and permission checks stay the gate.
101
112
  */
102
113
  private liveAgent;
114
+ /**
115
+ * The Host-registered facts of one session, for the accounts gate's bounded
116
+ * auto-claim. A session this process has not materialized (a chat of an
117
+ * earlier Host run, reached before its agent exists) yields no facts and
118
+ * keeps the historical unbounded claim.
119
+ */
120
+ private sessionFacts;
121
+ /**
122
+ * Account identity and ownership are checked before any policy work: an
123
+ * invalid token must not learn whether a session exists or how the
124
+ * deployment composes. Independent of lockdown — a deployment may gate
125
+ * users without pinning the policy, and the gate itself no-ops while
126
+ * accounts are disabled.
127
+ */
128
+ private accessOwner;
103
129
  secureSession(token: string, sessionId: string): Promise<QaLockdownProof>;
104
130
  /**
105
131
  * Mask one agent down to the policy's tool names, for the account-free path
@@ -0,0 +1,56 @@
1
+ /**
2
+ * The unified presentation model behind the palette.
3
+ *
4
+ * Two native catalogs arrive here — the session's user-invocable skills and
5
+ * the session agent's effective commands — and leave as one list of entries
6
+ * whose identity is `skill:<name>` / `command:<name>`. The prefix is the whole
7
+ * point: both registries may publish a `plan`, and a palette that keyed rows
8
+ * by bare name would let one of them silently replace the other.
9
+ *
10
+ * Pure on purpose. Nothing here reads a session, a service or a file: the host
11
+ * remote gathers the native inputs, this module decides what the palette sees,
12
+ * and the tests drive it with plain arrays.
13
+ */
14
+ import type { QaSlashCatalogEntry, QaSlashCommandSurface } from "../types.js";
15
+ import { type QaSlashPolicy } from "./policy.js";
16
+ export declare const QA_SLASH_SKILL_PREFIX = "skill:";
17
+ export declare const QA_SLASH_COMMAND_PREFIX = "command:";
18
+ /** One user-invocable skill, as the skills registry published it. */
19
+ export interface QaSlashNativeSkill {
20
+ readonly name: string;
21
+ readonly description: string;
22
+ readonly whenToUse?: string;
23
+ /** Whether the model is also offered this skill. */
24
+ readonly modelInvocable?: boolean;
25
+ }
26
+ /** One effective command descriptor, as the command registry published it. */
27
+ export interface QaSlashNativeCommand {
28
+ readonly name: string;
29
+ readonly description: string;
30
+ readonly inputHint?: string;
31
+ readonly acceptsAttachments?: boolean;
32
+ }
33
+ export interface BuildSlashCatalogOptions {
34
+ readonly skills: readonly QaSlashNativeSkill[];
35
+ readonly commands: readonly QaSlashNativeCommand[];
36
+ readonly skillPolicy: QaSlashPolicy;
37
+ readonly commandPolicy: QaSlashPolicy;
38
+ /**
39
+ * The session role's own user-skill grant, when the access system is on.
40
+ * `undefined` means the role system has no opinion, which is its state on a
41
+ * deployment that never enabled roles — not "grant nothing".
42
+ */
43
+ readonly grantedSkills?: readonly string[] | undefined;
44
+ readonly commandSurface: QaSlashCommandSurface;
45
+ /** Native entries arrive alphabetically; this makes the order explicit. */
46
+ readonly localeCompare?: (left: string, right: string) => number;
47
+ }
48
+ /** The routing identity of one native name; never the bare name. */
49
+ export declare function slashEntryId(kind: QaSlashCatalogEntry["kind"], name: string): string;
50
+ /**
51
+ * Build the palette the browser is allowed to show. Skills lead, commands
52
+ * follow: the two kinds stay contiguous so the palette can group them without
53
+ * re-sorting, and a name collision keeps both rows.
54
+ */
55
+ export declare function buildSlashCatalog(options: BuildSlashCatalogOptions): readonly QaSlashCatalogEntry[];
56
+ //# sourceMappingURL=catalog.d.ts.map
@@ -0,0 +1,51 @@
1
+ /**
2
+ * One matcher for both halves of the slash catalog.
3
+ *
4
+ * Upstream matches skills with `startsWith` and commands fuzzily, so the same
5
+ * query behaves differently depending on which registry answers it. QA always
6
+ * ranks with the ladder below, in this order:
7
+ *
8
+ * exact → prefix → name-token boundary → substring → ordered subsequence
9
+ *
10
+ * so `/tkp` finds `generate-tkp` through the token boundary and `/contract`
11
+ * finds both `contract-analysis` (prefix) and `review-contract` (token).
12
+ *
13
+ * Dependency-free on purpose: inlined into the browser bundle.
14
+ */
15
+ /** How a name matched; lower is a stronger claim on the top of the list. */
16
+ export declare const SLASH_MATCH_EXACT = 0;
17
+ export declare const SLASH_MATCH_PREFIX = 1;
18
+ export declare const SLASH_MATCH_TOKEN = 2;
19
+ export declare const SLASH_MATCH_SUBSTRING = 3;
20
+ export declare const SLASH_MATCH_SUBSEQUENCE = 4;
21
+ export interface QaSlashMatch {
22
+ readonly rank: number;
23
+ /** Where the match starts; earlier wins inside one rank. */
24
+ readonly index: number;
25
+ }
26
+ export interface QaSlashMatchOptions {
27
+ /**
28
+ * Whether the two weakest rungs run. Turning them off keeps the matcher
29
+ * predictable for deployments that read the palette as an index.
30
+ */
31
+ readonly fuzzy?: boolean;
32
+ }
33
+ /**
34
+ * Rank one name against a palette query. An empty query matches everything at
35
+ * the prefix rung, which keeps the unfiltered catalog in catalog order.
36
+ */
37
+ export declare function matchSlashName(name: string, query: string, options?: QaSlashMatchOptions): QaSlashMatch | undefined;
38
+ /**
39
+ * Order two ranked names; the caller has already ruled out `undefined`. Ties
40
+ * fall back to the name, so equal-rank rows keep catalog order and the list
41
+ * never reshuffles between two renders of the same query.
42
+ */
43
+ export declare function compareSlashMatches(leftName: string, left: QaSlashMatch, rightName: string, right: QaSlashMatch): number;
44
+ /**
45
+ * The matching entries in rank order. Identity of the input entries is
46
+ * preserved, so a caller can render them without a lookup.
47
+ */
48
+ export declare function rankSlashEntries<T extends {
49
+ readonly name: string;
50
+ }>(entries: readonly T[], query: string, options?: QaSlashMatchOptions): readonly T[];
51
+ //# sourceMappingURL=matcher.d.ts.map
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Composer input classification for the slash interface.
3
+ *
4
+ * The grammars are mirrors, not inventions: a command line is what the native
5
+ * command runtime parses (`/name` at byte zero, name then end-of-input or
6
+ * whitespace, everything after kept verbatim as `rawInput`), and a skill
7
+ * gesture is what `dsh-tool-skill` recognises (any whitespace-bounded `/name`
8
+ * token with the public skill-name grammar). A line that matches neither is
9
+ * ordinary prose and must keep behaving exactly as it did before this feature.
10
+ *
11
+ * Deliberately dependency-free: this module is inlined into the browser
12
+ * bundle, where the Host's config surface must not follow it.
13
+ */
14
+ export interface QaSlashLine {
15
+ readonly name: string;
16
+ /** Exact text after the name, including the separator whitespace. */
17
+ readonly args: string;
18
+ }
19
+ /**
20
+ * Parse a command-shaped line. `undefined` means the line is not one — either
21
+ * it is not slash-led at all, or the token after the slash is not a command
22
+ * name (`/usr/bin/env` stays a path, not a call).
23
+ */
24
+ export declare function parseSlashLine(input: string): QaSlashLine | undefined;
25
+ /** The palette filter of a draft, or `undefined` when the palette is closed. */
26
+ export declare function slashPaletteQuery(input: string): string | undefined;
27
+ /**
28
+ * Every whitespace-bounded `/name` gesture in the text, first-seen order and
29
+ * deduplicated. The Host owns invocation; this list exists only so the QA
30
+ * surface can warn about a gesture its own policy withholds before the turn
31
+ * is submitted.
32
+ */
33
+ export declare function skillGestures(input: string): readonly string[];
34
+ /** The invocation a submitted draft carries, once its route is decided. */
35
+ export interface QaSlashInvocation {
36
+ readonly name: string;
37
+ /** Text after the name with its separator whitespace removed. */
38
+ readonly args: string;
39
+ }
40
+ /**
41
+ * The invocation a draft names, independent of the catalog. Used for the
42
+ * routing decision and for the "unknown command" refusal, both of which must
43
+ * work while the catalog itself is unavailable.
44
+ */
45
+ export declare function slashInvocation(input: string): QaSlashInvocation | undefined;
46
+ //# sourceMappingURL=parser.d.ts.map