@sparkelf/dsh-knowledge-base 0.1.4 → 0.1.20

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 (60) hide show
  1. package/README.md +129 -2
  2. package/SKILL.md +86 -18
  3. package/lib/client.js +13915 -8694
  4. package/lib/client.js.map +1 -1
  5. package/lib/index.js +8098 -256
  6. package/lib/types/api.d.ts +36 -1
  7. package/lib/types/client/KnowledgeCreateDialog.d.ts +25 -0
  8. package/lib/types/client/KnowledgeFileTree.d.ts +143 -0
  9. package/lib/types/client/KnowledgeHome.d.ts +58 -0
  10. package/lib/types/client/KnowledgeListing.d.ts +7 -0
  11. package/lib/types/client/KnowledgeNewDocumentDialog.d.ts +32 -0
  12. package/lib/types/client/KnowledgeProgressPopover.d.ts +69 -0
  13. package/lib/types/client/KnowledgeSettings.d.ts +4 -3
  14. package/lib/types/client/KnowledgeTemplates.d.ts +4 -0
  15. package/lib/types/client/VectorSettingsGroup.d.ts +17 -0
  16. package/lib/types/client/WorkflowMenuIcon.d.ts +22 -0
  17. package/lib/types/client/dropTargetPath.d.ts +33 -0
  18. package/lib/types/client/extractionHistory.d.ts +43 -0
  19. package/lib/types/client/index.d.ts +32 -14
  20. package/lib/types/client/listingFilter.d.ts +58 -0
  21. package/lib/types/client/locales.d.ts +126 -0
  22. package/lib/types/client/openInSidebar.d.ts +2 -2
  23. package/lib/types/client/progressRules.d.ts +198 -17
  24. package/lib/types/client/sanitizeExplorerTabs.d.ts +20 -0
  25. package/lib/types/client/settingsGate.d.ts +65 -0
  26. package/lib/types/client/uploadTransport.d.ts +65 -0
  27. package/lib/types/client/useTreeSort.d.ts +72 -0
  28. package/lib/types/client/workflows/WorkflowPlaza.d.ts +146 -0
  29. package/lib/types/client/workflows/cron.d.ts +125 -0
  30. package/lib/types/client/workflows/dedupe.d.ts +70 -0
  31. package/lib/types/client/workflows/deps.d.ts +101 -0
  32. package/lib/types/client/workflows/modelChoice.d.ts +106 -0
  33. package/lib/types/client/workflows/published.d.ts +43 -0
  34. package/lib/types/client/workflows/registry.d.ts +98 -0
  35. package/lib/types/client/workflows/subscribe.d.ts +179 -0
  36. package/lib/types/embeddings.d.ts +62 -0
  37. package/lib/types/externalChange.d.ts +25 -0
  38. package/lib/types/extract.d.ts +32 -0
  39. package/lib/types/extractionQueue.d.ts +23 -2
  40. package/lib/types/ftsIndex.d.ts +497 -0
  41. package/lib/types/index.d.ts +266 -8
  42. package/lib/types/initialize.d.ts +105 -0
  43. package/lib/types/knowledgeTools.d.ts +239 -0
  44. package/lib/types/localStoragePath.d.ts +6 -0
  45. package/lib/types/localStorageSettings.d.ts +33 -0
  46. package/lib/types/managementTools.d.ts +184 -0
  47. package/lib/types/outlineGuard.d.ts +119 -0
  48. package/lib/types/outlineText.d.ts +134 -0
  49. package/lib/types/protocol.d.ts +34 -0
  50. package/lib/types/scopeAliases.d.ts +20 -0
  51. package/lib/types/trash.d.ts +14 -0
  52. package/lib/types/vectorIndex.d.ts +113 -0
  53. package/lib/types/views.d.ts +33 -1
  54. package/lib/types/workflowPublish.d.ts +114 -0
  55. package/package.json +7 -7
  56. package/skills/kb-summarize/SKILL.md +158 -0
  57. package/skills/kb-summarize/i18n/zh.json +10 -0
  58. package/skills/kb-vectorize/SKILL.md +57 -0
  59. package//344/270/207/347/233/270AI/344/275/277/347/224/250/346/225/231/347/250/213.html +294 -0
  60. package/lib/types/client/KnowledgeProgressPanel.d.ts +0 -53
@@ -0,0 +1,239 @@
1
+ /**
2
+ * Model-facing knowledge-base file tools (`kb_file_*`).
3
+ *
4
+ * The mounted tree is the one retrieval reads, but the plugin's write path is not
5
+ * "put bytes on disk": it decides permissions through DataOps, records an audit entry,
6
+ * keeps the caller's view in sync and records removals as tombstones. A shell write
7
+ * bypasses all of that, so the model gets tools that go through the same host
8
+ * operations as the HTTP routes.
9
+ *
10
+ * This module owns argument validation, the permission calls and the tool result
11
+ * shape. The host object is supplied by `index.ts`; it is the seam that reuses the
12
+ * existing `canReadPath` / `canWritePath` / `listDirectoryWithPermissions` /
13
+ * `readKnowledgeFile` / `createKnowledgeEntry` / `moveEntry` implementations, and it
14
+ * is what tests replace without importing the whole plugin.
15
+ *
16
+ * @module @sparkelf/dsh-knowledge-base/knowledgeTools
17
+ */
18
+ import type { FtsIndexStats, FtsSearchResult } from './ftsIndex.ts';
19
+ import type { OutlineKeyFact, OutlineTocEntry } from './outlineText.ts';
20
+ import type { OutlineSectionSubmission, OutlineSummaryKind } from './outlineGuard.ts';
21
+ import type { OutlineSaveResult } from './ftsIndex.ts';
22
+ import type { KnowledgeAuditEntry } from './views.ts';
23
+ /** Error codes a tool may report to the model. */
24
+ export type KnowledgeToolErrorCode = 'empty-path' | 'nul-byte' | 'absolute-path' | 'escapes-knowledge-root' | 'forbidden' | 'not-found' | 'exists' | 'too-large' | 'binary' | 'not-a-directory' | 'not-a-file' | 'not-configured' | 'unauthorized' | 'unreachable' | 'bad-response' | 'write-failed' | 'invalid-regex' | 'invalid-citation' | 'invalid-summary' | 'invalid';
25
+ /** Structured, model-readable failure. Thrown; never returned as a silent `false`. */
26
+ export declare class KnowledgeToolError extends Error {
27
+ readonly code: KnowledgeToolErrorCode;
28
+ readonly path?: string;
29
+ constructor(code: KnowledgeToolErrorCode, message: string, path?: string);
30
+ }
31
+ /** The identity a tool call acts as. */
32
+ export interface KnowledgeToolCaller {
33
+ userId: string;
34
+ label?: string;
35
+ }
36
+ /** One directory row, in view-relative coordinates. */
37
+ export interface KnowledgeFileEntry {
38
+ relPath: string;
39
+ name: string;
40
+ isDir: boolean;
41
+ size?: number;
42
+ mtimeMs?: number;
43
+ canExtract?: boolean;
44
+ hasMarkdown?: boolean;
45
+ }
46
+ /** One search hit, in view-relative coordinates. */
47
+ export interface KnowledgeFileHit {
48
+ relPath: string;
49
+ name: string;
50
+ inContent: boolean;
51
+ line?: string;
52
+ lineNumber?: number;
53
+ mtimeMs?: number;
54
+ }
55
+ /** One outline section as `kb_outline` returns it: navigation, never evidence. */
56
+ export interface KnowledgeOutlineSection {
57
+ sectionId: string;
58
+ /** Full heading path (`第三章 > 第二十二条`). */
59
+ sectionPath: string;
60
+ /** 1-based depth; 1 is a chapter/top-level heading. */
61
+ level: number;
62
+ summary: string;
63
+ keyFacts: OutlineKeyFact[];
64
+ /** Chunks whose own heading is this section. */
65
+ chunkIds: number[];
66
+ /** Every chunk under this section, including descendants. */
67
+ sourceChunkIds: number[];
68
+ }
69
+ /** A document's INDEX.md outline. No chapter body is included. */
70
+ export interface KnowledgeOutline {
71
+ docId: number;
72
+ /** Original source path (citable document). */
73
+ path: string;
74
+ displayPath?: string;
75
+ summary: string;
76
+ /** How the current summary was produced. */
77
+ summaryKind?: OutlineSummaryKind;
78
+ /** `missing` until `kb-summarize` saves a model-authored summary. */
79
+ summaryStatus?: 'ready' | 'missing';
80
+ /** Actionable next step when the summary is missing. */
81
+ hint?: string;
82
+ summaryVersion?: string;
83
+ /** Source chunk ids behind the document summary. */
84
+ sourceChunkIds?: number[];
85
+ toc: OutlineTocEntry[];
86
+ sections: KnowledgeOutlineSection[];
87
+ /** Absolute path of the generated `/nas/kb/index/md/<docId>.INDEX.md`. */
88
+ indexPath: string;
89
+ }
90
+ /** What reading a file produced. */
91
+ export type KnowledgeFileRead = {
92
+ kind: 'text';
93
+ content: string;
94
+ truncated: boolean;
95
+ mtimeMs?: number;
96
+ } | {
97
+ kind: 'binary';
98
+ size: number;
99
+ };
100
+ /** Audit outcome for a completed write: never turns a successful write into a failure. */
101
+ export type KnowledgeAuditOutcome = {
102
+ written: true;
103
+ } | {
104
+ written: false;
105
+ reason: string;
106
+ };
107
+ /** A view refresh that failed after the write itself succeeded. */
108
+ export type KnowledgeViewSync = {
109
+ failure?: string;
110
+ };
111
+ /**
112
+ * The host operations the tools compose.
113
+ *
114
+ * Every method is the SAME implementation an HTTP route uses. The host owns permission
115
+ * policy and filesystem layout; this module never derives a root or a grant itself.
116
+ */
117
+ export interface KnowledgeFileToolHost {
118
+ /** Resolve the caller (team: DataOps `/auth/me`; personal: the local operator). */
119
+ resolveCaller(): Promise<KnowledgeToolCaller>;
120
+ /** Backend DSH permission for this operation, when the host has a permission context. */
121
+ hasPermission?(permission: string): Promise<boolean>;
122
+ /** FTS5 search over the sidecar index, already scoped to the caller. */
123
+ searchIndex?(input: {
124
+ query: string;
125
+ scope?: string;
126
+ topK: number;
127
+ }): Promise<FtsSearchResult>;
128
+ /** Incremental index sync. */
129
+ syncIndex?(): Promise<FtsIndexStats>;
130
+ /** Explicitly vectorize one document, a directory subtree, or all targets. */
131
+ vectorize?(input: {
132
+ docId?: number;
133
+ path?: string;
134
+ scope?: string;
135
+ rebuild?: boolean;
136
+ dryRun?: boolean;
137
+ }): Promise<Record<string, unknown>>;
138
+ /** Resolve a citation token to its original source + anchors. */
139
+ chunkGet?(input: {
140
+ docId: number;
141
+ chunkId: number | string;
142
+ }): Promise<{
143
+ docId: number;
144
+ chunkId: number;
145
+ chunkKey?: string;
146
+ citation?: string;
147
+ path: string;
148
+ quote?: string;
149
+ heading?: string;
150
+ paragraph?: number;
151
+ chunkOrdinal?: number;
152
+ paragraphText?: string;
153
+ sheet?: string;
154
+ cell?: string;
155
+ page?: number;
156
+ boxes: import('./ftsIndex.ts').FtsChunkBox[];
157
+ snippet: string;
158
+ }>;
159
+ /** Read/build one document outline, already permission-checked by the host. */
160
+ outline?(input: {
161
+ docId: number;
162
+ }): Promise<KnowledgeOutline>;
163
+ /** Re-render INDEX.md from stored summaries; never regenerates summary text. */
164
+ outlineRewrite?(input: {
165
+ docId: number;
166
+ }): Promise<{
167
+ indexPath: string;
168
+ }>;
169
+ /** Persist one model-authored outline after the host checked read+write permission. */
170
+ outlineSave?(input: {
171
+ docId: number;
172
+ summary: string;
173
+ sections: readonly OutlineSectionSubmission[];
174
+ summaryVersion?: string;
175
+ }): Promise<OutlineSaveResult | undefined>;
176
+ canRead(relPath: string): Promise<boolean>;
177
+ canWrite(relPath: string): Promise<boolean>;
178
+ /** One view directory level, already filtered by `canReadPath`. */
179
+ list(relPath: string, caller: KnowledgeToolCaller): Promise<KnowledgeFileEntry[]>;
180
+ /** Search under one view-relative scope. */
181
+ search(scope: string, query: string, limit: number): Promise<KnowledgeFileHit[]>;
182
+ /** Path boundary + `canReadPath` + `readKnowledgeFile`, shared with the read route. */
183
+ readAuthorized(relPath: string): Promise<KnowledgeFileRead>;
184
+ statEntry(relPath: string): Promise<{
185
+ kind: 'file' | 'directory';
186
+ size?: number;
187
+ } | undefined>;
188
+ createEntry(relPath: string, options: {
189
+ directory: boolean;
190
+ content?: string;
191
+ }): Promise<{
192
+ relPath: string;
193
+ kind: 'file' | 'directory';
194
+ }>;
195
+ /** Overwrite an existing file in place, preserving its inode/view hardlink. */
196
+ overwriteFile(relPath: string, content: string): Promise<void>;
197
+ moveEntry(from: string, to: string, caller: KnowledgeToolCaller): Promise<{
198
+ from: string;
199
+ to: string;
200
+ }>;
201
+ /** Record a tombstone in the caller's trash; never unlinks bytes. */
202
+ deleteToTrash(caller: KnowledgeToolCaller, relPath: string, kind: 'file' | 'directory'): Promise<void>;
203
+ refreshView(expectVisible?: string): Promise<KnowledgeViewSync>;
204
+ readSettings(caller: KnowledgeToolCaller): Promise<{
205
+ reviewRequired?: boolean;
206
+ mineruBaseUrl?: string;
207
+ }>;
208
+ parkWrite(caller: KnowledgeToolCaller, relPath: string, content: string): Promise<void>;
209
+ /** Enqueue one document; mirrors the manual extraction route's outcomes. */
210
+ enqueueExtraction(relPath: string, caller: KnowledgeToolCaller): Promise<{
211
+ outcome: 'already-markdown' | 'unsupported' | 'exists' | 'queued';
212
+ markdown?: string;
213
+ task?: unknown;
214
+ }>;
215
+ /** Extractable files under the authoritative root that have no `.md` sibling yet. */
216
+ listExtractCandidates(limit: number): Promise<string[]>;
217
+ viewDir(userId: string): string;
218
+ appendAudit(viewDir: string, entry: KnowledgeAuditEntry): Promise<void>;
219
+ isExtractable(relPath: string): boolean;
220
+ now?(): Date;
221
+ }
222
+ /** The sentence every tool carries: use these tools, not the shell. */
223
+ export declare const KB_FILE_TOOL_GUIDANCE: string;
224
+ /** Map a host failure to a structured tool error without losing its code. */
225
+ export declare const asKnowledgeToolError: (error: unknown, path?: string) => KnowledgeToolError;
226
+ /**
227
+ * Validate one model-supplied path in view coordinates.
228
+ *
229
+ * Empty is allowed only where the root itself is the argument (list/search/extract-all);
230
+ * everything else is refused with the same four codes `checkLocalPath` uses.
231
+ */
232
+ export declare const assertToolPath: (value: unknown, allowRoot?: boolean) => string;
233
+ /**
234
+ * Build the five file model-facing tools.
235
+ *
236
+ * Returned definitions are registered by `apply`; tests call the same definitions with
237
+ * a fake host to assert permission, path and audit behaviour without a live backend.
238
+ */
239
+ export declare const createKnowledgeFileTools: (host: KnowledgeFileToolHost) => import("@deepseek-ai/dsh-tools").ToolDefinition[];
@@ -0,0 +1,6 @@
1
+ /** Directory holding the authoritative files under the storage root. */
2
+ export declare const STORAGE_ACTUAL_DIR = "actual";
3
+ /** Expand the UI's storage path into an absolute storage base. */
4
+ export declare function resolveStorageRoot(raw: string, home?: string): string;
5
+ /** The authoritative `actual/` directory for a storage base. */
6
+ export declare function storageActualRoot(storageRoot: string): string;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Deployment-level settings for a LOCAL knowledge deployment.
3
+ *
4
+ * These values cannot live under `mountPoint`: the local mount point IS the
5
+ * configured storage root, so reading the setting from there would make the
6
+ * default impossible to discover after the operator points it somewhere else.
7
+ * A small file under `$DSH_HOME` breaks that cycle. It contains no credentials
8
+ * and no document content, only the one path the Settings page owns.
9
+ *
10
+ * @module @sparkelf/dsh-knowledge-base/local-storage-settings
11
+ */
12
+ /** The local deployment fields the Settings page may change. */
13
+ export interface LocalStorageSettings {
14
+ /** Authoritative root, absolute or `~/...`. */
15
+ storageRoot?: string;
16
+ }
17
+ /** Path of the profile-local settings file. */
18
+ export declare function localStorageSettingsPath(home?: string, dshHome?: string | undefined): string;
19
+ /**
20
+ * Read the local settings file, tolerating absence/corruption.
21
+ * @returns The stored fields, empty when nothing usable exists.
22
+ */
23
+ export declare function readLocalStorageSettings(): Promise<LocalStorageSettings>;
24
+ /**
25
+ * Store one storage-root choice atomically.
26
+ *
27
+ * The value is validated by the same resolver the view builder uses, so a
28
+ * relative path is rejected at write time rather than becoming a process-cwd
29
+ * surprise on the next restart.
30
+ * @param storageRoot - new root, absolute or `~/...`.
31
+ * @returns The normalised value actually written.
32
+ */
33
+ export declare function writeLocalStorageRoot(storageRoot: string): Promise<string>;
@@ -0,0 +1,184 @@
1
+ /**
2
+ * Model-facing management tools for the knowledge base and the workflow plaza.
3
+ *
4
+ * The UI already exposes these operations. This module gives the model the same
5
+ * operations without re-implementing authorization: every tool reads the backend
6
+ * review context (roles + department scope) and refuses with a structured 403 before
7
+ * touching the host. Writes additionally require an explicit human authorization flag,
8
+ * because a model deciding on its own must never be indistinguishable from an operator
9
+ * approving a review.
10
+ *
11
+ * Secrets are write-only through the UI; these tools deliberately reject secret-shaped
12
+ * fields and redact them on reads.
13
+ *
14
+ * @module @sparkelf/dsh-knowledge-base/managementTools
15
+ */
16
+ /** A structured refusal the model can act on. */
17
+ export declare class ManagementToolError extends Error {
18
+ readonly code: 'forbidden' | 'invalid' | 'not-found' | 'backend';
19
+ readonly name = "ManagementToolError";
20
+ constructor(code: 'forbidden' | 'invalid' | 'not-found' | 'backend', message: string);
21
+ }
22
+ /** The backend's review context, narrowed to the fields these tools use. */
23
+ export interface ManagementContext {
24
+ readonly userId: string;
25
+ readonly username?: string;
26
+ readonly displayName?: string;
27
+ readonly primaryRole?: string;
28
+ readonly roleCodes: readonly string[];
29
+ /** Backend DSH permission keys resolved for the caller's roles. */
30
+ readonly permissions: readonly string[];
31
+ readonly departmentCode?: string | null;
32
+ readonly departmentPathCodes?: readonly string[];
33
+ readonly dataScope: {
34
+ readonly all: boolean;
35
+ readonly self: boolean;
36
+ readonly departmentCodes: readonly string[];
37
+ };
38
+ readonly review: {
39
+ readonly canReview: boolean;
40
+ readonly canReviewGlobal: boolean;
41
+ readonly canManagePermissions: boolean;
42
+ readonly departments: readonly string[];
43
+ };
44
+ }
45
+ /** One grant row as the host reports it. */
46
+ export interface ManagementGrant {
47
+ readonly id?: string;
48
+ readonly relPath: string;
49
+ readonly kind?: string;
50
+ readonly principalType?: string;
51
+ readonly principalId?: string;
52
+ readonly action?: string;
53
+ readonly grantedBy?: string;
54
+ readonly grantedAt?: string;
55
+ }
56
+ /** One audit entry. */
57
+ export interface ManagementAudit {
58
+ readonly at: string;
59
+ readonly actor: string;
60
+ readonly actorLabel?: string;
61
+ readonly action: string;
62
+ readonly relPath?: string;
63
+ readonly outcome?: string;
64
+ }
65
+ /** One KB pending submission. */
66
+ export interface ManagementPending {
67
+ readonly name: string;
68
+ readonly userId: string;
69
+ readonly relPath: string;
70
+ readonly at: string;
71
+ readonly bytes: number;
72
+ }
73
+ /** One workflow row shared by the public and review lists. */
74
+ export interface ManagementWorkflow {
75
+ readonly id: string;
76
+ readonly title: string;
77
+ readonly description?: string;
78
+ readonly instruction?: string;
79
+ readonly cronHint?: string | null;
80
+ readonly category?: string | null;
81
+ readonly reviewStatus?: string;
82
+ readonly visibility?: string;
83
+ readonly departmentCode?: string | null;
84
+ readonly ownerId?: string;
85
+ readonly ownerName?: string;
86
+ readonly sourceSessionId?: string | null;
87
+ readonly builtIn?: boolean;
88
+ }
89
+ /** One visible bucket. */
90
+ export interface ManagementBucket {
91
+ readonly name: string;
92
+ readonly visibility: string;
93
+ readonly departmentCode?: string | null;
94
+ readonly writable?: boolean;
95
+ }
96
+ /** The host operations tools compose. */
97
+ export interface ManagementToolHost {
98
+ context(): Promise<ManagementContext>;
99
+ kbConfigGet(): Promise<Record<string, unknown>>;
100
+ kbConfigUpdate(patch: Record<string, unknown>): Promise<Record<string, unknown>>;
101
+ kbGrantList(): Promise<readonly ManagementGrant[]>;
102
+ kbGrantSet(input: {
103
+ relPath: string;
104
+ principalType: string;
105
+ principalId: string;
106
+ action: string;
107
+ }): Promise<ManagementGrant>;
108
+ kbAuditList(filter: {
109
+ action?: string;
110
+ actor?: string;
111
+ path?: string;
112
+ from?: string;
113
+ to?: string;
114
+ limit?: number;
115
+ }): Promise<readonly ManagementAudit[]>;
116
+ kbReviewList(): Promise<readonly ManagementPending[]>;
117
+ kbReviewDecide(input: {
118
+ name: string;
119
+ decision: 'approve' | 'reject';
120
+ note?: string;
121
+ }): Promise<unknown>;
122
+ kbSync(): Promise<unknown>;
123
+ kbIndexRebuild(): Promise<unknown>;
124
+ kbBucketList(): Promise<readonly ManagementBucket[]>;
125
+ workflowList(query: {
126
+ scope?: string;
127
+ status?: string;
128
+ }): Promise<readonly ManagementWorkflow[]>;
129
+ workflowUpdate(input: Record<string, unknown>): Promise<unknown>;
130
+ workflowUnpublish(id: string): Promise<unknown>;
131
+ workflowReviewList(query: {
132
+ status?: string;
133
+ scope?: string;
134
+ departmentCode?: string;
135
+ }): Promise<readonly ManagementWorkflow[]>;
136
+ workflowReviewScan(ids: readonly string[]): Promise<unknown>;
137
+ workflowReviewDecide(input: {
138
+ ids: readonly string[];
139
+ decision: 'approve' | 'reject';
140
+ note?: string;
141
+ }): Promise<unknown>;
142
+ }
143
+ type Capability = 'global' | 'reviewer' | 'reader';
144
+ /** Role defaults used only when the permission matrix cannot be read (e.g. APP_USER). */
145
+ export declare const DEFAULT_DSH_PERMISSIONS: Readonly<Record<string, readonly string[]>>;
146
+ /** Union the default permission keys for a set of role system keys. */
147
+ export declare function defaultPermissionsForRoles(roleKeys: readonly string[]): string[];
148
+ /** True when the caller holds one backend permission key. */
149
+ export declare function hasPermission(context: ManagementContext, permission: string): boolean;
150
+ /** Require one backend permission key; a denial is a structured 403. */
151
+ export declare function requirePermission(context: ManagementContext, permission: string, action?: string): void;
152
+ /** Global administrators: all resources and all review queues. */
153
+ export declare function isGlobalAdmin(context: ManagementContext): boolean;
154
+ /** Department reviewers: their department and its descendants. */
155
+ export declare function isDepartmentReviewer(context: ManagementContext): boolean;
156
+ /** Require one capability; throws a structured 403 rather than returning false. */
157
+ export declare function requireCapability(context: ManagementContext, capability: Capability): void;
158
+ /** True when a path belongs to one of the caller's departments. */
159
+ export declare function isPathInDepartmentScope(context: ManagementContext, relPath: string): boolean;
160
+ /** Require department scope for one path; global admins bypass. */
161
+ export declare function requirePathScope(context: ManagementContext, relPath: string): void;
162
+ /** Publishing scope the workflow tool accepts. */
163
+ export type WorkflowPublishVisibility = 'global' | 'department' | 'private';
164
+ /**
165
+ * Normalize and authorize a publish scope.
166
+ *
167
+ * Ordinary users and department admins may only publish inside their own department
168
+ * (or privately); global visibility is reserved for platform admins. A department
169
+ * administrator cannot name a child/other department here even though review visibility
170
+ * can include descendants.
171
+ */
172
+ export declare function normalizePublishScope(context: ManagementContext, visibility: WorkflowPublishVisibility | undefined, departmentCode: string | undefined): {
173
+ visibility: WorkflowPublishVisibility;
174
+ departmentCode: string;
175
+ };
176
+ /** Writes require an explicit human confirmation. */
177
+ export declare function requireConfirmed(value: unknown): void;
178
+ /** Refuse an object carrying a secret-shaped field. */
179
+ export declare function assertNoSecretFields(value: unknown, path?: string): void;
180
+ /** Redact secret-shaped values on reads. */
181
+ export declare function redactSecrets<T>(value: T): T;
182
+ /** Build all management tools. */
183
+ export declare const createManagementTools: (host: ManagementToolHost) => import("@deepseek-ai/dsh-tools").ToolDefinition[];
184
+ export {};
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Grounding checks for model-written document summaries.
3
+ *
4
+ * Uploading and extraction never create prose. A summary only enters the index when the
5
+ * `kb-summarize` skill has read the original chunks and the model submits it through
6
+ * `kb_outline_save`; this module is the gate between that submission and the database.
7
+ *
8
+ * The gate is deliberately mechanical. It does not judge whether a sentence is a good
9
+ * summary, because that is the model's job. It refuses a submission whose numbers,
10
+ * ratios, clause numbers or responsible bodies cannot be found in the source chunks the
11
+ * summary claims to describe. Normalization is strict but language-aware: full-width
12
+ * digits, Chinese numerals, `5万元`/`50000元`, `百分之三十`/`30%` and `第三条`/`第3条`
13
+ * all collapse to one token before comparison.
14
+ *
15
+ * @module @sparkelf/dsh-knowledge-base/outlineGuard
16
+ */
17
+ import type { OutlineSection } from './outlineText.ts';
18
+ /** How a document's current summary was produced. */
19
+ export type OutlineSummaryKind = 'none' | 'extractive' | 'llm';
20
+ /** One key fact as a model submits it. `value` is the source-grounded claim. */
21
+ export interface OutlineKeyFactSubmission {
22
+ /** Article heading or label; defaults to the section title. */
23
+ fact?: string;
24
+ /** Threshold/ratio/body/exception sentence copied from the source. */
25
+ value: string;
26
+ /** Chunk the value came from; must belong to the document and the section. */
27
+ chunkId?: number;
28
+ }
29
+ /** One section summary as a model submits it. */
30
+ export interface OutlineSectionSubmission {
31
+ sectionId: string;
32
+ /** Full heading path from `kb_outline`; a mismatch is refused rather than renamed. */
33
+ headingPath?: string;
34
+ summary?: string;
35
+ keyFacts?: Array<string | OutlineKeyFactSubmission>;
36
+ /** Chunks the summary was written from; must be a subset of the section's chunks. */
37
+ sourceChunkIds?: number[];
38
+ }
39
+ /** One refused field. The caller can show this to the model and retry. */
40
+ export interface OutlineSaveRejection {
41
+ /** Dotted path within the submission, e.g. `sections[2].summary`. */
42
+ field: string;
43
+ reason: string;
44
+ sectionId?: string;
45
+ /** Bounded copy of the offending value, when one exists. */
46
+ value?: string;
47
+ /** Tokens/subjects that could not be found in the source chunks. */
48
+ missing?: string[];
49
+ }
50
+ /** A named section, as stored in `kb_sections`. */
51
+ export type StoredOutlineSection = Pick<OutlineSection, 'sectionId' | 'headingPath' | 'title' | 'level' | 'summary' | 'keyFacts' | 'chunkIds' | 'sourceChunkIds'>;
52
+ /** One chunk the gate may ground a claim against. */
53
+ export interface GroundingChunk {
54
+ id: number;
55
+ content: string;
56
+ }
57
+ /** The complete, validated row set to persist. */
58
+ export interface OutlineSavePlan {
59
+ summary: string;
60
+ /** Source chunks behind the document summary. */
61
+ docSourceChunkIds: number[];
62
+ /** Every section row, with submitted summaries replacing the stored ones. */
63
+ sections: StoredOutlineSection[];
64
+ keyFactCount: number;
65
+ }
66
+ /** Result of planning one save: either a plan, or the fields that were refused. */
67
+ export type OutlineSavePlanResult = {
68
+ ok: true;
69
+ plan: OutlineSavePlan;
70
+ } | {
71
+ ok: false;
72
+ rejected: OutlineSaveRejection[];
73
+ };
74
+ /** Maximum document summary length accepted from a model. */
75
+ export declare const MAX_DOC_SUMMARY_CHARS = 4000;
76
+ /** Maximum one section summary length accepted from a model. */
77
+ export declare const MAX_SECTION_SUMMARY_CHARS = 2000;
78
+ /** Maximum key facts one section may carry. */
79
+ export declare const MAX_KEY_FACTS_PER_SECTION = 20;
80
+ /** Maximum sections one save may carry. */
81
+ export declare const MAX_SUBMITTED_SECTIONS = 500;
82
+ /**
83
+ * Collapse presentation differences that do not change a claim.
84
+ *
85
+ * Used for source/claim comparison, never for display: the stored summary keeps the
86
+ * model's original wording (including Chinese numerals and full-width punctuation).
87
+ */
88
+ export declare function normalizeOutlineGrounding(value: string): string;
89
+ /** Convert a Chinese numeral (or digit string) to a number. */
90
+ export declare function chineseNumberToArabic(raw: string): number | undefined;
91
+ /**
92
+ * Extract the tokens a claim must share with its source.
93
+ *
94
+ * Tokens cover just the auditable classes: Arabic/Chinese numbers, percentages, Chinese
95
+ * fractions, ratios, clause numbers and common amounts. Ordinary prose is deliberately
96
+ * not tokenized, because a summary is allowed to paraphrase it.
97
+ */
98
+ export declare function extractGroundingTokens(value: string): string[];
99
+ /** Extract responsible-body terms from one claim. */
100
+ export declare function extractSubjectTerms(value: string): string[];
101
+ /** One submitted save request, as the planner sees it. */
102
+ export interface OutlineSaveSubmission {
103
+ docId: number;
104
+ summary: string;
105
+ sections: readonly OutlineSectionSubmission[];
106
+ }
107
+ /**
108
+ * Validate and assemble the complete row set for one save.
109
+ *
110
+ * Nothing here touches SQLite or the filesystem. A refusal returns every rejected field
111
+ * so the model can repair the whole submission in one retry; a success returns the rows
112
+ * that will be written inside one transaction.
113
+ */
114
+ export declare function planOutlineSave(input: {
115
+ docId: number;
116
+ chunks: readonly GroundingChunk[];
117
+ storedSections: readonly StoredOutlineSection[];
118
+ submission: OutlineSaveSubmission;
119
+ }): OutlineSavePlanResult;