@customize-agent/knowledge 1.0.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/index-state-store.d.ts +2 -0
- package/dist/core/index-state-store.js +51 -12
- package/dist/core/knowledge-base-manager.d.ts +1 -0
- package/dist/core/knowledge-base-manager.js +26 -7
- package/dist/dedup/dedup-engine.d.ts +3 -0
- package/dist/dedup/dedup-engine.js +12 -2
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/server/dashboard-styles.d.ts +1 -1
- package/dist/server/dashboard-styles.js +1 -1
- package/package.json +1 -1
|
@@ -29,6 +29,7 @@ export interface MinHashRecord {
|
|
|
29
29
|
filePath: string;
|
|
30
30
|
signature: number[];
|
|
31
31
|
shingleCount: number;
|
|
32
|
+
buckets: string[];
|
|
32
33
|
createdAt: number;
|
|
33
34
|
}
|
|
34
35
|
export interface FileRelationship {
|
|
@@ -64,6 +65,7 @@ export declare class IndexStateStore {
|
|
|
64
65
|
upsertFileHash(record: Omit<FileHashRecord, 'createdAt' | 'updatedAt'>): void;
|
|
65
66
|
upsertMinHash(record: Omit<MinHashRecord, 'createdAt'>): void;
|
|
66
67
|
listMinHashes(excludePath?: string): MinHashRecord[];
|
|
68
|
+
listMinHashesByBuckets(buckets: string[], excludePath?: string): MinHashRecord[];
|
|
67
69
|
addRelationship(relationship: Omit<FileRelationship, 'id' | 'createdAt'>): void;
|
|
68
70
|
listRelationships(filePath?: string): FileRelationship[];
|
|
69
71
|
setTags(relativePath: string, tags: string[]): void;
|
|
@@ -50,7 +50,7 @@ export class IndexStateStore {
|
|
|
50
50
|
listRecords() {
|
|
51
51
|
const rows = this.db.prepare(`
|
|
52
52
|
SELECT * FROM kb_index_state
|
|
53
|
-
WHERE status
|
|
53
|
+
WHERE status != 'deleted'
|
|
54
54
|
ORDER BY category, relative_path
|
|
55
55
|
`).all();
|
|
56
56
|
return rows.map(row => this.rowToRecord(row));
|
|
@@ -140,14 +140,22 @@ export class IndexStateStore {
|
|
|
140
140
|
`).run(record.contentHash, record.filePath, record.fileSize, record.category, record.normalizedHash ?? null, now, now);
|
|
141
141
|
}
|
|
142
142
|
upsertMinHash(record) {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
143
|
+
const now = Date.now();
|
|
144
|
+
const tx = this.db.transaction(() => {
|
|
145
|
+
this.db.prepare(`
|
|
146
|
+
INSERT INTO kb_minhash (file_path, signature, shingle_count, created_at)
|
|
147
|
+
VALUES (?, ?, ?, ?)
|
|
148
|
+
ON CONFLICT(file_path) DO UPDATE SET
|
|
149
|
+
signature = excluded.signature,
|
|
150
|
+
shingle_count = excluded.shingle_count,
|
|
151
|
+
created_at = excluded.created_at
|
|
152
|
+
`).run(record.filePath, Buffer.from(JSON.stringify(record.signature), 'utf8'), record.shingleCount, now);
|
|
153
|
+
this.db.prepare('DELETE FROM kb_lsh_buckets WHERE file_path = ?').run(record.filePath);
|
|
154
|
+
const insertBucket = this.db.prepare('INSERT OR IGNORE INTO kb_lsh_buckets (bucket_key, file_path, created_at) VALUES (?, ?, ?)');
|
|
155
|
+
for (const bucket of record.buckets)
|
|
156
|
+
insertBucket.run(bucket, record.filePath, now);
|
|
157
|
+
});
|
|
158
|
+
tx();
|
|
151
159
|
}
|
|
152
160
|
listMinHashes(excludePath) {
|
|
153
161
|
const rows = excludePath
|
|
@@ -155,6 +163,24 @@ export class IndexStateStore {
|
|
|
155
163
|
: this.db.prepare('SELECT * FROM kb_minhash').all();
|
|
156
164
|
return rows.map(row => this.rowToMinHash(row));
|
|
157
165
|
}
|
|
166
|
+
listMinHashesByBuckets(buckets, excludePath) {
|
|
167
|
+
if (buckets.length === 0)
|
|
168
|
+
return [];
|
|
169
|
+
const placeholders = buckets.map(() => '?').join(',');
|
|
170
|
+
const params = [...buckets];
|
|
171
|
+
let sql = `
|
|
172
|
+
SELECT DISTINCT m.*
|
|
173
|
+
FROM kb_minhash m
|
|
174
|
+
INNER JOIN kb_lsh_buckets b ON b.file_path = m.file_path
|
|
175
|
+
WHERE b.bucket_key IN (${placeholders})
|
|
176
|
+
`;
|
|
177
|
+
if (excludePath) {
|
|
178
|
+
sql += ' AND m.file_path != ?';
|
|
179
|
+
params.push(excludePath);
|
|
180
|
+
}
|
|
181
|
+
const rows = this.db.prepare(sql).all(...params);
|
|
182
|
+
return rows.map(row => this.rowToMinHash(row));
|
|
183
|
+
}
|
|
158
184
|
addRelationship(relationship) {
|
|
159
185
|
this.db.prepare(`
|
|
160
186
|
INSERT INTO kb_relationships (
|
|
@@ -209,6 +235,7 @@ export class IndexStateStore {
|
|
|
209
235
|
this.db.prepare('DELETE FROM kb_index_state WHERE relative_path = ?').run(relativePath);
|
|
210
236
|
this.db.prepare('DELETE FROM kb_file_hashes WHERE file_path = ?').run(relativePath);
|
|
211
237
|
this.db.prepare('DELETE FROM kb_minhash WHERE file_path = ?').run(relativePath);
|
|
238
|
+
this.db.prepare('DELETE FROM kb_lsh_buckets WHERE file_path = ?').run(relativePath);
|
|
212
239
|
this.db.prepare('DELETE FROM kb_tags WHERE file_path = ?').run(relativePath);
|
|
213
240
|
this.db.prepare('DELETE FROM kb_relationships WHERE source_file = ? OR target_file = ?').run(relativePath, relativePath);
|
|
214
241
|
}
|
|
@@ -222,11 +249,11 @@ export class IndexStateStore {
|
|
|
222
249
|
const stats = this.db.prepare(`
|
|
223
250
|
SELECT
|
|
224
251
|
COUNT(*) as file_count,
|
|
225
|
-
|
|
252
|
+
(SELECT COUNT(*) FROM kb_chunks) as chunk_count,
|
|
226
253
|
COALESCE(SUM(file_size), 0) as total_size_bytes,
|
|
227
254
|
COALESCE(MAX(indexed_at), 0) as last_indexed_at
|
|
228
255
|
FROM kb_index_state
|
|
229
|
-
WHERE status
|
|
256
|
+
WHERE status != 'deleted'
|
|
230
257
|
`).get();
|
|
231
258
|
return {
|
|
232
259
|
fileCount: Number(stats.file_count ?? 0),
|
|
@@ -301,6 +328,15 @@ export class IndexStateStore {
|
|
|
301
328
|
created_at INTEGER NOT NULL
|
|
302
329
|
);
|
|
303
330
|
|
|
331
|
+
CREATE TABLE IF NOT EXISTS kb_lsh_buckets (
|
|
332
|
+
bucket_key TEXT NOT NULL,
|
|
333
|
+
file_path TEXT NOT NULL,
|
|
334
|
+
created_at INTEGER NOT NULL,
|
|
335
|
+
PRIMARY KEY (bucket_key, file_path)
|
|
336
|
+
);
|
|
337
|
+
CREATE INDEX IF NOT EXISTS idx_lsh_bucket ON kb_lsh_buckets(bucket_key);
|
|
338
|
+
CREATE INDEX IF NOT EXISTS idx_lsh_file ON kb_lsh_buckets(file_path);
|
|
339
|
+
|
|
304
340
|
CREATE TABLE IF NOT EXISTS kb_relationships (
|
|
305
341
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
306
342
|
source_file TEXT NOT NULL,
|
|
@@ -341,10 +377,13 @@ export class IndexStateStore {
|
|
|
341
377
|
rowToMinHash(row) {
|
|
342
378
|
const raw = row.signature;
|
|
343
379
|
const json = Buffer.isBuffer(raw) ? raw.toString('utf8') : String(raw);
|
|
380
|
+
const filePath = String(row.file_path);
|
|
381
|
+
const bucketRows = this.db.prepare('SELECT bucket_key FROM kb_lsh_buckets WHERE file_path = ?').all(filePath);
|
|
344
382
|
return {
|
|
345
|
-
filePath
|
|
383
|
+
filePath,
|
|
346
384
|
signature: JSON.parse(json),
|
|
347
385
|
shingleCount: Number(row.shingle_count),
|
|
386
|
+
buckets: bucketRows.map(bucket => bucket.bucket_key),
|
|
348
387
|
createdAt: Number(row.created_at),
|
|
349
388
|
};
|
|
350
389
|
}
|
|
@@ -45,6 +45,7 @@ export declare class KnowledgeBaseManager {
|
|
|
45
45
|
listRelationships(filePath?: string): FileRelationship[];
|
|
46
46
|
listFiles(): IndexStateRecord[];
|
|
47
47
|
addFile(sourcePath: string, targetRelativePath?: string): Promise<DiffResult>;
|
|
48
|
+
getUploadRelativePath(fileName: string, targetRelativePath?: string): string;
|
|
48
49
|
uploadFile(fileName: string, content: Buffer, targetRelativePath?: string): Promise<DiffResult>;
|
|
49
50
|
listFailedFiles(): DiffResult['skippedFiles'];
|
|
50
51
|
removeFile(relativePath: string): Promise<void>;
|
|
@@ -81,10 +81,28 @@ export class KnowledgeBaseManager {
|
|
|
81
81
|
for (const file of [...diff.newFiles, ...diff.modifiedFiles]) {
|
|
82
82
|
const hash = tracker.hashFile(file.absolutePath);
|
|
83
83
|
const duplicate = this.store.findExactDuplicate(hash, file.relativePath);
|
|
84
|
+
const collectionName = this.scope === 'global'
|
|
85
|
+
? this.collections.getCollectionName('global', file.category)
|
|
86
|
+
: this.collections.getCollectionName('project', file.category, this.projectId);
|
|
84
87
|
const extraction = await this.extractor.extract(file);
|
|
85
88
|
if (!this.hasUsableContent(extraction.text, extraction.metadata)) {
|
|
86
|
-
|
|
87
|
-
|
|
89
|
+
const reason = extraction.warnings[0] ?? '未解析出可用于模型的正文内容,已跳过向量化';
|
|
90
|
+
diff.skippedFiles.push({ file, reason });
|
|
91
|
+
this.store.upsertRecord({
|
|
92
|
+
relativePath: file.relativePath,
|
|
93
|
+
category: file.category,
|
|
94
|
+
format: file.format,
|
|
95
|
+
contentHash: hash,
|
|
96
|
+
fileSize: file.fileSize,
|
|
97
|
+
mtime: file.mtime,
|
|
98
|
+
chunkCount: 0,
|
|
99
|
+
collectionName,
|
|
100
|
+
indexedAt: now,
|
|
101
|
+
lastVerifiedAt: now,
|
|
102
|
+
status: 'error',
|
|
103
|
+
errorMessage: reason,
|
|
104
|
+
metadataJson: JSON.stringify({ mimeType: file.mimeType, warnings: extraction.warnings }),
|
|
105
|
+
});
|
|
88
106
|
continue;
|
|
89
107
|
}
|
|
90
108
|
const normalizedHash = this.dedup.normalizedHash(extraction.text);
|
|
@@ -92,9 +110,6 @@ export class KnowledgeBaseManager {
|
|
|
92
110
|
? this.store.findNormalizedDuplicate(normalizedHash, file.relativePath)
|
|
93
111
|
: undefined;
|
|
94
112
|
const chunks = duplicate ? [] : this.chunker.chunk(extraction.text, file, extraction.metadata);
|
|
95
|
-
const collectionName = this.scope === 'global'
|
|
96
|
-
? this.collections.getCollectionName('global', file.category)
|
|
97
|
-
: this.collections.getCollectionName('project', file.category, this.projectId);
|
|
98
113
|
this.store.upsertFileHash({
|
|
99
114
|
contentHash: hash,
|
|
100
115
|
filePath: file.relativePath,
|
|
@@ -125,7 +140,7 @@ export class KnowledgeBaseManager {
|
|
|
125
140
|
if (!duplicate && extraction.text.length > 1000) {
|
|
126
141
|
const minHash = this.dedup.computeMinHash(extraction.text);
|
|
127
142
|
if (minHash) {
|
|
128
|
-
for (const existing of this.store.
|
|
143
|
+
for (const existing of this.store.listMinHashesByBuckets(minHash.buckets, file.relativePath)) {
|
|
129
144
|
const similarity = this.dedup.estimateSimilarity(minHash.signature, existing.signature);
|
|
130
145
|
const relationshipType = this.dedup.relationshipForSimilarity(similarity);
|
|
131
146
|
if (relationshipType) {
|
|
@@ -143,6 +158,7 @@ export class KnowledgeBaseManager {
|
|
|
143
158
|
filePath: file.relativePath,
|
|
144
159
|
signature: minHash.signature,
|
|
145
160
|
shingleCount: minHash.shingleCount,
|
|
161
|
+
buckets: minHash.buckets,
|
|
146
162
|
});
|
|
147
163
|
}
|
|
148
164
|
}
|
|
@@ -212,9 +228,12 @@ export class KnowledgeBaseManager {
|
|
|
212
228
|
fs.copyFileSync(resolvedSource, targetPath);
|
|
213
229
|
return this.incrementalIndex();
|
|
214
230
|
}
|
|
231
|
+
getUploadRelativePath(fileName, targetRelativePath) {
|
|
232
|
+
return targetRelativePath ?? this.defaultUploadRelativePath(fileName);
|
|
233
|
+
}
|
|
215
234
|
async uploadFile(fileName, content, targetRelativePath) {
|
|
216
235
|
this.initialize();
|
|
217
|
-
const relativePath =
|
|
236
|
+
const relativePath = this.getUploadRelativePath(fileName, targetRelativePath);
|
|
218
237
|
const targetPath = this.resolveKbRelativePath(relativePath);
|
|
219
238
|
fs.mkdirSync(path.dirname(targetPath), { recursive: true });
|
|
220
239
|
fs.writeFileSync(targetPath, content);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export interface MinHashSignature {
|
|
2
2
|
signature: number[];
|
|
3
3
|
shingleCount: number;
|
|
4
|
+
buckets: string[];
|
|
4
5
|
}
|
|
5
6
|
export interface SimilarityMatch {
|
|
6
7
|
filePath: string;
|
|
@@ -8,10 +9,12 @@ export interface SimilarityMatch {
|
|
|
8
9
|
}
|
|
9
10
|
export declare class DedupEngine {
|
|
10
11
|
private readonly hashCount;
|
|
12
|
+
private readonly bandSize;
|
|
11
13
|
normalizeText(text: string): string;
|
|
12
14
|
normalizedHash(text: string): string | undefined;
|
|
13
15
|
relationshipForFormats(sourceFormat: string, targetFormat: string): 'format_variant' | 'translation';
|
|
14
16
|
computeMinHash(text: string, shingleSize?: number): MinHashSignature | undefined;
|
|
17
|
+
computeLshBuckets(signature: number[]): string[];
|
|
15
18
|
estimateSimilarity(a: number[], b: number[]): number;
|
|
16
19
|
relationshipForSimilarity(similarity: number): 'near_duplicate' | 'revision' | undefined;
|
|
17
20
|
private hashToUint32;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as crypto from 'node:crypto';
|
|
2
2
|
export class DedupEngine {
|
|
3
|
-
hashCount =
|
|
3
|
+
hashCount = 192;
|
|
4
|
+
bandSize = 6;
|
|
4
5
|
normalizeText(text) {
|
|
5
6
|
return text
|
|
6
7
|
.toLowerCase()
|
|
@@ -42,7 +43,16 @@ export class DedupEngine {
|
|
|
42
43
|
signature[seed] = value;
|
|
43
44
|
}
|
|
44
45
|
}
|
|
45
|
-
return { signature, shingleCount: shingles.size };
|
|
46
|
+
return { signature, shingleCount: shingles.size, buckets: this.computeLshBuckets(signature) };
|
|
47
|
+
}
|
|
48
|
+
computeLshBuckets(signature) {
|
|
49
|
+
const buckets = [];
|
|
50
|
+
for (let i = 0; i < signature.length; i += this.bandSize) {
|
|
51
|
+
const band = signature.slice(i, i + this.bandSize);
|
|
52
|
+
if (band.length === this.bandSize)
|
|
53
|
+
buckets.push(`${i / this.bandSize}:${this.hashToUint32(band.join('|'))}`);
|
|
54
|
+
}
|
|
55
|
+
return buckets;
|
|
46
56
|
}
|
|
47
57
|
estimateSimilarity(a, b) {
|
|
48
58
|
const length = Math.min(a.length, b.length);
|
package/dist/index.d.ts
CHANGED
|
@@ -20,4 +20,3 @@ export { CollectionManager, globalCollectionName, projectCollectionName } from '
|
|
|
20
20
|
export type { CollectionClient, VectorCollectionInfo, VectorDocument, VectorSearchQuery, VectorSearchResult, VectorStoreInterface } from './vector/types.js';
|
|
21
21
|
export { VectorIndexer, type VectorIndexResult } from './vector/vector-indexer.js';
|
|
22
22
|
export { FederationSearch, type FederatedQuery, type FederatedResult, type FederatedSearchItem, type SearchFilters, type SearchScope } from './search/federation-search.js';
|
|
23
|
-
export { startKnowledgeDashboard, type DashboardServerHandle, type DashboardServerOptions } from './server/dashboard-server.js';
|
package/dist/index.js
CHANGED
|
@@ -19,4 +19,3 @@ export { ChromaHttpClient, ChromaVectorStore } from './vector/chroma-store.js';
|
|
|
19
19
|
export { CollectionManager, globalCollectionName, projectCollectionName } from './vector/collection-manager.js';
|
|
20
20
|
export { VectorIndexer } from './vector/vector-indexer.js';
|
|
21
21
|
export { FederationSearch } from './search/federation-search.js';
|
|
22
|
-
export { startKnowledgeDashboard } from './server/dashboard-server.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const dashboardStyles = "\n:root {\n color-scheme: light;\n --bg:#f5f5f7;\n --bg-glass:rgba(255,255,255,.72);\n --panel:rgba(255,255,255,.86);\n --panel-solid:#ffffff;\n --line:rgba(60,60,67,.16);\n --line-strong:rgba(60,60,67,.26);\n --text:#1d1d1f;\n --muted:#6e6e73;\n --accent:#007aff;\n --accent-2:#5856d6;\n --danger:#ff3b30;\n --ok:#34c759;\n --warn:#ff9500;\n --shadow:0 18px 45px rgba(0,0,0,.08);\n --shadow-soft:0 8px 24px rgba(0,0,0,.06);\n}\n* { box-sizing: border-box; }\nhtml { background:var(--bg); }\nbody {\n margin:0; min-height:100vh; font-family: -apple-system, BlinkMacSystemFont, \"SF Pro Display\", \"SF Pro Text\", \"Segoe UI\", sans-serif;\n background:\n radial-gradient(circle at 15% 0%, rgba(0,122,255,.12), transparent 28rem),\n radial-gradient(circle at 85% 8%, rgba(88,86,214,.10), transparent 26rem),\n linear-gradient(180deg, #fbfbfd 0%, var(--bg) 100%);\n color:var(--text);\n}\nheader {\n position: sticky; top:0; z-index:10; backdrop-filter: saturate(180%) blur(22px); -webkit-backdrop-filter: saturate(180%) blur(22px);\n padding:20px max(32px, calc((100vw - 1480px) / 2 + 32px)); border-bottom:1px solid var(--line); display:flex; align-items:center; justify-content:space-between; gap:18px;\n background:var(--bg-glass);\n}\nmain { padding:28px 32px 40px; max-width:1480px; margin:0 auto; }\nmain, aside, main > div { min-width:0; }\n.page { display:none; }\n.page.active { display:block; }\n.topbar { flex-wrap:nowrap; justify-content:flex-start; overflow-x:auto; padding-bottom:2px; scrollbar-width:none; }\n.topbar::-webkit-scrollbar { display:none; }\n.topbar > * { flex:0 0 auto; }\n.tab { background:rgba(255,255,255,.72); border-radius:999px; padding:9px 15px; color:var(--muted); }\n.tab.active { background:#1d1d1f; color:white; border-color:#1d1d1f; }\nsection {\n position:relative; overflow:visible;\n background:var(--panel); border:1px solid rgba(255,255,255,.7); border-radius:26px; padding:20px; box-shadow:var(--shadow-soft);\n backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);\n}\nsection:has(.custom-select.open), section.select-host-open { z-index:10000; }\nsection:hover { box-shadow:var(--shadow); transform:translateY(-1px); transition:.2s ease; }\nh1 { font-size:24px; margin:0; letter-spacing:-.02em; font-weight:700; }\nh2 { font-size:12px; margin:0 0 14px; color:var(--muted); text-transform:uppercase; letter-spacing:.12em; font-weight:700; }\nh3 { font-size:15px; margin:14px 0 8px; }\n.subtitle { margin-top:6px; color:var(--muted); font-size:14px; }\nbutton, input, select {\n min-width:0; background:rgba(255,255,255,.88); color:var(--text); border:1px solid var(--line); border-radius:14px; padding:10px 13px; outline:none;\n font: inherit; box-shadow: inset 0 0 0 1px rgba(255,255,255,.25);\n}\nselect {\n min-width:132px; appearance:none; -webkit-appearance:none; padding-right:34px;\n background-image:linear-gradient(45deg, transparent 50%, #6e6e73 50%), linear-gradient(135deg, #6e6e73 50%, transparent 50%);\n background-position:calc(100% - 18px) 50%, calc(100% - 12px) 50%; background-size:6px 6px, 6px 6px; background-repeat:no-repeat;\n}\nbutton { cursor:pointer; white-space:nowrap; transition:.16s ease; font-weight:600; }\nbutton:hover { border-color:rgba(0,122,255,.35); transform:translateY(-1px); box-shadow:0 8px 18px rgba(0,122,255,.12); }\nbutton.primary { background:linear-gradient(180deg, #0a84ff, #007aff); border-color:transparent; color:white; box-shadow:0 10px 22px rgba(0,122,255,.24); }\ninput { width:100%; }\ninput::placeholder { color:#a1a1a6; }\ninput:focus, select:focus { border-color:rgba(0,122,255,.55); box-shadow:0 0 0 4px rgba(0,122,255,.12); }\n.row { display:flex; gap:10px; margin-bottom:10px; align-items:center; }\n.row input { flex:1; }\n.stack { display:grid; gap:10px; }\n.stack.compact { gap:8px; }\n.field-row { display:grid; grid-template-columns:minmax(0, 1fr) auto; gap:8px; align-items:center; }\n.field-row:has(input + input + button) { grid-template-columns:minmax(0, 1fr) minmax(0, 1fr) auto; }\n.helper-title { font-size:15px; font-weight:700; color:var(--text); margin:2px 0 6px; }\n.helper-text { color:var(--muted); font-size:13px; line-height:1.6; margin-bottom:12px; overflow-wrap:anywhere; }\n.upload-card { display:flex; gap:14px; align-items:center; border:1.5px dashed rgba(0,122,255,.32); background:rgba(0,122,255,.06); border-radius:20px; padding:16px; cursor:pointer; margin-bottom:10px; }\n.upload-card:hover { background:rgba(0,122,255,.10); border-color:rgba(0,122,255,.55); }\nbutton.loading, .upload-card.loading { position:relative; pointer-events:none; opacity:.82; cursor:progress; }\nbutton.loading::after, .upload-card.loading::after { content:''; width:14px; height:14px; border:2px solid currentColor; border-top-color:transparent; border-radius:50%; display:inline-block; margin-left:8px; vertical-align:-2px; animation:spin .8s linear infinite; }\n.upload-card.loading::after { margin-left:auto; color:#007aff; width:18px; height:18px; }\nbutton:disabled { cursor:progress; }\n@keyframes spin { to { transform:rotate(360deg); } }\n.upload-card input { display:none; }\n.upload-card b { display:block; font-size:15px; }\n.upload-card span { display:block; color:var(--muted); font-size:12px; line-height:1.45; margin-top:3px; overflow-wrap:anywhere; }\n.upload-icon { width:38px; height:38px; flex:0 0 38px; border-radius:50%; display:grid; place-items:center; background:#007aff; color:white; font-weight:800; font-size:20px; }\n.advanced-block { margin-top:12px; border:1px solid var(--line); border-radius:16px; padding:10px 12px; background:rgba(255,255,255,.55); }\n.advanced-block summary { cursor:pointer; color:var(--muted); font-size:13px; font-weight:600; margin-bottom:8px; }\n.divider { height:1px; background:var(--line); margin:16px 0; }\n.search-bar { display:grid; grid-template-columns: 170px minmax(0, 1fr) auto; gap:10px; align-items:end; }\n.filter-bar { display:grid; grid-template-columns: repeat(2, minmax(180px, 260px)); gap:10px; align-items:end; margin:12px 0 14px; }\n.select-wrap { position:relative; display:grid; gap:5px; color:var(--muted); font-size:12px; font-weight:600; min-width:0; overflow:visible; }\n.select-wrap.compact { min-width:130px; }\n.language-select { width:96px; min-width:96px; }\n.language-select select { min-width:96px; width:96px; cursor:pointer; }\n.select-wrap select { width:100%; }\n.select-native-hidden { position:absolute !important; opacity:0 !important; pointer-events:none !important; width:1px !important; height:1px !important; }\n.custom-select { position:relative; min-width:0; z-index:1; }\n.custom-select.open { z-index:10001; }\n.custom-select-trigger { width:100%; justify-content:space-between; text-align:left; display:flex; align-items:center; gap:10px; background:rgba(255,255,255,.88); color:var(--text); border:1px solid var(--line); border-radius:14px; padding:10px 13px; box-shadow: inset 0 0 0 1px rgba(255,255,255,.25); }\n.custom-select-trigger::after { content:'\u2304'; color:var(--muted); font-size:13px; line-height:1; display:inline-flex; align-items:center; justify-content:center; transform:translateY(-1px); flex:0 0 auto; }\n.custom-select.open .custom-select-trigger { border-color:rgba(0,122,255,.55); box-shadow:0 0 0 4px rgba(0,122,255,.12); }\n.custom-select-menu { display:none; position:absolute; top:calc(100% + 6px); left:0; right:0; z-index:10002; max-height:260px; overflow:auto; padding:6px; border:1px solid var(--line); border-radius:16px; background:rgba(255,255,255,.98); box-shadow:0 18px 40px rgba(0,0,0,.16); backdrop-filter:blur(16px); }\n.custom-select.open .custom-select-menu { display:block; }\n.custom-select-option { display:block; width:100%; border:0; box-shadow:none; background:transparent; text-align:left; color:var(--text); border-radius:10px; padding:9px 10px; white-space:normal; }\n.custom-select-option:hover, .custom-select-option.active { background:rgba(0,122,255,.10); color:var(--accent); transform:none; box-shadow:none; }\n.config-row { display:grid; grid-template-columns:90px minmax(0, 1fr); gap:10px; align-items:start; padding:8px 0; border-top:1px solid var(--line); }\n.config-row:first-child { border-top:0; }\n.config-row b, .config-row span { min-width:0; overflow-wrap:anywhere; line-height:1.5; }\n.file-group { border:1px solid var(--line); border-radius:18px; background:rgba(255,255,255,.58); margin-top:10px; overflow:hidden; }\n.file-group summary { cursor:pointer; padding:12px 14px; font-weight:700; display:flex; justify-content:space-between; align-items:center; }\n.file-group summary span { color:var(--muted); font-size:12px; }\n.file-item { display:grid; grid-template-columns:minmax(0, 1fr) auto; gap:12px; padding:12px 14px; border-top:1px solid var(--line); align-items:center; }\n.file-main { min-width:0; }\n.file-actions { display:flex; gap:6px; flex-wrap:wrap; justify-content:flex-end; }\n.file-actions button { padding:7px 9px; font-size:12px; }\n.grid { display:grid; gap:20px; grid-template-columns: repeat(2, minmax(0, 1fr)); }\n.panel-gap { margin-top:20px; }\n.stat-grid { display:grid; grid-template-columns: repeat(3, 1fr); gap:10px; margin:10px 0 12px; }\n.metric { background:linear-gradient(180deg, #fff, #f7f7fa); border:1px solid var(--line); border-radius:18px; padding:14px; }\n.metric b { display:block; font-size:24px; margin-top:4px; letter-spacing:-.03em; }\n.metric span { color:var(--muted); font-size:12px; }\n.stat { display:flex; justify-content:space-between; align-items:flex-start; color:var(--muted); margin:8px 0; gap:12px; }\n.stat b { color:var(--text); }\n.card { border-top:1px solid var(--line); padding:14px 0; }\n.card:first-child { border-top:0; padding-top:0; }\n.path { color:var(--accent); font-size:13px; overflow-wrap:anywhere; word-break:normal; font-weight:600; line-height:1.45; }\n.meta { color:var(--muted); font-size:12px; overflow-wrap:anywhere; word-break:normal; line-height:1.55; min-width:0; }\n.badge { display:inline-flex; align-items:center; border:1px solid var(--line); border-radius:999px; padding:3px 9px; font-size:12px; color:var(--muted); margin:3px 5px 3px 0; background:rgba(255,255,255,.7); }\n.badge.ok { color:#1d7f3a; border-color:rgba(52,199,89,.28); background:rgba(52,199,89,.10); }\n.badge.warn { color:#9a5a00; border-color:rgba(255,149,0,.30); background:rgba(255,149,0,.10); }\n#capabilities { max-height: 460px; overflow:auto; padding-right:4px; }\n#results .card { background:var(--panel-solid); border-radius:20px; border:1px solid var(--line); margin-top:12px; padding:16px; box-shadow:var(--shadow-soft); }\n.status { color:var(--muted); min-height:20px; font-size:12px; margin-top:8px; }\n.status.ok { color:var(--ok); }\n.status.error { color:var(--danger); }\n.toolbar { display:flex; gap:10px; align-items:center; justify-content:flex-end; }\npre { white-space:pre-wrap; word-break:break-word; color:#3a3a3c; margin:10px 0 0; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size:12px; line-height:1.55; }\n.subsection { margin-top:18px; padding-top:16px; border-top:1px solid var(--line); }\n.modal-backdrop { position:fixed; inset:0; z-index:20000; display:grid; place-items:center; background:rgba(15,23,42,.35); backdrop-filter:blur(10px); }\n.modal-backdrop[hidden] { display:none; }\n.modal-card { width:min(520px, calc(100vw - 32px)); background:rgba(255,255,255,.98); border:1px solid var(--line); border-radius:24px; box-shadow:0 28px 70px rgba(0,0,0,.22); padding:22px; }\n.modal-card h3 { margin:0 0 8px; }\n.modal-card p { white-space:pre-wrap; color:var(--muted); margin:0 0 14px; }\n.modal-input { width:100%; box-sizing:border-box; margin:0 0 14px; border:1px solid var(--line); border-radius:14px; padding:11px 12px; font:inherit; }\n.modal-actions { display:flex; justify-content:flex-end; gap:10px; }\nbutton.danger { background:linear-gradient(135deg,#ff3b30,#ff6b5f); color:white; border-color:rgba(255,59,48,.25); }\n@media (max-width: 1080px) { .grid { grid-template-columns:1fr; } }\n@media (max-width: 680px) { main { padding:16px; } header { padding:16px; align-items:flex-start; flex-direction:column; } .toolbar { width:100%; justify-content:flex-start; flex-wrap:wrap; } .row { flex-direction:column; align-items:stretch; } .search-bar, .filter-bar { grid-template-columns:1fr; } select { width:100%; } .field-row, .field-row:has(input + input + button), .file-item, .config-row { grid-template-columns:1fr; } .file-actions { justify-content:flex-start; } .stat-grid { grid-template-columns:1fr; } .upload-card { align-items:flex-start; } }\n";
|
|
1
|
+
export declare const dashboardStyles = "\n:root {\n color-scheme: light;\n --bg:#f5f5f7;\n --bg-glass:rgba(255,255,255,.72);\n --panel:rgba(255,255,255,.86);\n --panel-solid:#ffffff;\n --line:rgba(60,60,67,.16);\n --line-strong:rgba(60,60,67,.26);\n --text:#1d1d1f;\n --muted:#6e6e73;\n --accent:#007aff;\n --accent-2:#5856d6;\n --danger:#ff3b30;\n --ok:#34c759;\n --warn:#ff9500;\n --shadow:0 18px 45px rgba(0,0,0,.08);\n --shadow-soft:0 8px 24px rgba(0,0,0,.06);\n}\n* { box-sizing: border-box; }\nhtml { background:var(--bg); }\nbody {\n margin:0; min-height:100vh; font-family: -apple-system, BlinkMacSystemFont, \"SF Pro Display\", \"SF Pro Text\", \"Segoe UI\", sans-serif;\n background:\n radial-gradient(circle at 15% 0%, rgba(0,122,255,.12), transparent 28rem),\n radial-gradient(circle at 85% 8%, rgba(88,86,214,.10), transparent 26rem),\n linear-gradient(180deg, #fbfbfd 0%, var(--bg) 100%);\n color:var(--text);\n}\nheader {\n position: sticky; top:0; z-index:10; backdrop-filter: saturate(180%) blur(22px); -webkit-backdrop-filter: saturate(180%) blur(22px);\n padding:20px max(32px, calc((100vw - 1480px) / 2 + 32px)); border-bottom:1px solid var(--line); display:flex; align-items:center; justify-content:space-between; gap:18px;\n background:var(--bg-glass);\n}\nmain { padding:28px 32px 40px; max-width:1480px; margin:0 auto; }\nmain, aside, main > div { min-width:0; }\n.page { display:none; }\n.page.active { display:block; }\n.topbar { flex-wrap:nowrap; justify-content:flex-start; overflow-x:auto; padding-bottom:2px; scrollbar-width:none; }\n.topbar::-webkit-scrollbar { display:none; }\n.topbar > * { flex:0 0 auto; }\n.tab { background:rgba(255,255,255,.72); border-radius:999px; padding:9px 15px; color:var(--muted); }\n.tab.active { background:#1d1d1f; color:white; border-color:#1d1d1f; }\nsection {\n position:relative; overflow:visible;\n background:var(--panel); border:1px solid rgba(255,255,255,.7); border-radius:26px; padding:20px; box-shadow:var(--shadow-soft);\n backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);\n}\nsection:has(.custom-select.open), section.select-host-open { z-index:10000; }\nsection:hover { box-shadow:var(--shadow); transform:translateY(-1px); transition:.2s ease; }\nh1 { font-size:24px; margin:0; letter-spacing:-.02em; font-weight:700; }\nh2 { font-size:12px; margin:0 0 14px; color:var(--muted); text-transform:uppercase; letter-spacing:.12em; font-weight:700; }\nh3 { font-size:15px; margin:14px 0 8px; }\n.subtitle { margin-top:6px; color:var(--muted); font-size:14px; }\nbutton, input, select {\n min-width:0; background:rgba(255,255,255,.88); color:var(--text); border:1px solid var(--line); border-radius:14px; padding:10px 13px; outline:none;\n font: inherit; box-shadow: inset 0 0 0 1px rgba(255,255,255,.25);\n}\nselect {\n min-width:132px; appearance:none; -webkit-appearance:none; padding-right:34px;\n background-image:linear-gradient(45deg, transparent 50%, #6e6e73 50%), linear-gradient(135deg, #6e6e73 50%, transparent 50%);\n background-position:calc(100% - 18px) 50%, calc(100% - 12px) 50%; background-size:6px 6px, 6px 6px; background-repeat:no-repeat;\n}\nbutton { cursor:pointer; white-space:nowrap; transition:.16s ease; font-weight:600; }\nbutton:hover { border-color:rgba(0,122,255,.35); transform:translateY(-1px); box-shadow:0 8px 18px rgba(0,122,255,.12); }\nbutton.primary { background:linear-gradient(180deg, #0a84ff, #007aff); border-color:transparent; color:white; box-shadow:0 10px 22px rgba(0,122,255,.24); }\ninput { width:100%; }\ninput::placeholder { color:#a1a1a6; }\ninput:focus, select:focus { border-color:rgba(0,122,255,.55); box-shadow:0 0 0 4px rgba(0,122,255,.12); }\n.row { display:flex; gap:10px; margin-bottom:10px; align-items:center; }\n.row input { flex:1; }\n.stack { display:grid; gap:10px; }\n.stack.compact { gap:8px; }\n.field-row { display:grid; grid-template-columns:minmax(0, 1fr) auto; gap:8px; align-items:center; }\n.field-row:has(input + input + button) { grid-template-columns:minmax(0, 1fr) minmax(0, 1fr) auto; }\n.helper-title { font-size:15px; font-weight:700; color:var(--text); margin:2px 0 6px; }\n.helper-text { color:var(--muted); font-size:13px; line-height:1.6; margin-bottom:12px; overflow-wrap:anywhere; }\n.upload-card { display:flex; gap:14px; align-items:center; border:1.5px dashed rgba(0,122,255,.32); background:rgba(0,122,255,.06); border-radius:20px; padding:16px; cursor:pointer; margin-bottom:10px; }\n.upload-card:hover { background:rgba(0,122,255,.10); border-color:rgba(0,122,255,.55); }\nbutton.loading, .upload-card.loading { position:relative; pointer-events:none; opacity:.82; cursor:progress; }\nbutton.loading::after, .upload-card.loading::after { content:''; width:14px; height:14px; border:2px solid currentColor; border-top-color:transparent; border-radius:50%; display:inline-block; margin-left:8px; vertical-align:-2px; animation:spin .8s linear infinite; }\n.upload-card.loading::after { margin-left:auto; color:#007aff; width:18px; height:18px; }\nbutton:disabled { cursor:progress; }\n@keyframes spin { to { transform:rotate(360deg); } }\n.upload-card input { display:none; }\n.upload-card b { display:block; font-size:15px; }\n.upload-card span { display:block; color:var(--muted); font-size:12px; line-height:1.45; margin-top:3px; overflow-wrap:anywhere; }\n.upload-icon { width:38px; height:38px; flex:0 0 38px; border-radius:50%; display:grid; place-items:center; background:#007aff; color:white; font-weight:800; font-size:20px; }\n.advanced-block { margin-top:12px; border:1px solid var(--line); border-radius:16px; padding:10px 12px; background:rgba(255,255,255,.55); }\n.advanced-block summary { cursor:pointer; color:var(--muted); font-size:13px; font-weight:600; margin-bottom:8px; }\n.divider { height:1px; background:var(--line); margin:16px 0; }\n.search-bar { display:grid; grid-template-columns: 170px minmax(0, 1fr) auto; gap:10px; align-items:end; }\n.filter-bar { display:grid; grid-template-columns: repeat(2, minmax(180px, 260px)); gap:10px; align-items:end; margin:12px 0 14px; }\n.select-wrap { position:relative; display:grid; gap:5px; color:var(--muted); font-size:12px; font-weight:600; min-width:0; overflow:visible; }\n.select-wrap.compact { min-width:130px; }\n.language-select { width:96px; min-width:96px; }\n.language-select select { min-width:96px; width:96px; cursor:pointer; }\n.select-wrap select { width:100%; }\n.select-native-hidden { position:absolute !important; opacity:0 !important; pointer-events:none !important; width:1px !important; height:1px !important; }\n.custom-select { position:relative; min-width:0; z-index:1; }\n.custom-select.open { z-index:10001; }\n.custom-select-trigger { width:100%; justify-content:space-between; text-align:left; display:flex; align-items:center; gap:10px; background:rgba(255,255,255,.88); color:var(--text); border:1px solid var(--line); border-radius:14px; padding:10px 13px; box-shadow: inset 0 0 0 1px rgba(255,255,255,.25); }\n.custom-select-trigger::after { content:'\u2304'; color:var(--muted); font-size:13px; line-height:1; display:inline-flex; align-items:center; justify-content:center; transform:translateY(-1px); flex:0 0 auto; }\n.custom-select.open .custom-select-trigger { border-color:rgba(0,122,255,.55); box-shadow:0 0 0 4px rgba(0,122,255,.12); }\n.custom-select-menu { display:none; position:absolute; top:calc(100% + 6px); left:0; right:0; z-index:10002; max-height:260px; overflow:auto; padding:6px; border:1px solid var(--line); border-radius:16px; background:rgba(255,255,255,.98); box-shadow:0 18px 40px rgba(0,0,0,.16); backdrop-filter:blur(16px); }\n.custom-select.open .custom-select-menu { display:block; }\n.custom-select-option { display:block; width:100%; border:0; box-shadow:none; background:transparent; text-align:left; color:var(--text); border-radius:10px; padding:9px 10px; white-space:normal; }\n.custom-select-option:hover, .custom-select-option.active { background:rgba(0,122,255,.10); color:var(--accent); transform:none; box-shadow:none; }\n.config-row { display:grid; grid-template-columns:90px minmax(0, 1fr); gap:10px; align-items:start; padding:8px 0; border-top:1px solid var(--line); }\n.config-row:first-child { border-top:0; }\n.config-row b, .config-row span { min-width:0; overflow-wrap:anywhere; line-height:1.5; }\n.file-group { border:1px solid var(--line); border-radius:18px; background:rgba(255,255,255,.58); margin-top:10px; overflow:hidden; }\n.file-group summary { cursor:pointer; padding:12px 14px; font-weight:700; display:flex; justify-content:space-between; align-items:center; }\n.file-group summary span { color:var(--muted); font-size:12px; }\n.file-item { display:grid; grid-template-columns:minmax(0, 1fr) auto; gap:12px; padding:12px 14px; border-top:1px solid var(--line); align-items:center; }\n.file-main { min-width:0; }\n.file-actions { display:flex; gap:6px; flex-wrap:wrap; justify-content:flex-end; }\n.file-actions button { padding:7px 9px; font-size:12px; }\n.grid { display:grid; gap:20px; grid-template-columns: repeat(2, minmax(0, 1fr)); }\n.panel-gap { margin-top:20px; }\n.stat-grid { display:grid; grid-template-columns: repeat(3, 1fr); gap:10px; margin:10px 0 12px; }\n.metric { background:linear-gradient(180deg, #fff, #f7f7fa); border:1px solid var(--line); border-radius:18px; padding:14px; }\n.metric b { display:block; font-size:24px; margin-top:4px; letter-spacing:-.03em; }\n.metric span { color:var(--muted); font-size:12px; }\n.stat { display:flex; justify-content:space-between; align-items:flex-start; color:var(--muted); margin:8px 0; gap:12px; }\n.stat b { color:var(--text); }\n.card { border-top:1px solid var(--line); padding:14px 0; }\n.card:first-child { border-top:0; padding-top:0; }\n.path { color:var(--accent); font-size:13px; overflow-wrap:anywhere; word-break:normal; font-weight:600; line-height:1.45; }\n.meta { color:var(--muted); font-size:12px; overflow-wrap:anywhere; word-break:normal; line-height:1.55; min-width:0; }\n.badge { display:inline-flex; align-items:center; border:1px solid var(--line); border-radius:999px; padding:3px 9px; font-size:12px; color:var(--muted); margin:3px 5px 3px 0; background:rgba(255,255,255,.7); }\n.badge.ok { color:#1d7f3a; border-color:rgba(52,199,89,.28); background:rgba(52,199,89,.10); }\n.badge.warn { color:#9a5a00; border-color:rgba(255,149,0,.30); background:rgba(255,149,0,.10); }\n#capabilities { max-height: 460px; overflow:auto; padding-right:4px; }\n#results .card { background:var(--panel-solid); border-radius:20px; border:1px solid var(--line); margin-top:12px; padding:16px; box-shadow:var(--shadow-soft); }\n.status { color:var(--muted); min-height:20px; font-size:12px; margin-top:8px; }\n.status.ok { color:var(--ok); }\n.status.error { color:var(--danger); }\n.toolbar { display:flex; gap:10px; align-items:center; justify-content:flex-end; }\npre { white-space:pre-wrap; word-break:break-word; color:#3a3a3c; margin:10px 0 0; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size:12px; line-height:1.55; }\n.subsection { margin-top:18px; padding-top:16px;}\n.modal-backdrop { position:fixed; inset:0; z-index:20000; display:grid; place-items:center; background:rgba(15,23,42,.35); backdrop-filter:blur(10px); }\n.modal-backdrop[hidden] { display:none; }\n.modal-card { width:min(520px, calc(100vw - 32px)); background:rgba(255,255,255,.98); border:1px solid var(--line); border-radius:24px; box-shadow:0 28px 70px rgba(0,0,0,.22); padding:22px; }\n.modal-card h3 { margin:0 0 8px; }\n.modal-card p { white-space:pre-wrap; color:var(--muted); margin:0 0 14px; }\n.modal-input { width:100%; box-sizing:border-box; margin:0 0 14px; border:1px solid var(--line); border-radius:14px; padding:11px 12px; font:inherit; }\n.modal-actions { display:flex; justify-content:flex-end; gap:10px; }\nbutton.danger { background:linear-gradient(135deg,#ff3b30,#ff6b5f); color:white; border-color:rgba(255,59,48,.25); }\n@media (max-width: 1080px) { .grid { grid-template-columns:1fr; } }\n@media (max-width: 680px) { main { padding:16px; } header { padding:16px; align-items:flex-start; flex-direction:column; } .toolbar { width:100%; justify-content:flex-start; flex-wrap:wrap; } .row { flex-direction:column; align-items:stretch; } .search-bar, .filter-bar { grid-template-columns:1fr; } select { width:100%; } .field-row, .field-row:has(input + input + button), .file-item, .config-row { grid-template-columns:1fr; } .file-actions { justify-content:flex-start; } .stat-grid { grid-template-columns:1fr; } .upload-card { align-items:flex-start; } }\n";
|
|
@@ -138,7 +138,7 @@ button:disabled { cursor:progress; }
|
|
|
138
138
|
.status.error { color:var(--danger); }
|
|
139
139
|
.toolbar { display:flex; gap:10px; align-items:center; justify-content:flex-end; }
|
|
140
140
|
pre { white-space:pre-wrap; word-break:break-word; color:#3a3a3c; margin:10px 0 0; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size:12px; line-height:1.55; }
|
|
141
|
-
.subsection { margin-top:18px; padding-top:16px;
|
|
141
|
+
.subsection { margin-top:18px; padding-top:16px;}
|
|
142
142
|
.modal-backdrop { position:fixed; inset:0; z-index:20000; display:grid; place-items:center; background:rgba(15,23,42,.35); backdrop-filter:blur(10px); }
|
|
143
143
|
.modal-backdrop[hidden] { display:none; }
|
|
144
144
|
.modal-card { width:min(520px, calc(100vw - 32px)); background:rgba(255,255,255,.98); border:1px solid var(--line); border-radius:24px; box-shadow:0 28px 70px rgba(0,0,0,.22); padding:22px; }
|