@yadsh/dsh-qa-surface 0.8.0 → 0.10.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 (242) hide show
  1. package/README.md +142 -4
  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/service.js +45 -17
  6. package/lib/access/service.js.map +1 -1
  7. package/lib/accounts/errors.js.map +1 -1
  8. package/lib/accounts/store.js +14 -0
  9. package/lib/accounts/store.js.map +1 -1
  10. package/lib/admin/permissions.js +4 -0
  11. package/lib/admin/permissions.js.map +1 -1
  12. package/lib/admin/quality-store.js +71 -0
  13. package/lib/admin/quality-store.js.map +1 -1
  14. package/lib/admin/service.js +113 -8
  15. package/lib/admin/service.js.map +1 -1
  16. package/lib/admin/session-log.js +66 -5
  17. package/lib/admin/session-log.js.map +1 -1
  18. package/lib/client/QaSessionController.js +371 -37
  19. package/lib/client/QaSessionController.js.map +1 -1
  20. package/lib/client/QaSurface.js +48 -8
  21. package/lib/client/QaSurface.js.map +1 -1
  22. package/lib/client/QaSurfaceGuard.js +12 -5
  23. package/lib/client/QaSurfaceGuard.js.map +1 -1
  24. package/lib/client/QaTranscriptAdapter.js +36 -0
  25. package/lib/client/QaTranscriptAdapter.js.map +1 -1
  26. package/lib/client/admin/QaAdmin.js +14 -2
  27. package/lib/client/admin/QaAdmin.js.map +1 -1
  28. package/lib/client/admin/pages/Conversations.js +33 -7
  29. package/lib/client/admin/pages/Conversations.js.map +1 -1
  30. package/lib/client/admin/pages/Users.js +9 -2
  31. package/lib/client/admin/pages/Users.js.map +1 -1
  32. package/lib/client/admin/shared.js +14 -1
  33. package/lib/client/admin/shared.js.map +1 -1
  34. package/lib/client/admin/styles.js +2 -0
  35. package/lib/client/admin/styles.js.map +1 -1
  36. package/lib/client/audit/QaAuditDialog.js +74 -0
  37. package/lib/client/audit/QaAuditDialog.js.map +1 -0
  38. package/lib/client/audit/QaAuditRowBadge.js +17 -0
  39. package/lib/client/audit/QaAuditRowBadge.js.map +1 -0
  40. package/lib/client/audit/controller.js +39 -0
  41. package/lib/client/audit/controller.js.map +1 -0
  42. package/lib/client/audit/types.js +36 -0
  43. package/lib/client/audit/types.js.map +1 -0
  44. package/lib/client/audit/use-chat-audits.js +139 -0
  45. package/lib/client/audit/use-chat-audits.js.map +1 -0
  46. package/lib/client/base64.js +22 -1
  47. package/lib/client/base64.js.map +1 -1
  48. package/lib/client/components/QaAgentsDrawer.js +9 -6
  49. package/lib/client/components/QaAgentsDrawer.js.map +1 -1
  50. package/lib/client/components/QaApproval.js +1 -1
  51. package/lib/client/components/QaApproval.js.map +1 -1
  52. package/lib/client/components/QaChangelog.js +72 -0
  53. package/lib/client/components/QaChangelog.js.map +1 -1
  54. package/lib/client/components/QaComposer.js +63 -3
  55. package/lib/client/components/QaComposer.js.map +1 -1
  56. package/lib/client/components/QaFilesPanel.js +17 -11
  57. package/lib/client/components/QaFilesPanel.js.map +1 -1
  58. package/lib/client/components/QaHeader.js +3 -11
  59. package/lib/client/components/QaHeader.js.map +1 -1
  60. package/lib/client/components/QaMessage.js +16 -0
  61. package/lib/client/components/QaMessage.js.map +1 -1
  62. package/lib/client/components/QaModal.js.map +1 -1
  63. package/lib/client/components/QaQuestions.js +5 -5
  64. package/lib/client/components/QaQuestions.js.map +1 -1
  65. package/lib/client/components/QaSidebar.js +22 -3
  66. package/lib/client/components/QaSidebar.js.map +1 -1
  67. package/lib/client/components/QaWidthHandle.js +111 -5
  68. package/lib/client/components/QaWidthHandle.js.map +1 -1
  69. package/lib/client/components/QaWorkspaceBrowser.js +231 -0
  70. package/lib/client/components/QaWorkspaceBrowser.js.map +1 -0
  71. package/lib/client/index.js +127 -51
  72. package/lib/client/index.js.map +1 -1
  73. package/lib/client/kiosk.js +51 -0
  74. package/lib/client/kiosk.js.map +1 -0
  75. package/lib/client/markdown/blocks.js +122 -7
  76. package/lib/client/markdown/blocks.js.map +1 -1
  77. package/lib/client/markdown/inline.js +108 -12
  78. package/lib/client/markdown/inline.js.map +1 -1
  79. package/lib/client/markdown/katex-css.js +12 -0
  80. package/lib/client/markdown/katex-css.js.map +1 -0
  81. package/lib/client/markdown/math.js +84 -0
  82. package/lib/client/markdown/math.js.map +1 -0
  83. package/lib/client/markdown/render.js +74 -5
  84. package/lib/client/markdown/render.js.map +1 -1
  85. package/lib/client/project-session-state.js +15 -2
  86. package/lib/client/project-session-state.js.map +1 -1
  87. package/lib/client/prompt-content.js +26 -0
  88. package/lib/client/prompt-content.js.map +1 -1
  89. package/lib/client/settings/card.js +2 -2
  90. package/lib/client/settings/card.js.map +1 -1
  91. package/lib/client/settings/sections/lockdown.js +1 -6
  92. package/lib/client/settings/sections/lockdown.js.map +1 -1
  93. package/lib/client/settings/sections/notes.js +46 -0
  94. package/lib/client/settings/sections/notes.js.map +1 -0
  95. package/lib/client/settings/sections/slash.js +57 -0
  96. package/lib/client/settings/sections/slash.js.map +1 -0
  97. package/lib/client/settings/sections/sources.js +4 -1
  98. package/lib/client/settings/sections/sources.js.map +1 -1
  99. package/lib/client/settings/sections/status.js +9 -1
  100. package/lib/client/settings/sections/status.js.map +1 -1
  101. package/lib/client/settings/sections.js +2 -0
  102. package/lib/client/settings/sections.js.map +1 -1
  103. package/lib/client/settlement.js +1 -1
  104. package/lib/client/settlement.js.map +1 -1
  105. package/lib/client/slash/SlashPalette.js +48 -0
  106. package/lib/client/slash/SlashPalette.js.map +1 -0
  107. package/lib/client/slash/copy.js +54 -0
  108. package/lib/client/slash/copy.js.map +1 -0
  109. package/lib/client/slash/slash-router.js +49 -0
  110. package/lib/client/slash/slash-router.js.map +1 -0
  111. package/lib/client/slash/useSlashNavigation.js +95 -0
  112. package/lib/client/slash/useSlashNavigation.js.map +1 -0
  113. package/lib/client/source-preview.js +3 -0
  114. package/lib/client/source-preview.js.map +1 -1
  115. package/lib/client/styles.js +145 -16
  116. package/lib/client/styles.js.map +1 -1
  117. package/lib/client/types.js +11 -0
  118. package/lib/client/types.js.map +1 -1
  119. package/lib/client.js +33548 -1876
  120. package/lib/client.js.map +1 -1
  121. package/lib/config-resolvers/basics.js +11 -2
  122. package/lib/config-resolvers/basics.js.map +1 -1
  123. package/lib/config-resolvers/defaults.js +32 -0
  124. package/lib/config-resolvers/defaults.js.map +1 -1
  125. package/lib/config-resolvers/lockdown.js +8 -2
  126. package/lib/config-resolvers/lockdown.js.map +1 -1
  127. package/lib/config-resolvers/notes.js +24 -0
  128. package/lib/config-resolvers/notes.js.map +1 -0
  129. package/lib/config-resolvers/slash-commands.js +60 -0
  130. package/lib/config-resolvers/slash-commands.js.map +1 -0
  131. package/lib/config-resolvers/sources.js +4 -0
  132. package/lib/config-resolvers/sources.js.map +1 -1
  133. package/lib/config.js +96 -2
  134. package/lib/config.js.map +1 -1
  135. package/lib/index.js +309 -11
  136. package/lib/index.js.map +1 -1
  137. package/lib/personal-skills/service.js +16 -3
  138. package/lib/personal-skills/service.js.map +1 -1
  139. package/lib/prompt-notes.js +45 -6
  140. package/lib/prompt-notes.js.map +1 -1
  141. package/lib/provenance/document-preview.js +51 -0
  142. package/lib/provenance/document-preview.js.map +1 -0
  143. package/lib/provenance/file-preview.js +191 -19
  144. package/lib/provenance/file-preview.js.map +1 -1
  145. package/lib/provenance/host-store.js +18 -1
  146. package/lib/provenance/host-store.js.map +1 -1
  147. package/lib/qa-tools/catalog.js +7 -1
  148. package/lib/qa-tools/catalog.js.map +1 -1
  149. package/lib/qa-tools/file-delete-gate.js +60 -0
  150. package/lib/qa-tools/file-delete-gate.js.map +1 -0
  151. package/lib/qa-tools/file-delete.js +156 -0
  152. package/lib/qa-tools/file-delete.js.map +1 -0
  153. package/lib/questions.js +90 -43
  154. package/lib/questions.js.map +1 -1
  155. package/lib/resolve-config.js +7 -0
  156. package/lib/resolve-config.js.map +1 -1
  157. package/lib/secure-session.js +24 -0
  158. package/lib/secure-session.js.map +1 -1
  159. package/lib/shared/documents.js +22 -0
  160. package/lib/shared/documents.js.map +1 -0
  161. package/lib/slash/catalog.js +77 -0
  162. package/lib/slash/catalog.js.map +1 -0
  163. package/lib/slash/matcher.js +100 -0
  164. package/lib/slash/matcher.js.map +1 -0
  165. package/lib/slash/parser.js +79 -0
  166. package/lib/slash/parser.js.map +1 -0
  167. package/lib/slash/policy.js +72 -0
  168. package/lib/slash/policy.js.map +1 -0
  169. package/lib/slash/remotes.js +272 -0
  170. package/lib/slash/remotes.js.map +1 -0
  171. package/lib/typert.host.js +544 -56
  172. package/lib/typert.remote-client.d.ts +13 -1
  173. package/lib/typert.remote-client.js +435 -53
  174. package/lib/types/access/capability-catalog.d.ts +28 -1
  175. package/lib/types/access/service.d.ts +33 -4
  176. package/lib/types/accounts/errors.d.ts +7 -1
  177. package/lib/types/accounts/store.d.ts +12 -0
  178. package/lib/types/admin/quality-store.d.ts +18 -0
  179. package/lib/types/admin/service.d.ts +34 -2
  180. package/lib/types/admin/session-log.d.ts +65 -1
  181. package/lib/types/client/QaSessionController.d.ts +84 -2
  182. package/lib/types/client/QaSurface.d.ts +14 -1
  183. package/lib/types/client/admin/pages/Conversations.d.ts +4 -0
  184. package/lib/types/client/admin/shared.d.ts +2 -0
  185. package/lib/types/client/audit/QaAuditDialog.d.ts +21 -0
  186. package/lib/types/client/audit/QaAuditRowBadge.d.ts +18 -0
  187. package/lib/types/client/audit/controller.d.ts +27 -0
  188. package/lib/types/client/audit/types.d.ts +72 -0
  189. package/lib/types/client/audit/use-chat-audits.d.ts +20 -0
  190. package/lib/types/client/base64.d.ts +13 -1
  191. package/lib/types/client/components/QaAgentsDrawer.d.ts +2 -1
  192. package/lib/types/client/components/QaComposer.d.ts +12 -2
  193. package/lib/types/client/components/QaFilesPanel.d.ts +16 -4
  194. package/lib/types/client/components/QaHeader.d.ts +9 -3
  195. package/lib/types/client/components/QaModal.d.ts +4 -3
  196. package/lib/types/client/components/QaQuestions.d.ts +7 -0
  197. package/lib/types/client/components/QaSidebar.d.ts +8 -0
  198. package/lib/types/client/components/QaWidthHandle.d.ts +48 -2
  199. package/lib/types/client/components/QaWorkspaceBrowser.d.ts +15 -0
  200. package/lib/types/client/index.d.ts +1 -1
  201. package/lib/types/client/kiosk.d.ts +34 -0
  202. package/lib/types/client/markdown/blocks.d.ts +14 -1
  203. package/lib/types/client/markdown/inline.d.ts +23 -7
  204. package/lib/types/client/markdown/katex-css.d.ts +11 -0
  205. package/lib/types/client/markdown/math.d.ts +23 -0
  206. package/lib/types/client/markdown/render.d.ts +2 -1
  207. package/lib/types/client/project-session-state.d.ts +3 -1
  208. package/lib/types/client/prompt-content.d.ts +9 -1
  209. package/lib/types/client/settings/sections/notes.d.ts +10 -0
  210. package/lib/types/client/settings/sections/slash.d.ts +16 -0
  211. package/lib/types/client/settings/sections.d.ts +2 -0
  212. package/lib/types/client/settlement.d.ts +4 -1
  213. package/lib/types/client/slash/SlashPalette.d.ts +24 -0
  214. package/lib/types/client/slash/copy.d.ts +30 -0
  215. package/lib/types/client/slash/slash-router.d.ts +67 -0
  216. package/lib/types/client/slash/useSlashNavigation.d.ts +47 -0
  217. package/lib/types/client/styles.d.ts +22 -0
  218. package/lib/types/client/types.d.ts +65 -1
  219. package/lib/types/config-resolvers/notes.d.ts +10 -0
  220. package/lib/types/config-resolvers/slash-commands.d.ts +20 -0
  221. package/lib/types/index.d.ts +116 -1
  222. package/lib/types/personal-skills/service.d.ts +5 -0
  223. package/lib/types/prompt-notes.d.ts +9 -0
  224. package/lib/types/provenance/document-preview.d.ts +24 -0
  225. package/lib/types/provenance/file-preview.d.ts +69 -2
  226. package/lib/types/provenance/host-store.d.ts +13 -0
  227. package/lib/types/qa-tools/catalog.d.ts +1 -1
  228. package/lib/types/qa-tools/file-delete-gate.d.ts +42 -0
  229. package/lib/types/qa-tools/file-delete.d.ts +32 -0
  230. package/lib/types/questions.d.ts +8 -0
  231. package/lib/types/shared/documents.d.ts +20 -0
  232. package/lib/types/slash/catalog.d.ts +56 -0
  233. package/lib/types/slash/matcher.d.ts +51 -0
  234. package/lib/types/slash/parser.d.ts +46 -0
  235. package/lib/types/slash/policy.d.ts +40 -0
  236. package/lib/types/slash/remotes.d.ts +35 -0
  237. package/lib/types/types.d.ts +293 -6
  238. package/lib/types/ui-mode.d.ts +18 -0
  239. package/lib/ui-mode.js +22 -0
  240. package/lib/ui-mode.js.map +1 -0
  241. package/package.json +15 -9
  242. package/scripts/attach-workspace-sessions.mjs +472 -0
@@ -0,0 +1,42 @@
1
+ import type { Context } from "@deepseek-ai/cordis";
2
+ import type { QaSessionOwnership } from "../session-ownership.js";
3
+ /** The one QA tool whose every call is parked for the operator. */
4
+ export declare const QA_FILE_DELETE_TOOL = "file_delete";
5
+ /** Why the gate answers `ask` before the chain can decide alone. */
6
+ export declare const QA_FILE_DELETE_ASK_REASON = "deleting a workspace file requires operator confirmation";
7
+ /**
8
+ * The inner half of `file_delete`'s safety: the decision that composes the
9
+ * approval flow around one destructive tool.
10
+ *
11
+ * Installed WITHOUT `prepend`, deliberately. The approval gate sits outside
12
+ * every other `tools/pre-execute` listener and resolves the decision the rest
13
+ * of the chain produced — an `ask` from an inner gate is what it parks for
14
+ * the operator. This listener is that inner gate: for a `file_delete` call
15
+ * from an attested QA session it answers `ask` on its own, without asking
16
+ * the chain, so the interactive approval card appears for every deletion,
17
+ * whatever the deployment's other policies would have said. The operator's
18
+ * answer becomes the decision, and on a deployment with
19
+ * `interaction.approvals: blocked` the approval gate keeps its fail-closed
20
+ * behavior and refuses the call — nothing is ever deleted without a person.
21
+ *
22
+ * Any other tool, and any caller this deployment did not attest, is handed
23
+ * back to the chain untouched.
24
+ */
25
+ export declare class QaFileDeleteGate {
26
+ private readonly ctx;
27
+ private readonly ownership;
28
+ private readonly disposers;
29
+ constructor(ctx: Context, ownership: QaSessionOwnership);
30
+ /** Sit inside the approval gate; registration order is the composition. */
31
+ install(): void;
32
+ /** Detach the listener. Wired as an effect, like every other gate. */
33
+ dispose(): void;
34
+ private handle;
35
+ /**
36
+ * Whether this deployment attested the chat the call belongs to, delegated
37
+ * children included. The same ownership service the approval gate reads,
38
+ * so one chat is parked under exactly one surface.
39
+ */
40
+ private attested;
41
+ }
42
+ //# sourceMappingURL=file-delete-gate.d.ts.map
@@ -0,0 +1,32 @@
1
+ import type { ToolDefinition } from "@deepseek-ai/dsh-tools";
2
+ /**
3
+ * `file_delete` — the QA catalog's one destructive capability.
4
+ *
5
+ * The QA surface serves untrusted-audience chats pinned to a read-only or
6
+ * workspace-write sandbox, and until now no chat could remove a file it had
7
+ * created. This tool deletes exactly one regular file strictly inside the
8
+ * calling agent's workspace root (the session cwd) and refuses everything
9
+ * else with a reason the model can act on: directories, missing paths, paths
10
+ * spelled outside the root, and paths that leave it through a symbolic link.
11
+ * Every call is additionally answered `ask` by the always-ask gate, so the
12
+ * interactive approval card parks it for the operator before this body ever
13
+ * runs — the fence here is the second of two boundaries, not the only one.
14
+ *
15
+ * The workspace root is read from `exec.agent` at call time, so building the
16
+ * tool (and the catalog that carries it) stays side-effect free.
17
+ */
18
+ /** Why `file_delete` refused a call. */
19
+ export type QaFileDeleteRefusal = "workspace-unavailable" | "outside-workspace" | "symlink-escape" | "not-found" | "not-a-file";
20
+ /**
21
+ * A typed refusal of one `file_delete` call.
22
+ *
23
+ * The message is what the model reads; it names the reason in words and
24
+ * deliberately never echoes the requested absolute host path, so a refusal
25
+ * cannot leak the deployment's layout into the conversation.
26
+ */
27
+ export declare class QaFileDeleteError extends Error {
28
+ readonly code: QaFileDeleteRefusal;
29
+ constructor(code: QaFileDeleteRefusal, message: string, options?: ErrorOptions);
30
+ }
31
+ export declare function createFileDeleteTool(): ToolDefinition;
32
+ //# sourceMappingURL=file-delete.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
  *
@@ -84,5 +90,7 @@ export declare class QaQuestionGate {
84
90
  private park;
85
91
  /** Fail the questions one session's agent owns; a disposed agent cannot ask. */
86
92
  private settleOwner;
93
+ /** Fail the questions one agent parked; an idle agent cannot receive them. */
94
+ private settleAgent;
87
95
  }
88
96
  //# sourceMappingURL=questions.d.ts.map
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Formats the files panel previews by conversion instead of by bytes.
3
+ *
4
+ * Shared by the Host half (which owns the conversion) and the browser card
5
+ * (which decides whether opening a file should ask for one), so the two cannot
6
+ * drift on what "we can render this" means. Dependency-free on purpose: the
7
+ * card bundle inlines it.
8
+ */
9
+ /** OOXML word-processing documents, as the deployment detects them. */
10
+ export declare const QA_WORD_MEDIA_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
11
+ /** The media type of the PDF a converted document arrives as. */
12
+ export declare const QA_PDF_MEDIA_TYPE = "application/pdf";
13
+ /**
14
+ * Whether the panel asks the Host for a converted PDF rather than rendering the
15
+ * bytes it already holds. Word documents are the whole set: the document
16
+ * pipeline reads them and renders PDF, while its other inputs are already
17
+ * previewable (Markdown as text, PDF through the browser's own viewer).
18
+ */
19
+ export declare function isConvertibleDocument(mediaType: string): boolean;
20
+ //# sourceMappingURL=documents.d.ts.map
@@ -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
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Admission policy for one half of the slash catalog.
3
+ *
4
+ * The policy is name-based because the persisted config is: an operator writes
5
+ * `generate-tkp`, never an internal id, and the same name means the same thing
6
+ * on every Host restart. Names that cannot be a native skill or command name
7
+ * are refused at config resolution rather than silently ignored at admission,
8
+ * so a typo surfaces while the deployment is being configured.
9
+ */
10
+ import type { QaSlashPolicyMode } from "../types.js";
11
+ /** Every accepted policy mode, in the order the settings card lists them. */
12
+ export declare const QA_SLASH_MODES: readonly QaSlashPolicyMode[];
13
+ /** Longest name either registry accepts in practice; keeps host echoes bounded. */
14
+ export declare const QA_SLASH_NAME_MAX = 200;
15
+ export interface QaSlashPolicy {
16
+ readonly mode: QaSlashPolicyMode;
17
+ readonly allow: readonly string[];
18
+ }
19
+ export declare function isQaSlashPolicyMode(value: unknown): value is QaSlashPolicyMode;
20
+ /**
21
+ * Normalize one allow-list: trimmed, deduplicated, order-preserving. Refuses
22
+ * a name that neither registry could ever carry, and refuses `all` alongside a
23
+ * non-empty list, which would be two answers to one question.
24
+ */
25
+ export declare function normalizeSlashAllow(values: readonly string[], label: string): readonly string[];
26
+ /** Whether the policy admits this native name. */
27
+ export declare function allowsSlashName(policy: QaSlashPolicy, name: string): boolean;
28
+ /** The admitted subset, in the order the native registry returned it. */
29
+ export declare function filterBySlashPolicy<T extends {
30
+ readonly name: string;
31
+ }>(entries: readonly T[], policy: QaSlashPolicy): readonly T[];
32
+ /**
33
+ * Intersect an already-admitted list with a second name set (the session's
34
+ * role grant). An empty set means "no second opinion" — the role system keeps
35
+ * its own switch, and a deployment that never enabled it grants nothing here.
36
+ */
37
+ export declare function intersectSlashNames<T extends {
38
+ readonly name: string;
39
+ }>(entries: readonly T[], names: readonly string[] | undefined): readonly T[];
40
+ //# sourceMappingURL=policy.d.ts.map
@@ -0,0 +1,35 @@
1
+ import type { Context } from "@deepseek-ai/cordis";
2
+ import type { PluginLogger } from "@yadsh/dsh-plugin-log";
3
+ import type { QaSlashCatalog, QaSlashExecution, QaSlashSubmitAttachment, ResolvedQaSurfaceConfig } from "../types.js";
4
+ /**
5
+ * Host-side bodies of the slash remotes. The `@Remote`-decorated signatures
6
+ * stay on the `QaSurface` service class (typert code generation reads the class
7
+ * shape); this context owns everything behind them.
8
+ *
9
+ * The division of labour is the whole feature in one sentence: QA decides what
10
+ * the palette may show and whether a line may run, and the native registries
11
+ * decide what a skill and a command *mean*. Nothing here reads a SKILL.md,
12
+ * injects instructions or re-implements a registry.
13
+ */
14
+ export interface QaSlashRemotes {
15
+ /** The catalog this browser may render, already policy-filtered. */
16
+ catalog(token: string, sessionId: string): Promise<QaSlashCatalog>;
17
+ /** Run one human command line through the native command runtime. */
18
+ execute(token: string, sessionId: string, line: string, attachments: readonly QaSlashSubmitAttachment[]): Promise<QaSlashExecution>;
19
+ }
20
+ export interface QaSlashRemotesOptions {
21
+ readonly ctx: Context;
22
+ readonly getConfig: () => ResolvedQaSurfaceConfig;
23
+ readonly logger: PluginLogger;
24
+ /**
25
+ * Ownership and role check for the current QA session. Runs only while the
26
+ * deployment gates QA users with accounts; it throws on refusal, which is
27
+ * what makes a foreign session unreadable instead of merely unowned.
28
+ *
29
+ * @returns the role's user-skill grant, or `undefined` when the access
30
+ * system has no opinion about this session's skills.
31
+ */
32
+ readonly sessionGrant: (token: string, sessionId: string, agent: unknown) => Promise<readonly string[] | undefined>;
33
+ }
34
+ export declare function createQaSlashRemotes(options: QaSlashRemotesOptions): QaSlashRemotes;
35
+ //# sourceMappingURL=remotes.d.ts.map