@sparkelf/dsh-knowledge-base 0.0.0-stage → 0.1.1

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 (67) hide show
  1. package/LICENSE +21 -0
  2. package/SKILL.md +147 -0
  3. package/cordis.patch.yml +5 -0
  4. package/i18n/zh.json +10 -0
  5. package/lib/client.js +18308 -0
  6. package/lib/client.js.map +1 -0
  7. package/lib/index.js +6005 -0
  8. package/lib/types/api.d.ts +620 -0
  9. package/lib/types/client/KnowledgeAudit.d.ts +39 -0
  10. package/lib/types/client/KnowledgeContextMenu.d.ts +121 -0
  11. package/lib/types/client/KnowledgeCreateDialog.d.ts +134 -0
  12. package/lib/types/client/KnowledgeFileTree.d.ts +117 -0
  13. package/lib/types/client/KnowledgeHome.d.ts +102 -0
  14. package/lib/types/client/KnowledgeIndexing.d.ts +60 -0
  15. package/lib/types/client/KnowledgeListing.d.ts +174 -0
  16. package/lib/types/client/KnowledgeLoading.d.ts +41 -0
  17. package/lib/types/client/KnowledgeMenuIcon.d.ts +27 -0
  18. package/lib/types/client/KnowledgePanel.d.ts +58 -0
  19. package/lib/types/client/KnowledgePermissionOverview.d.ts +147 -0
  20. package/lib/types/client/KnowledgePermissions.d.ts +47 -0
  21. package/lib/types/client/KnowledgeProgressPanel.d.ts +53 -0
  22. package/lib/types/client/KnowledgeReferencePicker.d.ts +81 -0
  23. package/lib/types/client/KnowledgeSearch.d.ts +83 -0
  24. package/lib/types/client/KnowledgeSectionHeader.d.ts +71 -0
  25. package/lib/types/client/KnowledgeSelectionBar.d.ts +45 -0
  26. package/lib/types/client/KnowledgeSettings.d.ts +96 -0
  27. package/lib/types/client/KnowledgeSettingsSection.d.ts +21 -0
  28. package/lib/types/client/KnowledgeShareDialog.d.ts +70 -0
  29. package/lib/types/client/KnowledgeTemplates.d.ts +43 -0
  30. package/lib/types/client/KnowledgeTrash.d.ts +62 -0
  31. package/lib/types/client/MenuGlyphs.d.ts +37 -0
  32. package/lib/types/client/auditPaging.d.ts +40 -0
  33. package/lib/types/client/departmentFolders.d.ts +57 -0
  34. package/lib/types/client/deployTarget.d.ts +34 -0
  35. package/lib/types/client/index.d.ts +40 -0
  36. package/lib/types/client/insertReadiness.d.ts +60 -0
  37. package/lib/types/client/knowledgeMenuCopy.d.ts +23 -0
  38. package/lib/types/client/locales.d.ts +505 -0
  39. package/lib/types/client/openInSidebar.d.ts +62 -0
  40. package/lib/types/client/ownerLabel.d.ts +39 -0
  41. package/lib/types/client/paging.d.ts +69 -0
  42. package/lib/types/client/permissionRows.d.ts +265 -0
  43. package/lib/types/client/progressRules.d.ts +54 -0
  44. package/lib/types/client/referenceTargets.d.ts +60 -0
  45. package/lib/types/client/roleSummary.d.ts +47 -0
  46. package/lib/types/client/saveAudit.d.ts +87 -0
  47. package/lib/types/client/shareRelations.d.ts +81 -0
  48. package/lib/types/client/useFavorites.d.ts +49 -0
  49. package/lib/types/client/useFileDrop.d.ts +171 -0
  50. package/lib/types/client/useFileDropHook.d.ts +64 -0
  51. package/lib/types/client/usePinnedPaths.d.ts +39 -0
  52. package/lib/types/client/useTreeState.d.ts +46 -0
  53. package/lib/types/client/useViewMode.d.ts +39 -0
  54. package/lib/types/deploy.d.ts +209 -0
  55. package/lib/types/extract.d.ts +144 -0
  56. package/lib/types/extractionQueue.d.ts +154 -0
  57. package/lib/types/index.d.ts +899 -0
  58. package/lib/types/permissions.d.ts +237 -0
  59. package/lib/types/protocol.d.ts +229 -0
  60. package/lib/types/remote.d.ts +105 -0
  61. package/lib/types/trash.d.ts +142 -0
  62. package/lib/types/viewMetadata.d.ts +20 -0
  63. package/lib/types/views.d.ts +923 -0
  64. package/package.json +109 -4
  65. package/skills/kb-organize/SKILL.md +365 -0
  66. package/skills/kb-organize/i18n/zh.json +10 -0
  67. package/README.md +0 -3
@@ -0,0 +1,174 @@
1
+ /**
2
+ * A directory listing with the modification time each entry carries.
3
+ *
4
+ * The row is the file explorer's own row from `dsh-better-sidebar`, copied from
5
+ * `src/client/FileTree.tsx` (`FileRow`/`DirRow`) and `src/client/sidebar.module.css`
6
+ * (`.explorerRow`): the same `div[role=button]`, the same 14px glyph, the same
7
+ * ellipsised name, the same trailing modified time that yields its right edge to
8
+ * the same hover-revealed `@` reference button, and the same `depth * 22 + 6`
9
+ * indent. A reader sees that tree in this window's right sidebar, so a second
10
+ * design beside it reads as bolted on -- which is why this is a copy rather than
11
+ * a re-drawing.
12
+ *
13
+ * What the borrowed tree cannot carry is why this list exists. Its host entry
14
+ * shape (`FsEntry`: name, path, isDir, hidden, isSymlink, broken) has no
15
+ * timestamp, so a row built from it can never show when a document last changed;
16
+ * and its rows decide visibility from a shared curated store rather than from
17
+ * per-user grants. This panel reads the same directories through the plugin's own
18
+ * route, which stats each child, and its row carries a right-click into the grant
19
+ * form the tree has no place for.
20
+ *
21
+ * @module @sparkelf/dsh-knowledge-base/client
22
+ */
23
+ import { type ReactNode } from 'react';
24
+ /** Props for the listing panel. */
25
+ export interface KnowledgeListingProps {
26
+ /** Locale-bound copy resolver. */
27
+ t: (key: string) => string;
28
+ /** Called with a chosen path so the page can show its preview. */
29
+ onOpen: (path: string) => void;
30
+ /** Re-read trigger, so a rescan from elsewhere refreshes this too. */
31
+ refreshTick?: number;
32
+ /** Locale tag, so dates match the reader's language. */
33
+ locale?: string;
34
+ /**
35
+ * Open the permission surface for one path.
36
+ *
37
+ * Exists because the borrowed tree's context menu is built inside it with no way
38
+ * to add a row, so the grant entry lives here instead: this is the plugin's own
39
+ * listing, where a right-click can mean what the knowledge base needs it to mean.
40
+ */
41
+ onGrant?: (path: string) => void;
42
+ /**
43
+ * Insert one row's reference into the conversation draft.
44
+ *
45
+ * The borrowed tree reveals this affordance on hover; the listing mirrors that so
46
+ * a reader gets the same `@` action from either tree.
47
+ */
48
+ onReference?: (path: string, isDir: boolean) => void;
49
+ /**
50
+ * Pin or unpin one row.
51
+ *
52
+ * Omitted by a caller that has no pin store, which is how the search results list
53
+ * stays free of an action that would only make sense inside the tree.
54
+ */
55
+ onPin?: (path: string, pinned: boolean) => void;
56
+ /** Whether one path is currently pinned, so the row can mark it. */
57
+ isPinned?: (path: string) => boolean;
58
+ /**
59
+ * Star or unstar one row.
60
+ *
61
+ * Omitted by a caller with no favourites store, which is how the search results list
62
+ * stays free of an entry that would only make sense inside the tree. A folder is
63
+ * favoured the same way a file is: the star marks a row, not a document.
64
+ */
65
+ onFavorite?: (path: string, favorite: boolean) => void;
66
+ /** Whether one path is currently favourited, so the row can draw its star. */
67
+ isFavorite?: (path: string) => boolean;
68
+ /**
69
+ * The path a paste would land in, given the row this menu was opened on.
70
+ *
71
+ * A directory row pastes INTO itself; a file row pastes beside itself. Kept a
72
+ * callback rather than derived in the menu because only the listing knows whether a
73
+ * row is the tree's root, which has no parent to paste beside.
74
+ */
75
+ pasteTargetFor?: (relPath: string, isDir: boolean) => string | null;
76
+ /**
77
+ * Upload external files dropped onto a directory row.
78
+ *
79
+ * Distinct from the row-to-row move handled above: a file dragged in from the
80
+ * desktop carries no `KB_DRAG_MIME`, so it is the only case this callback serves.
81
+ * Omitted by a read-only caller, which keeps the rows from accepting a drop that
82
+ * would then be refused on the Host.
83
+ * @param relPath - the directory the files were dropped onto.
84
+ * @param files - the dropped files with paths relative to that directory.
85
+ */
86
+ onUpload?: (relPath: string, files: readonly {
87
+ file: unknown;
88
+ relativePath: string;
89
+ }[]) => void;
90
+ /**
91
+ * Called after a menu-driven delete or paste succeeded.
92
+ *
93
+ * Both change paths this component is currently holding -- a delete removes one, a
94
+ * paste adds one and empties another -- so the page has to reload rather than the
95
+ * component guessing which levels moved.
96
+ */
97
+ onTreeChanged?: () => void;
98
+ /**
99
+ * Called after a rename succeeded, so the page reloads the tree.
100
+ *
101
+ * The listing cannot reload itself: it reads through `refreshTick`, which the page
102
+ * owns, and a rename changes the paths this component is currently holding.
103
+ */
104
+ onRenamed?: () => void;
105
+ /**
106
+ * Render one row's action as "unpin" rather than "pin".
107
+ *
108
+ * The pinned band lists paths that are already pinned, so every row there offers
109
+ * the opposite action; deriving it from a flag keeps one row shape for both bands.
110
+ */
111
+ unpinOnly?: boolean;
112
+ /**
113
+ * Narrow the tree to rows whose name contains this text.
114
+ *
115
+ * Filtering happens over the rows already read, so it costs no request: the tree
116
+ * section header's search is the in-place narrowing, while the rail's field is the
117
+ * cross-directory search. A filter that matched nothing read as an empty tree, so
118
+ * the two empty states are kept apart.
119
+ */
120
+ filter?: string;
121
+ /**
122
+ * Start with every directory expanded.
123
+ *
124
+ * Used by the pinned band, where a pinned folder is only useful if its contents
125
+ * are already visible.
126
+ */
127
+ expandAll?: boolean;
128
+ /**
129
+ * The action offered when the tree genuinely holds no documents.
130
+ *
131
+ * Distinct from a filter that matched nothing: an empty tree wants a way to make
132
+ * a document, while an unmatched filter wants a different search term.
133
+ */
134
+ emptyAction?: ReactNode;
135
+ /**
136
+ * Move one entry into a directory, or pin it when the target is the pin band.
137
+ *
138
+ * Omitted by a caller that must stay read-only, which is how the search results
139
+ * list keeps its rows free of a gesture the Host would refuse there.
140
+ */
141
+ onMove?: (from: string, toDirectory: string) => void;
142
+ /**
143
+ * The layout to render. `list` is the tree; `grid` is the document cards.
144
+ *
145
+ * Defaults to the tree so a caller that does not persist a preference behaves
146
+ * exactly as it did before the card view existed.
147
+ */
148
+ viewMode?: 'list' | 'grid';
149
+ /**
150
+ * Enter multi-select. A callback rather than internal state because the batch
151
+ * bar's actions are the host's (they move and pin through the same routes a
152
+ * single drag uses), so the selection has to be visible to it.
153
+ */
154
+ onSelectionChange?: (paths: readonly string[]) => void;
155
+ /** The current selection, so a batch action can act on it. */
156
+ selection?: readonly string[];
157
+ }
158
+ /**
159
+ * The drag payload's MIME type.
160
+ *
161
+ * Exported because the drop target that pins is NOT in this component: the pin
162
+ * band lives in the panel, and the two have to agree on the name of the thing
163
+ * being carried. The native drag payload is used rather than lifted React state
164
+ * for exactly that reason -- it crosses the component boundary the gesture
165
+ * crosses, without the panel having to hold a second copy of the tree's state.
166
+ */
167
+ export declare const KB_DRAG_MIME = "application/x-dsh-kb-path";
168
+ /**
169
+ * Render the listing for the mount's top level, and one level per expanded
170
+ * directory.
171
+ * @param props - copy resolver and the open callback.
172
+ * @returns The listing panel.
173
+ */
174
+ export declare function KnowledgeListing(props: KnowledgeListingProps): import("react").JSX.Element;
@@ -0,0 +1,41 @@
1
+ /**
2
+ * The loading state, as a book whose page turns.
3
+ *
4
+ * The knowledge base is a library of documents, so a turning page says what is
5
+ * happening in the product's own terms rather than with a generic spinner. The
6
+ * animation is CSS and inline SVG: no animation library, because this plugin ships
7
+ * as one bundled file and a dependency would grow it and add a supply-chain surface
8
+ * for a decoration.
9
+ *
10
+ * The motion is a real 3D turn rather than a sequence of drawn frames: the leaf is a
11
+ * zero-thickness plane inside a `perspective` container, rotated about the spine with
12
+ * `rotateY`. That keeps the whole effect to two keyframes and makes the direction of
13
+ * travel read correctly at any moment, which a frame sequence does not.
14
+ *
15
+ * @module @sparkelf/dsh-knowledge-base/client
16
+ */
17
+ /** Props for the loading surface. */
18
+ export interface KnowledgeLoadingProps {
19
+ /**
20
+ * What is being loaded, in the reader's language.
21
+ *
22
+ * Optional because a card or a table cell may have no label of its own; the
23
+ * animation then stands alone and the accessible name falls back to the shared
24
+ * loading sentence.
25
+ */
26
+ label?: string;
27
+ /**
28
+ * Accessible name for the animation itself.
29
+ *
30
+ * Required rather than derived: the animation is decorative, so it must either be
31
+ * hidden from assistive technology or carry a name, and hiding it silently would
32
+ * leave a screen-reader user with no announcement that anything is loading.
33
+ */
34
+ announce?: string;
35
+ }
36
+ /**
37
+ * Render the book-turning loading animation.
38
+ * @param props - the optional label and the accessible announcement.
39
+ * @returns The centred loading surface.
40
+ */
41
+ export declare function KnowledgeLoading(props: KnowledgeLoadingProps): import("react").JSX.Element;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * The glyph the left sidebar renders for the knowledge-base entry.
3
+ *
4
+ * `sidebar.panellist` is a list of icon buttons, so this component receives only a
5
+ * size and never renders a surface. The page the entry selects is a separate
6
+ * component registered against the `main` key.
7
+ *
8
+ * The glyph is the product's own icon component rather than a local path: the rail
9
+ * sits directly beside the other panel icons, and a hand-drawn stroke read visibly
10
+ * heavier than its neighbours. Using the product icon keeps the rail uniform and
11
+ * lets the size the sidebar passes through unchanged.
12
+ *
13
+ * @module @sparkelf/dsh-knowledge-base/client
14
+ */
15
+ /** Props the sidebar list passes to one entry. */
16
+ export interface KnowledgeMenuIconProps {
17
+ /** Glyph edge length in pixels, chosen by the sidebar for its current width. */
18
+ size?: number;
19
+ /** Whether this entry is the selected panel. */
20
+ active?: boolean;
21
+ }
22
+ /**
23
+ * Render the knowledge-base glyph.
24
+ * @param props - sidebar-supplied glyph size.
25
+ * @returns The product icon sized for the sidebar rail.
26
+ */
27
+ export declare function KnowledgeMenuIcon(props: KnowledgeMenuIconProps): import("react").JSX.Element;
@@ -0,0 +1,58 @@
1
+ /**
2
+ * The knowledge-base management page.
3
+ *
4
+ * Selected by the left-sidebar entry and rendered into the `main` slot, so it
5
+ * replaces the conversation area. The page carries its own master-detail layout:
6
+ * the rail holds a menu above the knowledge tree, and the content region shows
7
+ * whichever surface the rail selected (a file preview, permissions, or indexing).
8
+ *
9
+ * The tree is this package's own listing rather than the file component from
10
+ * `dsh-better-sidebar`. That component renders icon and name only and builds its
11
+ * context menu internally, so it has nowhere to show whether a row is readable and
12
+ * nowhere to add a grant entry, while the actions its menu does offer (rename,
13
+ * delete, upload) edit a shared curated store rather than deciding who may see a
14
+ * document. The one thing worth keeping from it is the `@`-reference action, reused
15
+ * through its own helper so both trees insert the same reference.
16
+ *
17
+ * @module @sparkelf/dsh-knowledge-base/client
18
+ */
19
+ /**
20
+ * The session binding the page scopes its file tree with.
21
+ *
22
+ * It is a subscribable observable rather than a plain value because the session it
23
+ * names appears only after a Workspace is chosen, which regularly happens after
24
+ * this page has already mounted.
25
+ */
26
+ export interface SessionSource {
27
+ /** Current binding; `key` is the session id, absent before a session exists. */
28
+ getSnapshot: () => {
29
+ key?: unknown;
30
+ };
31
+ /** Subscribe to changes; returns the unsubscribe function. */
32
+ subscribe: (listener: () => void) => () => void;
33
+ }
34
+ /** Values the `main` slot injects into the page. */
35
+ export interface KnowledgePanelInjected {
36
+ /** Locale-bound copy for this package's namespace. */
37
+ t: (key: string) => string;
38
+ /** Locale tag the slot bound for this namespace, so dates match the reader. */
39
+ locale?: string;
40
+ /** Source of the session the file tree resolves its scope from. */
41
+ sessionSource: SessionSource;
42
+ /**
43
+ * The client context, needed by the borrowed tree's `@` helper.
44
+ *
45
+ * That helper resolves the workspace root and the conversation input service
46
+ * itself, so it needs the context rather than the values it reads from it.
47
+ */
48
+ ctx: unknown;
49
+ }
50
+ /** Props the page receives. */
51
+ export interface KnowledgePanelProps extends Partial<KnowledgePanelInjected> {
52
+ }
53
+ /**
54
+ * Render the knowledge-base management page.
55
+ * @param props - injected locale copy and the current session id.
56
+ * @returns The master-detail page.
57
+ */
58
+ export declare function KnowledgePanel(props: KnowledgePanelProps): import("react").JSX.Element;
@@ -0,0 +1,147 @@
1
+ /**
2
+ * The permissions surface: one grant table, read two ways.
3
+ *
4
+ * A grant says "this principal may do this action to this path". That is the right
5
+ * shape to STORE and the wrong shape to AUDIT: an administrator asking "what does
6
+ * 张三 have" and "who can see 制度.md" is asking two questions that one
7
+ * row-per-grant layout cannot answer without being read line by line.
8
+ *
9
+ * So the page has one body and two readings of it. The tabs switch which question
10
+ * is being asked; both render the same loaded grants, so the two can never
11
+ * disagree. No second endpoint exists because there is no second truth.
12
+ *
13
+ * The tables are the page's own body rather than a summary above one. An earlier
14
+ * version stacked both readings as bulleted lists and *also* drew a third,
15
+ * row-per-principal table underneath: three renderings of one payload, so the
16
+ * reader had to work out which of the three was authoritative before reading any
17
+ * of them. Two tabs over one table removes that question.
18
+ *
19
+ * @module @sparkelf/dsh-knowledge-base/client/KnowledgePermissionOverview
20
+ */
21
+ import type { GrantView, KnowledgeGrantSubjectType } from '../api.ts';
22
+ import { type RoleSummary } from './roleSummary.ts';
23
+ /** Which reading of the grant table the tabs are showing. */
24
+ export type OverviewTab = 'person' | 'role' | 'resource';
25
+ /** Copy for the overview, supplied by the caller's locale record. */
26
+ export interface OverviewCopy {
27
+ tabByPerson: string;
28
+ tabByRole: string;
29
+ tabByResource: string;
30
+ empty: string;
31
+ /** Empty state per view, so "nobody is directly granted" is not shown for a role. */
32
+ emptyByPerson: string;
33
+ emptyByRole: string;
34
+ emptyByResource: string;
35
+ /** Where a principal's access comes from. */
36
+ sourceDirect: string;
37
+ /** Format "inherited via role X": `{role}` is replaced by the role code. */
38
+ sourceViaRole: (role: string) => string;
39
+ /** Shown when the user directory could not be read, so inheritance is unknowable. */
40
+ sourceUnavailable: string;
41
+ /** Word for a permission set that could not be fully determined. */
42
+ actionsUnknown: string;
43
+ actionsUnknownHint: string;
44
+ /** Column headers unique to the three views. */
45
+ colAccount: string;
46
+ colSource: string;
47
+ /** "{count} member(s)". */
48
+ roleMemberCount: (count: number) => string;
49
+ /** Pager copy, shared with the audit table's wording. */
50
+ pagerPrev: string;
51
+ pagerNext: string;
52
+ pagerStatus: (page: number, pageCount: number, total: number) => string;
53
+ pageSizeLabel: string;
54
+ pageSizeOption: (size: number) => string;
55
+ pathsHeld: (count: number) => string;
56
+ rolesHeld: string;
57
+ actionsHeld: string;
58
+ builtInRoles: string;
59
+ noActions: string;
60
+ /** Accessible name for the tab strip, for readers who arrive at it by keyboard. */
61
+ tabsLabel: string;
62
+ /** Stat-card labels: the four numbers the page leads with. */
63
+ statPrincipals: string;
64
+ statResources: string;
65
+ statGrants: string;
66
+ statRoles: string;
67
+ /** Shared column headers, person reading. */
68
+ colPrincipal: string;
69
+ colKind: string;
70
+ colPermission: string;
71
+ colResources: string;
72
+ colExpiry: string;
73
+ colActions: string;
74
+ /** Shared column headers, resource reading. */
75
+ colResource: string;
76
+ colHolders: string;
77
+ colKindOfResource: string;
78
+ revoke: string;
79
+ revokeBusy: string;
80
+ expiryNever: string;
81
+ kindFile: string;
82
+ kindDirectory: string;
83
+ /** Formats "N grants · M paths" under a person's name. */
84
+ grantsUnit: (count: number) => string;
85
+ resourcesUnit: (count: number) => string;
86
+ /**
87
+ * Resolves a principal kind and an action to its localized word.
88
+ *
89
+ * Supplied as callbacks rather than as a keyed map so this component never
90
+ * reaches into the locale record itself: a caller with its own wording (a test,
91
+ * another surface) can pass its own, and the type checker still enforces that
92
+ * every kind and action the table can print has a word.
93
+ */
94
+ kindLabel: (kind: KnowledgeGrantSubjectType) => string;
95
+ actionLabel: (action: string) => string;
96
+ }
97
+ /** Props the parent panel supplies. */
98
+ export interface KnowledgePermissionOverviewProps {
99
+ /** The grant table already loaded by the permissions page. */
100
+ grants: readonly GrantView[];
101
+ /** Display names by `principalType:principalId`. */
102
+ labels?: Readonly<Record<string, string>>;
103
+ /**
104
+ * The DataOps account directory, when the caller could read it.
105
+ *
106
+ * Absent means the same as an unavailable read: inheritance cannot be attributed, and
107
+ * the page says so instead of listing accounts that look like they hold nothing.
108
+ */
109
+ directory?: {
110
+ kind: 'available';
111
+ users: ReadonlyArray<{
112
+ id: string;
113
+ label: string;
114
+ username?: string;
115
+ roleCodes?: string[];
116
+ }>;
117
+ } | {
118
+ kind: 'unavailable';
119
+ reason: string;
120
+ };
121
+ /** Built-in role summaries, so the person view can explain what a role means. */
122
+ roles?: readonly RoleSummary[];
123
+ /** Locale copy. */
124
+ copy: OverviewCopy;
125
+ /**
126
+ * Asks the parent to confirm revoking the grants one row covers.
127
+ *
128
+ * The confirmation lives in the parent because it is a dialog, and a dialog in
129
+ * the middle of a table's row renderer would make the table responsible for
130
+ * ownership of the overlay. This component says *what* to revoke; the parent
131
+ * decides whether to ask first and then performs it.
132
+ */
133
+ onRevoke: (grants: GrantView[], label: string) => void;
134
+ /** Disables every revoke control while a write is in flight. */
135
+ busy?: boolean;
136
+ }
137
+ /**
138
+ * Render the permission overview as stat cards over a three-tab table.
139
+ *
140
+ * THREE views, not two, because the old pair answered different questions under one
141
+ * heading: "by person" listed ROLE grants, so the only rows were 管理员 and 超级管理员
142
+ * and a reader concluding "these are the people with access" was reading the page
143
+ * correctly and being told something false. A role is not a person.
144
+ *
145
+ * @param props - grants, labels, directory, role summaries, copy and the revoke hook.
146
+ */
147
+ export declare function KnowledgePermissionOverview(props: KnowledgePermissionOverviewProps): import("react").JSX.Element;
@@ -0,0 +1,47 @@
1
+ /**
2
+ * The permissions surface of the management page.
3
+ *
4
+ * This view reads and writes grants through the DSH Host, which forwards them to
5
+ * the DataOps backend. It deliberately holds no policy of its own: the backend's
6
+ * authorization resolves the principal, checks the caller's permission keys, and
7
+ * enforces what a grant means. The page only presents the result, so a rule
8
+ * change lands in one place.
9
+ *
10
+ * The page leads with its table. A grant list is what an operator opens this
11
+ * surface to read, so the data is the body of the page and the two things that
12
+ * CHANGE it -- creating a grant, revoking one -- are raised into dialogs. A form
13
+ * parked above the table would push the answer below the fold to make room for
14
+ * the question.
15
+ *
16
+ * @module @sparkelf/dsh-knowledge-base/client
17
+ */
18
+ import { type ReactNode } from 'react';
19
+ /** Props for the permissions surface. */
20
+ export interface KnowledgePermissionsProps {
21
+ /**
22
+ * Publishes this page's primary control to the panel header.
23
+ *
24
+ * The header is the only band at the top of the page, so a page-level action has
25
+ * to be handed up rather than drawn in a second title row.
26
+ */
27
+ onAction?: (action: ReactNode) => void;
28
+ /** Locale-bound copy resolver. */
29
+ t: (key: string) => string;
30
+ /** Mount point the grants are scoped to. */
31
+ mountPoint: string;
32
+ /** Path the user selected, when the surface opened from a file row. */
33
+ initialPath?: string;
34
+ /**
35
+ * Changes when a row's context menu picks a new path.
36
+ *
37
+ * The form's path field is seeded from `initialPath` once; without a signal that
38
+ * the seed changed, a second right-click would leave the field on the first path.
39
+ */
40
+ reloadToken?: number;
41
+ }
42
+ /**
43
+ * Render the permission editor.
44
+ * @param props - copy resolver and the mount point grants are scoped to.
45
+ * @returns The permission surface.
46
+ */
47
+ export declare function KnowledgePermissions(props: KnowledgePermissionsProps): import("react").JSX.Element;
@@ -0,0 +1,53 @@
1
+ /**
2
+ * The progress strip at the bottom of the knowledge base panel.
3
+ *
4
+ * Uploading a document and extracting its text are two waits a reader cannot see
5
+ * otherwise: the drop appears to do nothing until the bytes land, and a scanned PDF
6
+ * looks uploaded while its `.md` sibling is still being produced. Both are reported
7
+ * here, in one place, at the bottom of the surface the reader is already looking at.
8
+ *
9
+ * It is a resident strip rather than a toast on purpose. A toast is gone before a slow
10
+ * parse finishes, and the reader's next question ("did it work?") has nowhere to go;
11
+ * this stays until the work is done and then folds to one line so it stops taking
12
+ * space without taking the record away.
13
+ *
14
+ * Nothing here is persisted. A refresh loses the history, which is the right trade: the
15
+ * files themselves are on disk, and a stale "uploading 40%" from yesterday would be a
16
+ * lie the reader cannot clear.
17
+ *
18
+ * @module @sparkelf/dsh-knowledge-base/client
19
+ */
20
+ /** One file's upload, as the strip shows it. */
21
+ export interface UploadTaskView {
22
+ /** The file's path relative to the drop target: the name the reader dropped. */
23
+ name: string;
24
+ /** The tree-relative directory it is landing in, `''` for the mount root. */
25
+ dir: string;
26
+ /** Where this file is in its own lifecycle. */
27
+ state: 'waiting' | 'uploading' | 'done' | 'failed';
28
+ /** Why it failed, in the Host's own words. */
29
+ reason?: string;
30
+ }
31
+ /** Props for the progress strip. */
32
+ export interface KnowledgeProgressPanelProps {
33
+ /** Locale-bound copy resolver. */
34
+ t: (key: string) => string;
35
+ /** The batch currently uploading, oldest first; empty when nothing is in flight. */
36
+ uploads: readonly UploadTaskView[];
37
+ /**
38
+ * Whether to read extraction progress at all.
39
+ *
40
+ * False on a surface that cannot extract (no mount, or a caller without write
41
+ * access): polling a route whose answer can never be acted on is a request per
42
+ * reader that buys nothing.
43
+ */
44
+ watchExtraction: boolean;
45
+ /** Called after a retry was accepted, so the caller can refresh its own views. */
46
+ onRetried?: (relPath: string) => void;
47
+ }
48
+ /**
49
+ * Render the bottom progress strip.
50
+ * @param props - the upload batch, whether to watch extraction, and the copy resolver.
51
+ * @returns The strip, or nothing when there is no work to show.
52
+ */
53
+ export declare function KnowledgeProgressPanel(props: KnowledgeProgressPanelProps): import("react").JSX.Element | null;
@@ -0,0 +1,81 @@
1
+ /**
2
+ * The `@`-mention picker: choose which conversation a knowledge file goes into.
3
+ *
4
+ * The explorer row's `@` button used to answer `if (sessionId === undefined) return`
5
+ * -- a page with no conversation open simply dropped the click, so the button looked
6
+ * broken. But "no conversation open" is exactly the state this page is in most of the
7
+ * time: it is a management surface, not a chat. The reference still has to land
8
+ * somewhere, so the click now asks where.
9
+ *
10
+ * Two things are deliberately borrowed rather than invented:
11
+ *
12
+ * The insertion itself is `referenceInChat`, the same contract the sidebar explorer
13
+ * and the viewer's selection popup call. That function owns the whole policy this
14
+ * dialog must not re-derive: which workspace root the mention is relative to, the
15
+ * chip spelling for files versus folders, the quoted form for paths with spaces, and
16
+ * the "degrade to a logged no-op" behaviour when a service is missing. Building a
17
+ * second insertion path here would be the one way to make the two surfaces disagree.
18
+ *
19
+ * The session list and the navigation are the host's own services, resolved lazily
20
+ * through `ctx.get` rather than injected: this dialog is mounted whether or not the
21
+ * user has ever opened a conversation, and a page that cannot see `uiSession` must
22
+ * still render (it would show an empty list, not crash).
23
+ *
24
+ * @module @sparkelf/dsh-knowledge-base/client
25
+ */
26
+ /** Props for the picker. */
27
+ export interface KnowledgeReferencePickerProps {
28
+ /** Whether the dialog is showing. */
29
+ open: boolean;
30
+ /** Close without referencing anything. */
31
+ onClose: () => void;
32
+ /** Absolute path of the entry the `@` button was pressed on. */
33
+ path: string;
34
+ /** Whether that entry is a directory (a folder mention rather than a file chip). */
35
+ isDir: boolean;
36
+ /**
37
+ * Every entry a multi-row selection asked to reference.
38
+ *
39
+ * Present only when the `@` button was pressed with several rows selected; the
40
+ * single-row case keeps using `path`/`isDir`. Each entry carries its own `isDir`
41
+ * because a selection may mix folders and documents, and the mention spelling
42
+ * differs between them.
43
+ *
44
+ * This is one dialog for both cases on purpose: "where should this go" is the same
45
+ * question whether one row or five are being referenced, and a second batch-only
46
+ * dialog would be a second place for the insertion contract to drift.
47
+ */
48
+ targets?: readonly {
49
+ path: string;
50
+ isDir: boolean;
51
+ }[];
52
+ /** The client context; both the draft insert and the service lookups need it. */
53
+ ctx: unknown;
54
+ /** Locale-bound copy for this package's namespace. */
55
+ t: (key: string) => string;
56
+ /** Locale tag, so a session's timestamp reads in the reader's language. */
57
+ locale?: string;
58
+ /**
59
+ * The conversation the host currently has selected, read at call time.
60
+ *
61
+ * The New Session flow creates a conversation asynchronously and does not return
62
+ * its id, so the only way to name it afterwards is to ask the page's own session
63
+ * binding -- the same observable the file tree is scoped by. Reading it lazily
64
+ * rather than as a prop is what makes it current by the time the draft is ready.
65
+ */
66
+ selectedSessionId?: () => string | undefined;
67
+ /**
68
+ * Called once a reference was actually inserted, with the session that received it.
69
+ *
70
+ * The dialog closes itself either way; this exists so the page can report which
71
+ * conversation the file went to, which is the only feedback a reader gets when the
72
+ * target tab is not the one they were looking at.
73
+ */
74
+ onReferenced?: (sessionId: string) => void;
75
+ }
76
+ /**
77
+ * The `@`-mention session picker.
78
+ * @param props - the entry to reference and the dialog's state.
79
+ * @returns The dialog, or null while closed.
80
+ */
81
+ export declare function KnowledgeReferencePicker(props: KnowledgeReferencePickerProps): import("react").JSX.Element;