@hasna/knowledge 0.2.26 → 0.2.28

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 (61) hide show
  1. package/README.md +61 -0
  2. package/bin/open-knowledge-mcp.js +85 -9
  3. package/bin/open-knowledge.js +86 -86
  4. package/dist/agent.d.ts +35 -0
  5. package/dist/artifact-store.d.ts +63 -0
  6. package/dist/auth.d.ts +35 -0
  7. package/dist/embeddings.d.ts +77 -0
  8. package/dist/index.d.ts +20 -0
  9. package/dist/index.js +5709 -0
  10. package/dist/knowledge-db.d.ts +27 -0
  11. package/dist/manifest-ingest.d.ts +35 -0
  12. package/dist/outbox-consume.d.ts +25 -0
  13. package/dist/provenance.d.ts +50 -0
  14. package/dist/providers.d.ts +89 -0
  15. package/dist/reindex.d.ts +37 -0
  16. package/dist/remote-client.d.ts +108 -0
  17. package/dist/retrieval.d.ts +71 -0
  18. package/dist/safety.d.ts +70 -0
  19. package/dist/sdk.d.ts +72 -0
  20. package/dist/search.d.ts +65 -0
  21. package/dist/service.d.ts +117 -0
  22. package/dist/source-ingest.d.ts +18 -0
  23. package/dist/source-ref.d.ts +30 -0
  24. package/dist/source-resolver.d.ts +92 -0
  25. package/dist/storage-contract.d.ts +106 -0
  26. package/dist/web-search.d.ts +40 -0
  27. package/dist/wiki-compiler.d.ts +67 -0
  28. package/dist/wiki-layout.d.ts +23 -0
  29. package/dist/workspace.d.ts +111 -0
  30. package/docs/architecture/ai-native-knowledge-base.md +24 -0
  31. package/docs/architecture/hosted-wrapper-responsibilities.md +8 -0
  32. package/docs/canonical-secrets-bootstrap-2026-06-08.md +127 -0
  33. package/package.json +15 -7
  34. package/src/agent.ts +0 -367
  35. package/src/artifact-store.ts +0 -184
  36. package/src/auth.ts +0 -123
  37. package/src/cli.ts +0 -1181
  38. package/src/embeddings.ts +0 -516
  39. package/src/knowledge-db.ts +0 -354
  40. package/src/manifest-ingest.ts +0 -515
  41. package/src/mcp-http.js +0 -110
  42. package/src/mcp.js +0 -1503
  43. package/src/outbox-consume.ts +0 -463
  44. package/src/provenance.ts +0 -93
  45. package/src/providers.ts +0 -308
  46. package/src/reindex.ts +0 -260
  47. package/src/remote-client.ts +0 -268
  48. package/src/retrieval.ts +0 -326
  49. package/src/safety.ts +0 -265
  50. package/src/schema.js +0 -25
  51. package/src/search.ts +0 -510
  52. package/src/service.ts +0 -432
  53. package/src/source-ingest.ts +0 -268
  54. package/src/source-ref.ts +0 -104
  55. package/src/source-resolver.ts +0 -436
  56. package/src/storage-contract.ts +0 -293
  57. package/src/store.ts +0 -113
  58. package/src/web-search.ts +0 -330
  59. package/src/wiki-compiler.ts +0 -711
  60. package/src/wiki-layout.ts +0 -251
  61. package/src/workspace.ts +0 -213
@@ -1,184 +0,0 @@
1
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
2
- import { dirname, join, relative, sep } from 'node:path';
3
- import type { KnowledgeConfig, KnowledgeWorkspace } from './workspace';
4
-
5
- interface S3ClientLike {
6
- send(command: unknown): Promise<any>;
7
- }
8
-
9
- export interface ArtifactWrite {
10
- key: string;
11
- body: string | Uint8Array;
12
- content_type?: string;
13
- metadata?: Record<string, string>;
14
- }
15
-
16
- export interface ArtifactStore {
17
- readonly type: 'local' | 's3';
18
- readonly canRead: boolean;
19
- readonly canWrite: boolean;
20
- put(entry: ArtifactWrite): Promise<{ key: string; uri: string }>;
21
- getText(key: string): Promise<string>;
22
- exists(key: string): Promise<boolean>;
23
- }
24
-
25
- export function normalizeArtifactKey(key: string): string {
26
- const raw = key.replace(/\\/g, '/').trim();
27
- if (!raw || raw.startsWith('/')) {
28
- throw new Error(`Invalid artifact key: ${key}`);
29
- }
30
- const segments = raw.split('/').filter(Boolean);
31
- if (segments.length === 0 || segments.some((segment) => segment === '.' || segment === '..')) {
32
- throw new Error(`Invalid artifact key: ${key}`);
33
- }
34
- return segments.join('/');
35
- }
36
-
37
- function assertInside(root: string, target: string): void {
38
- const rel = relative(root, target);
39
- if (rel.startsWith('..') || rel === '..' || rel.startsWith(`..${sep}`)) {
40
- throw new Error(`Artifact path escapes root: ${target}`);
41
- }
42
- }
43
-
44
- export class LocalArtifactStore implements ArtifactStore {
45
- readonly type = 'local' as const;
46
- readonly canRead = true;
47
- readonly canWrite = true;
48
-
49
- constructor(private readonly root: string) {
50
- mkdirSync(root, { recursive: true });
51
- }
52
-
53
- async put(entry: ArtifactWrite): Promise<{ key: string; uri: string }> {
54
- const key = normalizeArtifactKey(entry.key);
55
- const path = join(this.root, key);
56
- assertInside(this.root, path);
57
- mkdirSync(dirname(path), { recursive: true });
58
- writeFileSync(path, entry.body);
59
- return { key, uri: `file://${path}` };
60
- }
61
-
62
- async getText(key: string): Promise<string> {
63
- const normalizedKey = normalizeArtifactKey(key);
64
- const path = join(this.root, normalizedKey);
65
- assertInside(this.root, path);
66
- return readFileSync(path, 'utf8');
67
- }
68
-
69
- async exists(key: string): Promise<boolean> {
70
- const normalizedKey = normalizeArtifactKey(key);
71
- const path = join(this.root, normalizedKey);
72
- assertInside(this.root, path);
73
- return existsSync(path);
74
- }
75
- }
76
-
77
- export interface S3ArtifactStoreOptions {
78
- bucket: string;
79
- prefix?: string;
80
- region?: string;
81
- profile?: string;
82
- max_attempts?: number;
83
- server_side_encryption?: 'AES256' | 'aws:kms';
84
- kms_key_id?: string;
85
- client?: S3ClientLike;
86
- }
87
-
88
- export class S3ArtifactStore implements ArtifactStore {
89
- readonly type = 's3' as const;
90
- readonly canRead = true;
91
- readonly canWrite = true;
92
- private client?: S3ClientLike;
93
-
94
- constructor(private readonly options: S3ArtifactStoreOptions) {
95
- this.client = options.client;
96
- }
97
-
98
- private async getClient(): Promise<S3ClientLike> {
99
- if (this.client) return this.client;
100
- const [{ S3Client }, { fromIni }] = await Promise.all([
101
- import('@aws-sdk/client-s3'),
102
- import('@aws-sdk/credential-providers'),
103
- ]);
104
- this.client = new S3Client({
105
- region: this.options.region,
106
- credentials: this.options.profile ? fromIni({ profile: this.options.profile }) : undefined,
107
- maxAttempts: this.options.max_attempts,
108
- });
109
- return this.client;
110
- }
111
-
112
- private objectKey(key: string): string {
113
- const normalizedKey = normalizeArtifactKey(key);
114
- const prefix = this.options.prefix ? normalizeArtifactKey(this.options.prefix) : '';
115
- return prefix ? `${prefix}/${normalizedKey}` : normalizedKey;
116
- }
117
-
118
- async put(entry: ArtifactWrite): Promise<{ key: string; uri: string }> {
119
- const [{ PutObjectCommand }, client] = await Promise.all([
120
- import('@aws-sdk/client-s3'),
121
- this.getClient(),
122
- ]);
123
- const key = this.objectKey(entry.key);
124
- await client.send(new PutObjectCommand({
125
- Bucket: this.options.bucket,
126
- Key: key,
127
- Body: entry.body,
128
- ContentType: entry.content_type,
129
- Metadata: entry.metadata,
130
- ServerSideEncryption: this.options.server_side_encryption,
131
- SSEKMSKeyId: this.options.kms_key_id,
132
- }));
133
- return { key, uri: `s3://${this.options.bucket}/${key}` };
134
- }
135
-
136
- async getText(key: string): Promise<string> {
137
- const [{ GetObjectCommand }, client] = await Promise.all([
138
- import('@aws-sdk/client-s3'),
139
- this.getClient(),
140
- ]);
141
- const objectKey = this.objectKey(key);
142
- const response = await client.send(new GetObjectCommand({
143
- Bucket: this.options.bucket,
144
- Key: objectKey,
145
- }));
146
- if (!response.Body) return '';
147
- return await response.Body.transformToString();
148
- }
149
-
150
- async exists(key: string): Promise<boolean> {
151
- const [{ HeadObjectCommand }, client] = await Promise.all([
152
- import('@aws-sdk/client-s3'),
153
- this.getClient(),
154
- ]);
155
- const objectKey = this.objectKey(key);
156
- try {
157
- await client.send(new HeadObjectCommand({
158
- Bucket: this.options.bucket,
159
- Key: objectKey,
160
- }));
161
- return true;
162
- } catch (error) {
163
- const name = error instanceof Error ? error.name : '';
164
- if (name === 'NotFound' || name === 'NoSuchKey' || name === 'NotFoundError') return false;
165
- throw error;
166
- }
167
- }
168
- }
169
-
170
- export function createArtifactStore(config: KnowledgeConfig, workspace: KnowledgeWorkspace): ArtifactStore {
171
- if (config.storage.type === 's3') {
172
- if (!config.storage.s3?.bucket) throw new Error('S3 artifact storage requires storage.s3.bucket');
173
- return new S3ArtifactStore({
174
- bucket: config.storage.s3.bucket,
175
- prefix: config.storage.s3.prefix,
176
- region: config.storage.s3.region,
177
- profile: config.storage.s3.profile,
178
- max_attempts: config.storage.s3.max_attempts,
179
- server_side_encryption: config.storage.s3.server_side_encryption,
180
- kms_key_id: config.storage.s3.kms_key_id,
181
- });
182
- }
183
- return new LocalArtifactStore(workspace.artifactsDir);
184
- }
package/src/auth.ts DELETED
@@ -1,123 +0,0 @@
1
- import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';
2
- import { homedir } from 'node:os';
3
- import { dirname, join } from 'node:path';
4
- import type { KnowledgeConfig } from './workspace';
5
-
6
- export interface KnowledgeAuthConfig {
7
- api_key: string;
8
- email?: string;
9
- org_id?: string;
10
- org_slug?: string;
11
- user_id?: string;
12
- api_url?: string;
13
- created_at: string;
14
- }
15
-
16
- export interface KnowledgeAuthStatus {
17
- authenticated: boolean;
18
- source: 'env' | 'file' | 'none';
19
- api_url: string;
20
- auth_path: string;
21
- email: string | null;
22
- org_id: string | null;
23
- org_slug: string | null;
24
- user_id: string | null;
25
- api_key_present: boolean;
26
- }
27
-
28
- export const DEFAULT_KNOWLEDGE_API_URL = 'https://knowledge.hasna.xyz';
29
-
30
- export function normalizeKnowledgeApiOrigin(apiUrl: string): string {
31
- const url = new URL(apiUrl);
32
- if (url.protocol !== 'http:' && url.protocol !== 'https:') {
33
- throw new Error('Knowledge API URL must use http or https.');
34
- }
35
- const pathname = url.pathname.replace(/\/+$/, '');
36
- if (pathname === '/api' || pathname === '/api/v1') {
37
- url.pathname = '/';
38
- } else if (pathname.endsWith('/api/v1')) {
39
- url.pathname = pathname.slice(0, -'/api/v1'.length) || '/';
40
- } else if (pathname.endsWith('/api')) {
41
- url.pathname = pathname.slice(0, -'/api'.length) || '/';
42
- }
43
- return url.toString().replace(/\/+$/, '');
44
- }
45
-
46
- export function knowledgeAuthPath(env: Record<string, string | undefined> = process.env): string {
47
- if (env.HASNA_KNOWLEDGE_AUTH_PATH) return env.HASNA_KNOWLEDGE_AUTH_PATH;
48
- const root = env.HASNA_KNOWLEDGE_AUTH_DIR ?? join(homedir(), '.hasna', 'knowledge');
49
- return join(root, 'auth.json');
50
- }
51
-
52
- export function resolveKnowledgeApiUrl(
53
- config?: KnowledgeConfig,
54
- env: Record<string, string | undefined> = process.env,
55
- ): string {
56
- return normalizeKnowledgeApiOrigin(env.KNOWLEDGE_API_URL ?? config?.hosted?.api_url ?? DEFAULT_KNOWLEDGE_API_URL);
57
- }
58
-
59
- export function getKnowledgeAuth(env: Record<string, string | undefined> = process.env): KnowledgeAuthConfig | null {
60
- try {
61
- const path = knowledgeAuthPath(env);
62
- if (!existsSync(path)) return null;
63
- const parsed = JSON.parse(readFileSync(path, 'utf8')) as KnowledgeAuthConfig;
64
- return typeof parsed.api_key === 'string' && parsed.api_key.length > 0 ? parsed : null;
65
- } catch {
66
- return null;
67
- }
68
- }
69
-
70
- export function saveKnowledgeAuth(
71
- auth: Omit<KnowledgeAuthConfig, 'created_at'> & { created_at?: string },
72
- env: Record<string, string | undefined> = process.env,
73
- ): KnowledgeAuthConfig {
74
- const path = knowledgeAuthPath(env);
75
- const stored: KnowledgeAuthConfig = {
76
- ...auth,
77
- api_url: auth.api_url ? normalizeKnowledgeApiOrigin(auth.api_url) : undefined,
78
- created_at: auth.created_at ?? new Date().toISOString(),
79
- };
80
- mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
81
- writeFileSync(path, `${JSON.stringify(stored, null, 2)}\n`, { mode: 0o600 });
82
- return stored;
83
- }
84
-
85
- export function clearKnowledgeAuth(env: Record<string, string | undefined> = process.env): boolean {
86
- try {
87
- unlinkSync(knowledgeAuthPath(env));
88
- return true;
89
- } catch {
90
- return false;
91
- }
92
- }
93
-
94
- export function getKnowledgeApiKey(env: Record<string, string | undefined> = process.env): { apiKey: string | null; source: KnowledgeAuthStatus['source'] } {
95
- if (env.KNOWLEDGE_API_KEY) return { apiKey: env.KNOWLEDGE_API_KEY, source: 'env' };
96
- if (env.HASNA_KNOWLEDGE_API_KEY) return { apiKey: env.HASNA_KNOWLEDGE_API_KEY, source: 'env' };
97
- const auth = getKnowledgeAuth(env);
98
- return auth?.api_key ? { apiKey: auth.api_key, source: 'file' } : { apiKey: null, source: 'none' };
99
- }
100
-
101
- export function knowledgeAuthStatus(
102
- config?: KnowledgeConfig,
103
- env: Record<string, string | undefined> = process.env,
104
- ): KnowledgeAuthStatus {
105
- const auth = getKnowledgeAuth(env);
106
- const key = getKnowledgeApiKey(env);
107
- const apiUrl = env.KNOWLEDGE_API_URL
108
- ? resolveKnowledgeApiUrl(config, env)
109
- : auth?.api_url
110
- ? normalizeKnowledgeApiOrigin(auth.api_url)
111
- : resolveKnowledgeApiUrl(config, env);
112
- return {
113
- authenticated: Boolean(key.apiKey),
114
- source: key.source,
115
- api_url: apiUrl,
116
- auth_path: knowledgeAuthPath(env),
117
- email: key.source === 'file' ? auth?.email ?? null : null,
118
- org_id: key.source === 'file' ? auth?.org_id ?? null : null,
119
- org_slug: key.source === 'file' ? auth?.org_slug ?? null : null,
120
- user_id: key.source === 'file' ? auth?.user_id ?? null : null,
121
- api_key_present: Boolean(key.apiKey),
122
- };
123
- }