@sparkelf/dsh-knowledge-base 0.1.5 → 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 (58) hide show
  1. package/README.md +129 -2
  2. package/SKILL.md +86 -18
  3. package/lib/client.js +14766 -9663
  4. package/lib/client.js.map +1 -1
  5. package/lib/index.js +8082 -258
  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/extractionHistory.d.ts +43 -0
  18. package/lib/types/client/index.d.ts +32 -14
  19. package/lib/types/client/listingFilter.d.ts +58 -0
  20. package/lib/types/client/locales.d.ts +123 -0
  21. package/lib/types/client/openInSidebar.d.ts +2 -2
  22. package/lib/types/client/progressRules.d.ts +198 -17
  23. package/lib/types/client/sanitizeExplorerTabs.d.ts +20 -0
  24. package/lib/types/client/settingsGate.d.ts +65 -0
  25. package/lib/types/client/uploadTransport.d.ts +65 -0
  26. package/lib/types/client/useTreeSort.d.ts +72 -0
  27. package/lib/types/client/workflows/WorkflowPlaza.d.ts +146 -0
  28. package/lib/types/client/workflows/cron.d.ts +125 -0
  29. package/lib/types/client/workflows/dedupe.d.ts +70 -0
  30. package/lib/types/client/workflows/deps.d.ts +101 -0
  31. package/lib/types/client/workflows/modelChoice.d.ts +106 -0
  32. package/lib/types/client/workflows/published.d.ts +43 -0
  33. package/lib/types/client/workflows/registry.d.ts +98 -0
  34. package/lib/types/client/workflows/subscribe.d.ts +179 -0
  35. package/lib/types/embeddings.d.ts +62 -0
  36. package/lib/types/externalChange.d.ts +25 -0
  37. package/lib/types/extract.d.ts +32 -0
  38. package/lib/types/extractionQueue.d.ts +23 -2
  39. package/lib/types/ftsIndex.d.ts +497 -0
  40. package/lib/types/index.d.ts +266 -8
  41. package/lib/types/initialize.d.ts +105 -0
  42. package/lib/types/knowledgeTools.d.ts +239 -0
  43. package/lib/types/localStoragePath.d.ts +6 -0
  44. package/lib/types/localStorageSettings.d.ts +33 -0
  45. package/lib/types/managementTools.d.ts +184 -0
  46. package/lib/types/outlineGuard.d.ts +119 -0
  47. package/lib/types/outlineText.d.ts +134 -0
  48. package/lib/types/protocol.d.ts +34 -0
  49. package/lib/types/scopeAliases.d.ts +20 -0
  50. package/lib/types/vectorIndex.d.ts +113 -0
  51. package/lib/types/views.d.ts +33 -1
  52. package/lib/types/workflowPublish.d.ts +114 -0
  53. package/package.json +7 -7
  54. package/skills/kb-summarize/SKILL.md +158 -0
  55. package/skills/kb-summarize/i18n/zh.json +10 -0
  56. package/skills/kb-vectorize/SKILL.md +57 -0
  57. package//344/270/207/347/233/270AI/344/275/277/347/224/250/346/225/231/347/250/213.html +294 -0
  58. package/lib/types/client/KnowledgeProgressPanel.d.ts +0 -53
@@ -5,8 +5,8 @@
5
5
  * 1. The protocol contract toward the DataOps knowledge API (`protocol.ts`).
6
6
  * 2. Idempotent deployment recipes for the remote pieces, run over the
7
7
  * ssh-manager seam (`deploy.ts`, `remote.ts`).
8
- * 3. The same-origin HTTP surface the Settings panel reads, plus the two
9
- * model-facing tools.
8
+ * 3. The same-origin HTTP surface the Settings panel reads, plus the
9
+ * model-facing `kb_search` / `kb_chunk_get` / `kb_outline` / `kb_file_*` tools.
10
10
  *
11
11
  * It owns no authorization logic. DataOps AuthGuard and PermissionGuard resolve
12
12
  * the caller's roles and grants from the session credential; this plugin only
@@ -19,12 +19,16 @@
19
19
  * @module @sparkelf/dsh-knowledge-base
20
20
  */
21
21
  import type { Context } from '@deepseek-ai/cordis';
22
+ import { type WorkflowActor } from './workflowPublish.ts';
22
23
  import z from '@deepseek-ai/schemastery';
23
24
  import { type KnowledgeConfig, type KnowledgeGrant, type KnowledgeGrantRequest, type KnowledgeRevokeRequest, type KnowledgeSshView, type KnowledgeStatus } from './protocol.ts';
25
+ import { type ScopeLocale } from './scopeAliases.ts';
24
26
  import { type KnowledgeStorageSettings, type ViewDelta } from './views.ts';
25
27
  import { type DeployPlanContext, type MineruBackend, type MineruTier } from './deploy.ts';
26
28
  import { type RemoteHost, type RemoteRunner } from './remote.ts';
27
29
  import { type ExtractionOutcome } from './extractionQueue.ts';
30
+ import { type MineruBlock } from './extract.ts';
31
+ import { type KnowledgeFileRead } from './knowledgeTools.ts';
28
32
  /** Cordis plugin name. */
29
33
  export declare const name = "dsh-knowledge-base";
30
34
  /**
@@ -74,6 +78,8 @@ export interface Config {
74
78
  actualRoot: string;
75
79
  /** Absolute path of the per-user view tree on the storage host. */
76
80
  viewRoot: string;
81
+ /** Local deployments: authoritative storage base, default `~/kb`. */
82
+ storageRoot: string;
77
83
  /** Comma-separated export spec of clients allowed to mount the NFS export. */
78
84
  permitted: string;
79
85
  /** Host serving the export, as an address or `address:/path` pseudo root. */
@@ -116,16 +122,101 @@ export interface Config {
116
122
  mineruBaseUrl: string;
117
123
  /** Memory ceiling in MiB for the MinerU service, clamped to half the host's RAM. */
118
124
  mineruMemoryMaxMiB: number;
125
+ /**
126
+ * Directory holding `published.json` for the workflow plaza.
127
+ *
128
+ * Empty keeps the profile-local default (`$DSH_HOME/workflow-plaza`): the store is
129
+ * product metadata of this profile, not knowledge-tree content, so it deliberately
130
+ * does not live under the mount or the view root.
131
+ */
132
+ publishDir: string;
133
+ /** Sidecar directory for the SQLite FTS5 index (outside the agent-visible tree). */
134
+ indexDir?: string;
135
+ /** Optional hybrid retrieval. Disabled by default; no provider is called unless enabled. */
136
+ retrieval: {
137
+ vector: import('./embeddings.ts').VectorRetrievalConfig;
138
+ };
139
+ /**
140
+ * Outline generation policy.
141
+ *
142
+ * `autoGenerate: false` (the default) means upload/extraction build only the TOC and
143
+ * section structure. Summaries are written later by the `kb-summarize` skill through
144
+ * `kb_outline_save`. `true` restores the legacy deterministic extractive summaries.
145
+ */
146
+ outline: {
147
+ autoGenerate: boolean;
148
+ };
149
+ /** Locale used for the virtual root aliases in search/citation display paths. */
150
+ scopeLocale: ScopeLocale;
119
151
  }
120
152
  /** Config schema; an invalid value fails the profile load loudly. */
121
153
  export declare const Config: z<Config>;
122
154
  /** Why a knowledge-base request failed, with a stable machine-routable code. */
123
- export type KnowledgeErrorCode = 'not-configured' | 'unauthorized' | 'unreachable' | 'bad-response';
155
+ export type KnowledgeErrorCode = 'not-configured' | 'unauthorized' | 'unreachable' | 'bad-response' | 'escapes-knowledge-root' | 'absolute-path' | 'empty-path' | 'nul-byte';
124
156
  /** Typed knowledge-base failure. */
125
157
  export declare class KnowledgeError extends Error {
126
158
  readonly code: KnowledgeErrorCode;
127
159
  constructor(message: string, code: KnowledgeErrorCode, options?: ErrorOptions);
128
160
  }
161
+ /**
162
+ * Whether this deployment runs with a DataOps backend at all.
163
+ *
164
+ * `baseUrl` is the single fact that decides it: an empty value is a PERSONAL deployment, and
165
+ * a filled one is a TEAM deployment whose accounts, permissions, grants, shared settings and
166
+ * templates live in DataOps. This is an environment fact read from configuration, not a
167
+ * feature flag chosen at runtime -- which is why the personal and team paths are the same
168
+ * code with different gates rather than two branches selected by a boolean.
169
+ *
170
+ * Two consequences follow, and both are deliberate:
171
+ *
172
+ * 1. A personal deployment has NO accounts, NO permission model, NO shared settings and NO
173
+ * member management. Those are not disabled features; they do not exist without an
174
+ * authority to ask.
175
+ * 2. Every route that used to answer "not configured" now answers normally, gated on the
176
+ * local filesystem instead. An unconfigured deployment is a supported shape, not an
177
+ * error state.
178
+ *
179
+ * @param config - resolved plugin config.
180
+ * @returns true when a DataOps backend is configured.
181
+ */
182
+ export declare function isTeamDeployment(config: Config): boolean;
183
+ /**
184
+ * The identity a personal deployment acts as.
185
+ *
186
+ * A personal deployment has no caller to ask about: there is one operator, at the keyboard,
187
+ * with the file permissions of the process. `viewPathFor` still keys a view directory by
188
+ * user id, so this constant keeps that code path single rather than adding a second one for
189
+ * "no user".
190
+ */
191
+ export declare const LOCAL_USER_ID = "local";
192
+ /**
193
+ * Why a path was refused in a personal deployment.
194
+ *
195
+ * Named rather than silently refused: the reader asked for a file and the answer must say
196
+ * whether the path left the knowledge root or was simply not there.
197
+ */
198
+ export interface LocalPathRefusal {
199
+ /** Machine-readable reason. */
200
+ readonly code: 'escapes-knowledge-root' | 'absolute-path' | 'empty-path' | 'nul-byte';
201
+ /** One sentence naming what was wrong with the path. */
202
+ readonly reason: string;
203
+ }
204
+ /**
205
+ * Whether a personal deployment may read or write one path.
206
+ *
207
+ * A personal deployment has no OTHER users to protect a path from, so there is no grant to
208
+ * consult -- but that is not the same as having no boundary. The boundary is the knowledge
209
+ * root itself: a relative path that stays inside `actualRoot` is allowed, and anything that
210
+ * climbs out is refused with a reason.
211
+ *
212
+ * The check is spelled out instead of relying on `join(root, relPath)` to clamp, because a
213
+ * silent clamp would let `../../etc/passwd` resolve to something inside the tree and report
214
+ * success for a request that should have been refused.
215
+ *
216
+ * @param relPath - the path as the caller sent it, relative to the knowledge root.
217
+ * @returns undefined when the path is allowed, else why it is not.
218
+ */
219
+ export declare function checkLocalPath(relPath: string): LocalPathRefusal | undefined;
129
220
  /**
130
221
  * The resolved layout, derived on the Host.
131
222
  *
@@ -135,6 +226,10 @@ export declare class KnowledgeError extends Error {
135
226
  * @param config - resolved plugin config.
136
227
  * @returns The layout the page renders.
137
228
  */
229
+ /** The authoritative root for a local deployment. */
230
+ export declare function localStorageRoot(config: Config): string;
231
+ /** Overlay the profile-local storage-root setting on a config. */
232
+ export declare function withLocalStorageRoot(config: Config, storageRoot: string | undefined): Config;
138
233
  export declare function localConfig(config: Config,
139
234
  /**
140
235
  * Whether the SSHFS credential currently resolves.
@@ -148,6 +243,7 @@ sshKeyConfigured?: boolean): KnowledgeConfig & {
148
243
  backendConfigured: boolean;
149
244
  storageProtocol: 'nfs' | 'sshfs';
150
245
  ssh: KnowledgeSshView;
246
+ retrieval: import('./embeddings.ts').VectorRetrievalConfig;
151
247
  };
152
248
  /**
153
249
  * Read the mounted tree's shape without consulting a backend.
@@ -434,6 +530,22 @@ export declare function readKnowledgeFile(ctx: Context, config: Config, relPath:
434
530
  kind: 'binary';
435
531
  size: number;
436
532
  }>;
533
+ /**
534
+ * Read one file AFTER resolving the caller's permission for it.
535
+ *
536
+ * The HTTP `read` route used to rely on the caller's view hardlink alone: the file was
537
+ * visible because a previous sync linked it, but a revoke or an unsynced view could
538
+ * leave a readable link behind. Both the read route and the extraction path now share this
539
+ * function, so the permission answer is DataOps' and the path boundary is still
540
+ * enforced first.
541
+ *
542
+ * @param ctx - Host context.
543
+ * @param config - resolved plugin config.
544
+ * @param relPath - path relative to the knowledge root, in view coordinates.
545
+ * @returns The same shape `readKnowledgeFile` returns.
546
+ * @throws KnowledgeToolError with a structured code for the model.
547
+ */
548
+ export declare function readAuthorized(ctx: Context, config: Config, relPath: string): Promise<KnowledgeFileRead>;
437
549
  /**
438
550
  * Read one file as raw bytes for a save-to-disk.
439
551
  *
@@ -616,7 +728,7 @@ export declare function canWritePath(ctx: Context, config: Config, relPath: stri
616
728
  * post an arbitrarily large body, because nothing downstream limits the size of a
617
729
  * file on the share.
618
730
  */
619
- export declare const MAX_KNOWLEDGE_WRITE_BYTES = 1048576;
731
+ export declare const MAX_KNOWLEDGE_WRITE_BYTES: number;
620
732
  /**
621
733
  * How long the template list may take before the surface gives up.
622
734
  *
@@ -672,6 +784,16 @@ export declare function createKnowledgeEntry(config: Config, relPath: string, op
672
784
  directory: boolean;
673
785
  content?: string;
674
786
  bytes?: Uint8Array;
787
+ /**
788
+ * The ceiling this write is checked against.
789
+ *
790
+ * Defaults to {@link MAX_KNOWLEDGE_WRITE_BYTES}. It is injectable ONLY so a test can
791
+ * verify the boundary with a small body: the production ceiling is a product decision
792
+ * that has already moved (1 MiB → 500 MiB), and building a payload at the current
793
+ * ceiling costs seconds of string work. A test that has to allocate the limit is
794
+ * measuring the machine's memory bandwidth, not the check.
795
+ */
796
+ limitBytes?: number;
675
797
  }): Promise<{
676
798
  relPath: string;
677
799
  kind: 'file' | 'directory';
@@ -687,12 +809,25 @@ export declare function createKnowledgeEntry(config: Config, relPath: string, op
687
809
  *
688
810
  * @param config - resolved plugin config, for the knowledge root and MinerU port.
689
811
  * @param relPath - the uploaded document's path, relative to the knowledge root.
812
+ * @param mineruUrl - the caller's own stored address, when they have one.
813
+ * @param readSharedUrl - reads the deployment's shared address. Called only when the caller
814
+ * has none of their own, so a deployment without the OCR plugin pays nothing.
690
815
  * @returns What happened, or undefined when the format needs no extraction.
691
816
  */
692
- export declare function extractBeside(config: Config, relPath: string, mineruUrl?: string): Promise<{
817
+ /**
818
+ * Resolve a view-relative path to the authoritative path.
819
+ *
820
+ * The agent sees `/workspace/kb` = `views/<uid>`; personal files are flattened from
821
+ * `actual/personal/<uid>/...`, and a department view may carry the organization chain.
822
+ * Extraction and indexing must open the actual file, not the view alias, or MinerU gets
823
+ * `no such document`.
824
+ */
825
+ export declare function actualRelPathForView(ctx: Context, config: Config, relPath: string, caller?: KnowledgeCaller): Promise<string>;
826
+ export declare function extractBeside(config: Config, relPath: string, mineruUrl?: string, readSharedUrl?: () => Promise<string | undefined>, ctx?: Context): Promise<{
693
827
  markdown: string;
694
828
  via?: string;
695
829
  reason?: string;
830
+ blocks?: MineruBlock[];
696
831
  } | undefined>;
697
832
  /**
698
833
  * Translate {@link extractBeside}'s answer into a queue terminal state.
@@ -719,13 +854,71 @@ export declare function extractionOutcomeOf(outcome: {
719
854
  via?: string;
720
855
  reason?: string;
721
856
  } | undefined): ExtractionOutcome;
857
+ /**
858
+ * Where the MinerU address this deployment uses came from.
859
+ *
860
+ * The settings page says which of the three applies, so a reader never mistakes a shared
861
+ * value for their own: the caption under the field is the only thing distinguishing "you
862
+ * typed this" from "your administrator set this" from "this deployment derives it".
863
+ */
864
+ export type MineruUrlSource = 'own' | 'shared' | 'derived';
865
+ /** The effective MinerU address and where it came from. */
866
+ export interface MineruUrlResolution {
867
+ /** The address to call, or undefined when nothing is configured. */
868
+ readonly url: string | undefined;
869
+ /** Which input produced {@link url}. */
870
+ readonly source: MineruUrlSource | undefined;
871
+ }
872
+ /**
873
+ * Resolve MinerU's base URL for this deployment, in the documented precedence order.
874
+ *
875
+ * Three inputs, and the order is the whole point:
876
+ *
877
+ * 1. **The caller's own stored address.** It is a deliberate choice, so nothing overrides it.
878
+ * 2. **The shared address the 「文档识别」 plugin's administrator configured.** One value for
879
+ * the whole deployment; the reason a member never has to know MinerU exists.
880
+ * 3. **The address this deployment derives from its configured port.** Only ever
881
+ * `127.0.0.1:<port>`, which is why it is last: it can name nothing but this machine.
882
+ *
883
+ * The shared value is READ, never written. This plugin has no business persisting another
884
+ * plugin's setting, and a copy written back into `.kb-settings.json` would become a second
885
+ * source of truth that silently stops following the administrator's later change.
886
+ *
887
+ * @param config - resolved plugin config.
888
+ * @param sharedUrl - the deployment's shared address, when the caller has none of their own.
889
+ * @returns the effective address and its origin.
890
+ */
891
+ export declare function resolveMineruUrl(config: Config, sharedUrl?: string): MineruUrlResolution;
722
892
  /**
723
893
  * MinerU's base URL for this deployment, or undefined when it is not configured.
724
894
  *
895
+ * The URL-only view of {@link resolveMineruUrl}, kept because the extractor only needs the
896
+ * address and threading a source through it would make every caller unpack a field it does
897
+ * not read.
898
+ *
725
899
  * @param config - resolved plugin config.
726
- * @returns `http://127.0.0.1:<port>` when the service is expected, else undefined.
900
+ * @param sharedUrl - the deployment's shared address, when the caller has none of their own.
901
+ * @returns the address to call, else undefined.
727
902
  */
728
- export declare function mineruUrlFor(config: Config): string | undefined;
903
+ export declare function mineruUrlFor(config: Config, sharedUrl?: string): string | undefined;
904
+ /**
905
+ * Read the shared MinerU address the 「文档识别」 plugin's administrator configured.
906
+ *
907
+ * A read-only peek at another plugin's setting, and deliberately tolerant: the OCR plugin is
908
+ * optional, its backend route answers `''` when nobody has configured it, and an unreachable
909
+ * backend must not stop a document upload. Every failure therefore answers "no shared value"
910
+ * and the caller falls through to its own derivation, which is the behaviour a deployment
911
+ * without the OCR plugin has.
912
+ *
913
+ * This never writes. The value belongs to the OCR plugin's administrator; copying it into
914
+ * this plugin's settings file would make a stale duplicate of a value that is supposed to
915
+ * change once for everyone.
916
+ *
917
+ * @param ctx - host context carrying the credential store.
918
+ * @param config - resolved plugin config, for the backend origin and credential.
919
+ * @returns the shared address, or undefined when none is configured or it cannot be read.
920
+ */
921
+ export declare function readSharedMineruUrl(ctx: Context, config: Config): Promise<string | undefined>;
729
922
  /**
730
923
  * Ask DataOps whether the CALLER may manage grants.
731
924
  *
@@ -755,6 +948,30 @@ export declare function mineruUrlFor(config: Config): string | undefined;
755
948
  * @returns Whether the caller holds the grant-management permission.
756
949
  */
757
950
  export declare function canManageGrants(ctx: Context, config: Config): Promise<boolean>;
951
+ /**
952
+ * Who authors or reviews a plaza workflow.
953
+ *
954
+ * Team deployments must name the real DataOps caller: a publish record without a
955
+ * responsible author is not reviewable. A personal deployment has no backend and no
956
+ * second administrator, so its local operator is both author and reviewer.
957
+ */
958
+ export declare function resolveWorkflowActor(ctx: Context, config: Config): Promise<WorkflowActor>;
959
+ /**
960
+ * The backend permission one HTTP method needs.
961
+ *
962
+ * The named file operations are the routes the page and the file tools actually call;
963
+ * leaving a route out is deliberate for read-only status/preferences surfaces whose
964
+ * data is already scoped by the caller's grants.
965
+ */
966
+ export declare function permissionForKbRoute(method: string): string | undefined;
967
+ /**
968
+ * Whether this caller may see and use the review tab.
969
+ *
970
+ * In a team deployment this is the same grant-management authority the permission page
971
+ * uses. A personal deployment has no administrator and no grants; its owner is the
972
+ * reviewer by construction.
973
+ */
974
+ export declare function canReviewWorkflows(ctx: Context, config: Config): Promise<boolean>;
758
975
  /**
759
976
  * Create one grant in the backend permission store.
760
977
  *
@@ -807,6 +1024,10 @@ export interface StepRun {
807
1024
  export declare const KNOWLEDGE_SKILL_PROVIDER = "dsh-knowledge-base";
808
1025
  /** Name the model sees in the skill catalog. */
809
1026
  export declare const KNOWLEDGE_SKILL_NAME = "knowledge-base";
1027
+ /** Second bundled skill: the explicit, model-authored summarisation workflow. */
1028
+ export declare const KB_SUMMARIZE_SKILL_NAME = "kb-summarize";
1029
+ /** Third bundled skill: explicit document/directory vectorization. */
1030
+ export declare const KB_VECTORIZE_SKILL_NAME = "kb-vectorize";
810
1031
  /**
811
1032
  * Short description shown in the skill list.
812
1033
  *
@@ -814,7 +1035,18 @@ export declare const KNOWLEDGE_SKILL_NAME = "knowledge-base";
814
1035
  * catalog answers `list()` without reading any skill content, so the text has to
815
1036
  * be available before the file is opened.
816
1037
  */
817
- export declare const KNOWLEDGE_SKILL_DESCRIPTION = "Read and change the shared knowledge base: browse, search, create, upload, rename, move and delete documents in the \u5168\u5C40 / \u90E8\u95E8 / \u4E2A\u4EBA trees.";
1038
+ export declare const KNOWLEDGE_SKILL_DESCRIPTION: string;
1039
+ /**
1040
+ * Short description of the explicit summary skill.
1041
+ *
1042
+ * Upload and extraction never write summaries. This skill is the only documented way to
1043
+ * turn source chunks into document/section summaries and key facts, and it does so through
1044
+ * the model's own reading plus `kb_outline_save` -- never through a hidden LLM call inside
1045
+ * the plugin.
1046
+ */
1047
+ export declare const KB_SUMMARIZE_SKILL_DESCRIPTION: string;
1048
+ /** Short description of the explicit vectorization skill. */
1049
+ export declare const KB_VECTORIZE_SKILL_DESCRIPTION: string;
818
1050
  /**
819
1051
  * Where this package's SKILL.md lives, from either build layout.
820
1052
  *
@@ -825,6 +1057,28 @@ export declare const KNOWLEDGE_SKILL_DESCRIPTION = "Read and change the shared k
825
1057
  * @returns absolute path of the SKILL.md this plugin ships.
826
1058
  */
827
1059
  export declare function knowledgeSkillPath(): string;
1060
+ /**
1061
+ * Where the bundled `kb-summarize` skill lives.
1062
+ *
1063
+ * Same layout reasoning as {@link knowledgeSkillPath}: both `lib/index.js` and a source
1064
+ * run from `src/` sit one level below the package root.
1065
+ *
1066
+ * @returns absolute path of the kb-summarize SKILL.md.
1067
+ */
1068
+ export declare function kbSummarizeSkillPath(): string;
1069
+ /** Where the bundled `kb-vectorize` skill lives. */
1070
+ export declare function kbVectorizeSkillPath(): string;
1071
+ /**
1072
+ * Where this package's tutorial document lives, from either build layout.
1073
+ *
1074
+ * Resolved the same way {@link knowledgeSkillPath} is, and for the same reason: the
1075
+ * build emits `lib/index.js` while a source run executes from `src/`, and both sit one
1076
+ * level below the package root. The file is shipped by `files[]` in package.json, so a
1077
+ * published install answers the same path without a second mechanism.
1078
+ *
1079
+ * @returns absolute path of the tutorial this plugin ships.
1080
+ */
1081
+ export declare function tutorialTemplatePath(): string;
828
1082
  /**
829
1083
  * The skill provider that teaches the model how to use this knowledge base.
830
1084
  *
@@ -835,6 +1089,10 @@ export declare function knowledgeSkillPath(): string;
835
1089
  * @returns a provider the skill registry can list and read.
836
1090
  */
837
1091
  export declare const KNOWLEDGE_SKILL_RANK = 640;
1092
+ /** The summary skill is more specialised, so it sorts after the general KB skill. */
1093
+ export declare const KB_SUMMARIZE_SKILL_RANK = 650;
1094
+ /** Vectorization is another explicit, specialised action. */
1095
+ export declare const KB_VECTORIZE_SKILL_RANK = 660;
838
1096
  /** Both a human and the model may invoke this skill. */
839
1097
  export declare const KNOWLEDGE_SKILL_INVOCATION: {
840
1098
  readonly modelInvocable: true;
@@ -0,0 +1,105 @@
1
+ /**
2
+ * First-run initialisation of the authoritative knowledge tree.
3
+ *
4
+ * A deployment that has never been used has no `global/`, `department/` or
5
+ * `personal/` directory, and the reader finds a knowledge base that can hold
6
+ * nothing. The buckets were previously created only as a side effect of some write
7
+ * happening to need their parent, so a fresh share, or one whose buckets were
8
+ * removed, stayed empty with no way to recover.
9
+ *
10
+ * Two rules shape everything here:
11
+ *
12
+ * 1. **Every run re-checks the directories.** A bucket someone deleted by hand must
13
+ * come back on the next start, so "did this already run" is the wrong question
14
+ * for them; the answer is recomputed from the filesystem each time and costs three
15
+ * `mkdir` calls.
16
+ * 2. **The tutorial is written once, ever.** It is an ordinary document that the
17
+ * reader may edit, and an edit is worth more than a newer built-in version, so a
18
+ * second write is refused and the refusal is the success case.
19
+ *
20
+ * @module @sparkelf/dsh-knowledge-base
21
+ */
22
+ /** Buckets that must exist before the knowledge base can hold anything. */
23
+ export declare const KNOWLEDGE_BUCKETS: readonly ["global", "department", "personal"];
24
+ /**
25
+ * File name of the bundled tutorial, both as shipped and as published.
26
+ *
27
+ * One constant for both so a rename cannot leave the writer looking for a file the
28
+ * package no longer ships, or publishing under a name the template is not stored at.
29
+ */
30
+ export declare const TUTORIAL_FILE_NAME = "\u4E07\u76F8AI\u4F7F\u7528\u6559\u7A0B.html";
31
+ /** Where the bundled tutorial is published inside the authoritative tree. */
32
+ export declare const TUTORIAL_REL_PATH: string;
33
+ /** What one bucket did on this run. */
34
+ export type BucketOutcome = 'created' | 'exists' | 'failed';
35
+ /** What the tutorial did on this run. */
36
+ export type TutorialOutcome = 'written' | 'skipped' | 'failed';
37
+ /** The result of one initialisation attempt, per item. */
38
+ export interface InitReport {
39
+ /** One entry per bucket, in the order they are checked. */
40
+ buckets: {
41
+ bucket: string;
42
+ outcome: BucketOutcome;
43
+ }[];
44
+ /** What happened to the tutorial document. */
45
+ tutorial: TutorialOutcome;
46
+ /** Set when the run could not even reach the tree (a missing mount, a bad root). */
47
+ error?: string;
48
+ }
49
+ /** The write and read surface, injected so the rules can be tested without a NAS. */
50
+ export interface InitIo {
51
+ /**
52
+ * Whether the storage the root lives in is attached.
53
+ *
54
+ * Provisioning CREATES the root and its buckets, so it cannot require the root to
55
+ * exist; what it does require is the thing the root lives in. On a real deployment
56
+ * that is the mounted share, whose absence means provisioning would manufacture a
57
+ * directory where a mount belongs -- and the next mount would then refuse it as
58
+ * non-empty. Answering false leaves the tree untouched and the run unsuccessful, so
59
+ * the next page load retries once the share appears.
60
+ */
61
+ isStorageReady: () => Promise<boolean>;
62
+ /** Create a directory under the authoritative root; throws `exists` when taken. */
63
+ createDirectory: (relPath: string) => Promise<void>;
64
+ /** Create a document with exclusive semantics; throws `exists` when taken. */
65
+ createDocument: (relPath: string, content: string) => Promise<void>;
66
+ /** The tutorial body to publish. */
67
+ tutorialHtml: () => string;
68
+ /** Personal mode: create only the root, with no buckets or tutorial. */
69
+ ensureRoot?: () => Promise<void>;
70
+ }
71
+ /** One line of the run log; the caller decides where it goes. */
72
+ export interface InitLogLine {
73
+ /** `bucket` or `tutorial`. */
74
+ item: string;
75
+ /** The outcome word reported for this item. */
76
+ outcome: BucketOutcome | TutorialOutcome;
77
+ }
78
+ /** The initialiser, as the plugin holds it. */
79
+ export interface Initializer {
80
+ /**
81
+ * Make sure the tree is usable, at most one run in flight.
82
+ *
83
+ * Concurrent callers share one run rather than queueing: the work is idempotent, so
84
+ * a second run would only repeat the first one's `mkdir` calls and race it on the
85
+ * tutorial write. A caller arriving while a run is in flight awaits that run's
86
+ * result.
87
+ * @returns The report of the run this caller observed.
88
+ */
89
+ ensure: () => Promise<InitReport>;
90
+ /** Whether any run has completed without a fatal error, for the status route. */
91
+ hasSucceeded: () => boolean;
92
+ }
93
+ /**
94
+ * Build the initialiser.
95
+ *
96
+ * The IO is injected rather than imported so the four rules this exists to enforce --
97
+ * idempotent buckets, self-healing, write-once tutorial, single concurrent run -- can
98
+ * be exercised against a fake tree that can be inspected and mutated between runs.
99
+ * @param io - the write surface and the tutorial body.
100
+ * @param log - sink for the per-item report lines.
101
+ * @returns the initialiser the plugin stores.
102
+ */
103
+ export declare function createInitializer(io: InitIo, log: (line: InitLogLine) => void, options?: {
104
+ personal?: boolean;
105
+ }): Initializer;