@deployxai/dxc 0.3.1 → 0.3.3
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/README.md +6 -3
- package/dist/chunks/chunk-P5VZG7OG.js +2345 -0
- package/dist/chunks/{knowledge-JCYMCMSP.js → knowledge-QIIEPI2V.js} +538 -199
- package/dist/index.js +2150 -1021
- package/package.json +2 -2
- package/skills/dxc-article-outline/SKILL.md +17 -3
- package/skills/dxc-article-write/SKILL.md +21 -5
- package/skills/dxc-content-brief/SKILL.md +17 -3
- package/skills/dxc-content-review/SKILL.md +21 -5
- package/skills/dxc-content-review/references/review-checklist.md +2 -1
- package/skills/dxc-content-workflow/SKILL.md +9 -3
- package/skills/dxc-knowledge/SKILL.md +12 -7
- package/skills/dxc-memory/SKILL.md +24 -8
- package/skills/dxc-profile/SKILL.md +28 -10
- package/skills/dxc-project-overview/SKILL.md +9 -5
- package/skills/dxc-quote-curator/SKILL.md +23 -9
- package/skills/dxc-research/SKILL.md +17 -3
- package/skills/dxc-title-write/SKILL.md +20 -4
- package/skills/dxc-visual-plan/SKILL.md +19 -12
- package/skills/dxc-wechat-publisher/SKILL.md +14 -8
- package/dist/chunks/chunk-6JNQZHAQ.js +0 -1522
|
@@ -7,23 +7,29 @@ import {
|
|
|
7
7
|
CONTENT_KNOWLEDGE_EMBEDDING_REVISION,
|
|
8
8
|
CONTENT_KNOWLEDGE_SCHEMA_VERSION,
|
|
9
9
|
LocalStateError,
|
|
10
|
+
ProjectCli,
|
|
11
|
+
contentKnowledgeAdoptResultSchema,
|
|
10
12
|
contentKnowledgeImportResultSchema,
|
|
11
13
|
contentKnowledgeModelSchema,
|
|
12
14
|
contentKnowledgeQuoteListResultSchema,
|
|
13
15
|
contentKnowledgeQuoteMutationResultSchema,
|
|
14
16
|
contentKnowledgeQuoteStatusResultSchema,
|
|
17
|
+
contentKnowledgeRefSchema,
|
|
15
18
|
contentKnowledgeRemoveResultSchema,
|
|
16
19
|
contentKnowledgeSearchModeSchema,
|
|
17
20
|
contentKnowledgeSearchResultSchema,
|
|
21
|
+
contentKnowledgeSourceFilterSchema,
|
|
18
22
|
contentKnowledgeStatusResultSchema,
|
|
23
|
+
contentWorkflowAdoptedKnowledgeSchema,
|
|
19
24
|
ensurePrivateDirectory,
|
|
20
25
|
ensurePrivateRegularFile,
|
|
21
26
|
readPrivateBuffer,
|
|
22
27
|
readPrivateFile,
|
|
23
28
|
resolveUserPath,
|
|
29
|
+
withPrivateFileLocks,
|
|
24
30
|
writePrivateBuffer,
|
|
25
31
|
writePrivateJson
|
|
26
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-P5VZG7OG.js";
|
|
27
33
|
|
|
28
34
|
// apps/cli/src/knowledge.ts
|
|
29
35
|
import { createHash as createHash2, randomUUID } from "node:crypto";
|
|
@@ -330,8 +336,6 @@ var LocalBgeKnowledgeEmbedder = class {
|
|
|
330
336
|
};
|
|
331
337
|
|
|
332
338
|
// apps/cli/src/knowledge.ts
|
|
333
|
-
var DATABASE_DISPLAY_PATH = "~/.dxc/content-memory.sqlite";
|
|
334
|
-
var QUOTE_SOURCE_DISPLAY_PATH = "~/Documents/DxC/\u91D1\u53E5\u5E93.md";
|
|
335
339
|
var QUOTE_SOURCE_FILE_NAME = "\u91D1\u53E5\u5E93.md";
|
|
336
340
|
var LEGACY_QUOTE_SOURCE_FILE_NAME = "quotes.json";
|
|
337
341
|
var MAXIMUM_ARTICLE_BYTES = 5 * 1024 * 1024;
|
|
@@ -348,15 +352,20 @@ var SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Set([".md", ".markdown", ".txt"])
|
|
|
348
352
|
var MAXIMUM_DIRECTORY_ARTICLES = 1e3;
|
|
349
353
|
var MAXIMUM_DIRECTORY_DEPTH = 32;
|
|
350
354
|
var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu;
|
|
355
|
+
var KNOWLEDGE_REF_PATTERN = /^kr1_([A-Za-z0-9_-]+)\.([a-f0-9]{32})$/u;
|
|
356
|
+
var PROJECT_CONTEXT_FILE = ".dxc/context.json";
|
|
357
|
+
var PROJECT_CONTEXT_MAXIMUM_BYTES = 64 * 1024;
|
|
351
358
|
var KnowledgeCliError = class extends Error {
|
|
352
|
-
constructor(code, message, details) {
|
|
359
|
+
constructor(code, message, details, fields = { recovery: "\u8BF7\u6309 Skill \u8FD4\u56DE\u7684\u6062\u590D\u52A8\u4F5C\u91CD\u8BD5\u3002" }) {
|
|
353
360
|
super(message);
|
|
354
361
|
this.code = code;
|
|
355
362
|
this.details = details;
|
|
363
|
+
this.fields = fields;
|
|
356
364
|
this.name = "KnowledgeCliError";
|
|
357
365
|
}
|
|
358
366
|
code;
|
|
359
367
|
details;
|
|
368
|
+
fields;
|
|
360
369
|
};
|
|
361
370
|
var quoteMetadataValueSchema = z.string().trim().min(1).max(300).refine((value) => !/[\r\n]/u.test(value) && value !== "\uFF08\u65E0\uFF09", {
|
|
362
371
|
message: "quote metadata must stay on one line"
|
|
@@ -426,6 +435,75 @@ function skippedArticle(error, inputPath) {
|
|
|
426
435
|
function sha2562(value) {
|
|
427
436
|
return createHash2("sha256").update(value).digest("hex");
|
|
428
437
|
}
|
|
438
|
+
var projectContextStoreSchema = z.object({
|
|
439
|
+
adoptedKnowledge: z.array(
|
|
440
|
+
z.union([
|
|
441
|
+
contentWorkflowAdoptedKnowledgeSchema,
|
|
442
|
+
z.object({
|
|
443
|
+
attribution: z.string().trim().min(1).max(300).nullable(),
|
|
444
|
+
knowledgeRef: contentKnowledgeRefSchema,
|
|
445
|
+
label: z.string().trim().min(1).max(300),
|
|
446
|
+
snippet: z.string().trim().min(1).max(420),
|
|
447
|
+
sourceType: z.literal("quote"),
|
|
448
|
+
verbatimUse: z.literal("do-not-use-verbatim")
|
|
449
|
+
}).strict()
|
|
450
|
+
])
|
|
451
|
+
).max(20),
|
|
452
|
+
quoteVerbatimGuards: z.array(
|
|
453
|
+
z.object({
|
|
454
|
+
knowledgeRef: contentKnowledgeRefSchema,
|
|
455
|
+
text: z.string().trim().min(1).max(2e3)
|
|
456
|
+
}).strict()
|
|
457
|
+
).max(20).default([]),
|
|
458
|
+
schemaVersion: z.literal("1")
|
|
459
|
+
}).strict();
|
|
460
|
+
function encodeKnowledgeRef(payload) {
|
|
461
|
+
const encoded = Buffer.from(JSON.stringify(payload), "utf8").toString("base64url");
|
|
462
|
+
return `kr1_${encoded}.${sha2562(encoded).slice(0, 32)}`;
|
|
463
|
+
}
|
|
464
|
+
function decodeKnowledgeRef(value) {
|
|
465
|
+
const match = KNOWLEDGE_REF_PATTERN.exec(value);
|
|
466
|
+
if (match?.[1] === void 0 || match[2] === void 0 || sha2562(match[1]).slice(0, 32) !== match[2]) {
|
|
467
|
+
throw new KnowledgeCliError(
|
|
468
|
+
"DXC_KNOWLEDGE_REFERENCE_INVALID",
|
|
469
|
+
"\u77E5\u8BC6\u5F15\u7528\u683C\u5F0F\u6216\u5B8C\u6574\u6027\u65E0\u6548\u3002",
|
|
470
|
+
void 0,
|
|
471
|
+
{
|
|
472
|
+
actual: value,
|
|
473
|
+
expected: "knowledge search \u8FD4\u56DE\u7684 knowledgeRef",
|
|
474
|
+
field: "item",
|
|
475
|
+
recovery: "\u8BF7\u91CD\u65B0\u68C0\u7D22\u5E76\u4F7F\u7528\u5F53\u524D\u7ED3\u679C\u8FD4\u56DE\u7684 knowledgeRef\u3002"
|
|
476
|
+
}
|
|
477
|
+
);
|
|
478
|
+
}
|
|
479
|
+
try {
|
|
480
|
+
const payload = JSON.parse(Buffer.from(match[1], "base64url").toString("utf8"));
|
|
481
|
+
if (typeof payload !== "object" || payload === null || !("version" in payload) || payload.version !== 1 || !("sourceType" in payload) || payload.sourceType !== "history-article" && payload.sourceType !== "quote" || !("contentSha256" in payload) || typeof payload.contentSha256 !== "string") {
|
|
482
|
+
throw new Error("invalid");
|
|
483
|
+
}
|
|
484
|
+
return payload;
|
|
485
|
+
} catch {
|
|
486
|
+
throw new KnowledgeCliError(
|
|
487
|
+
"DXC_KNOWLEDGE_REFERENCE_INVALID",
|
|
488
|
+
"\u77E5\u8BC6\u5F15\u7528\u5185\u5BB9\u65E0\u6548\u3002",
|
|
489
|
+
void 0,
|
|
490
|
+
{
|
|
491
|
+
recovery: "\u8BF7\u91CD\u65B0\u68C0\u7D22\u5E76\u4F7F\u7528\u5F53\u524D\u7ED3\u679C\u8FD4\u56DE\u7684 knowledgeRef\u3002"
|
|
492
|
+
}
|
|
493
|
+
);
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
function sameKnowledgeEntity(value, expected) {
|
|
497
|
+
try {
|
|
498
|
+
const actual = decodeKnowledgeRef(value);
|
|
499
|
+
if (actual.sourceType !== expected.sourceType) {
|
|
500
|
+
return false;
|
|
501
|
+
}
|
|
502
|
+
return actual.sourceType === "quote" ? actual.quoteId === (expected.sourceType === "quote" ? expected.quoteId : void 0) : actual.articleId === (expected.sourceType === "history-article" ? expected.articleId : void 0) && actual.chunkId === (expected.sourceType === "history-article" ? expected.chunkId : void 0);
|
|
503
|
+
} catch {
|
|
504
|
+
return false;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
429
507
|
function knowledgeModelChoices(operation, inputFingerprint) {
|
|
430
508
|
const choiceId = (mode) => {
|
|
431
509
|
const payload = Buffer.from(
|
|
@@ -772,7 +850,6 @@ function articleSummary(row) {
|
|
|
772
850
|
return {
|
|
773
851
|
articleId: row.id,
|
|
774
852
|
chunkCount: row.chunkCount,
|
|
775
|
-
contentSha256: row.contentSha256,
|
|
776
853
|
importedAt: row.importedAt,
|
|
777
854
|
sourceLabel: row.sourceLabel,
|
|
778
855
|
title: row.title,
|
|
@@ -1151,10 +1228,26 @@ async function readQuoteSource(sourcePath, allowLegacyPermissions = false) {
|
|
|
1151
1228
|
quotes: preparedQuotes(document.data)
|
|
1152
1229
|
};
|
|
1153
1230
|
}
|
|
1154
|
-
async function writeQuoteSource(sourcePath, quotes) {
|
|
1231
|
+
async function writeQuoteSource(sourcePath, quotes, expectedSha256) {
|
|
1155
1232
|
try {
|
|
1156
|
-
|
|
1157
|
-
|
|
1233
|
+
if (expectedSha256 !== void 0) {
|
|
1234
|
+
const current = await readQuoteSource(sourcePath);
|
|
1235
|
+
if (current.contentSha256 !== expectedSha256) {
|
|
1236
|
+
throw new KnowledgeCliError(
|
|
1237
|
+
"DXC_KNOWLEDGE_REFERENCE_STALE",
|
|
1238
|
+
"\u91D1\u53E5\u5E93\u5DF2\u88AB\u5176\u4ED6\u52A8\u4F5C\u6216\u7528\u6237\u4FEE\u6539\u3002",
|
|
1239
|
+
void 0,
|
|
1240
|
+
{ recovery: "\u8BF7\u91CD\u65B0\u67E5\u770B\u91D1\u53E5\u5E93\uFF0C\u518D\u91CD\u505A\u672C\u6B21\u4FEE\u6539\u3002" }
|
|
1241
|
+
);
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
const contents = quoteSourceTemplate(quotes);
|
|
1245
|
+
await writePrivateBuffer(sourcePath, Buffer.from(contents, "utf8"));
|
|
1246
|
+
return sha2562(contents);
|
|
1247
|
+
} catch (error) {
|
|
1248
|
+
if (error instanceof KnowledgeCliError) {
|
|
1249
|
+
throw error;
|
|
1250
|
+
}
|
|
1158
1251
|
throw new KnowledgeCliError("DXC_KNOWLEDGE_IO_FAILED", "Unable to write quote source file");
|
|
1159
1252
|
}
|
|
1160
1253
|
}
|
|
@@ -1179,13 +1272,10 @@ function quoteSourceSummary(database, sourceInitialized) {
|
|
|
1179
1272
|
FROM quotes`
|
|
1180
1273
|
).get()
|
|
1181
1274
|
);
|
|
1182
|
-
const source = database.prepare("SELECT content_sha256 FROM quote_sources WHERE source_key = 'default' LIMIT 1").get();
|
|
1183
1275
|
return {
|
|
1184
1276
|
activeCount: numberColumn(counts, "active_count"),
|
|
1185
1277
|
archivedCount: numberColumn(counts, "archived_count"),
|
|
1186
|
-
sourceInitialized
|
|
1187
|
-
sourcePath: QUOTE_SOURCE_DISPLAY_PATH,
|
|
1188
|
-
sourceSha256: source === void 0 ? null : stringColumn(sqlRow(source), "content_sha256")
|
|
1278
|
+
sourceInitialized
|
|
1189
1279
|
};
|
|
1190
1280
|
}
|
|
1191
1281
|
function quoteEmbeddingText(quote) {
|
|
@@ -1397,9 +1487,11 @@ function semanticIndexComplete(database, articleId) {
|
|
|
1397
1487
|
);
|
|
1398
1488
|
return numberColumn(row, "total") > 0 && numberColumn(row, "total") === numberColumn(row, "indexed");
|
|
1399
1489
|
}
|
|
1400
|
-
function saveArticle(database, article, existing, vectors, timestamp, createId) {
|
|
1490
|
+
function saveArticle(database, article, existing, vectors, timestamp, createId, manageTransaction = true) {
|
|
1401
1491
|
const articleId = existing?.id ?? createId();
|
|
1402
|
-
|
|
1492
|
+
if (manageTransaction) {
|
|
1493
|
+
database.exec("BEGIN IMMEDIATE");
|
|
1494
|
+
}
|
|
1403
1495
|
try {
|
|
1404
1496
|
if (existing === void 0) {
|
|
1405
1497
|
database.prepare(
|
|
@@ -1476,11 +1568,15 @@ function saveArticle(database, article, existing, vectors, timestamp, createId)
|
|
|
1476
1568
|
);
|
|
1477
1569
|
insertSearch.run(chunkId, articleId, article.title, chunk.heading ?? "", chunk.body);
|
|
1478
1570
|
}
|
|
1479
|
-
|
|
1571
|
+
if (manageTransaction) {
|
|
1572
|
+
database.exec("COMMIT");
|
|
1573
|
+
}
|
|
1480
1574
|
} catch (error) {
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1575
|
+
if (manageTransaction) {
|
|
1576
|
+
try {
|
|
1577
|
+
database.exec("ROLLBACK");
|
|
1578
|
+
} catch {
|
|
1579
|
+
}
|
|
1484
1580
|
}
|
|
1485
1581
|
if (error instanceof KnowledgeCliError) {
|
|
1486
1582
|
throw error;
|
|
@@ -1651,12 +1747,15 @@ function fusedResults(chunks, mode, lexical, semantic, limit) {
|
|
|
1651
1747
|
}
|
|
1652
1748
|
articleCounts.set(chunk.articleId, (articleCounts.get(chunk.articleId) ?? 0) + 1);
|
|
1653
1749
|
results.push({
|
|
1654
|
-
articleId: chunk.articleId,
|
|
1655
|
-
chunkId: chunk.id,
|
|
1656
|
-
chunkSha256: chunk.chunkSha256,
|
|
1657
1750
|
heading: chunk.heading,
|
|
1751
|
+
knowledgeRef: encodeKnowledgeRef({
|
|
1752
|
+
articleId: chunk.articleId,
|
|
1753
|
+
chunkId: chunk.id,
|
|
1754
|
+
contentSha256: chunk.chunkSha256,
|
|
1755
|
+
sourceType: "history-article",
|
|
1756
|
+
version: 1
|
|
1757
|
+
}),
|
|
1658
1758
|
lanes: [...score.lanes].sort(),
|
|
1659
|
-
ordinal: chunk.ordinal,
|
|
1660
1759
|
rank: results.length + 1,
|
|
1661
1760
|
snippet: snippet(chunk.body),
|
|
1662
1761
|
sourceLabel: chunk.sourceLabel,
|
|
@@ -1692,15 +1791,18 @@ function fusedQuoteResults(quotes, mode, lexical, semantic, limit) {
|
|
|
1692
1791
|
}
|
|
1693
1792
|
results.push({
|
|
1694
1793
|
attribution: quote.attribution,
|
|
1695
|
-
|
|
1794
|
+
knowledgeRef: encodeKnowledgeRef({
|
|
1795
|
+
contentSha256: quote.contentSha256,
|
|
1796
|
+
quoteId: quote.id,
|
|
1797
|
+
sourceType: "quote",
|
|
1798
|
+
version: 1
|
|
1799
|
+
}),
|
|
1696
1800
|
lanes: [...score.lanes].sort(),
|
|
1697
1801
|
origin: quote.origin,
|
|
1698
|
-
quoteId: quote.id,
|
|
1699
1802
|
rank: results.length + 1,
|
|
1700
1803
|
snippet: snippet(quote.text),
|
|
1701
1804
|
sourceLabel: quote.sourceLabel,
|
|
1702
1805
|
sourceType: "quote",
|
|
1703
|
-
status: quote.status,
|
|
1704
1806
|
tags: [...quote.tags],
|
|
1705
1807
|
verbatimUse: quote.verbatimUse
|
|
1706
1808
|
});
|
|
@@ -1756,6 +1858,7 @@ var KnowledgeCli = class {
|
|
|
1756
1858
|
try {
|
|
1757
1859
|
const imported = [];
|
|
1758
1860
|
const skipped = [];
|
|
1861
|
+
const pending = [];
|
|
1759
1862
|
let semanticPreparationAnnounced = false;
|
|
1760
1863
|
for (const file of options.files) {
|
|
1761
1864
|
let article;
|
|
@@ -1772,40 +1875,59 @@ var KnowledgeCli = class {
|
|
|
1772
1875
|
const existing = findExistingArticle(database, article);
|
|
1773
1876
|
const unchanged = existing?.contentSha256 === article.contentSha256 && existing.chunkerVersion === CONTENT_KNOWLEDGE_CHUNKER_VERSION;
|
|
1774
1877
|
const semanticComplete = existing === void 0 ? false : semanticIndexComplete(database, existing.id);
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
article: articleSummary(existing),
|
|
1778
|
-
semanticIndexed: semanticComplete,
|
|
1779
|
-
status: "unchanged"
|
|
1780
|
-
});
|
|
1781
|
-
continue;
|
|
1782
|
-
}
|
|
1783
|
-
if (!options.lexicalOnly && !semanticPreparationAnnounced) {
|
|
1878
|
+
const fullyUnchanged = unchanged && (options.lexicalOnly || semanticComplete);
|
|
1879
|
+
if (!fullyUnchanged && !options.lexicalOnly && !semanticPreparationAnnounced) {
|
|
1784
1880
|
this.#writeStderr(
|
|
1785
1881
|
"Preparing the local semantic index; first use downloads a quantized model of about 24 MB.\n"
|
|
1786
1882
|
);
|
|
1787
1883
|
semanticPreparationAnnounced = true;
|
|
1788
1884
|
}
|
|
1789
|
-
|
|
1790
|
-
const saved = saveArticle(
|
|
1791
|
-
database,
|
|
1885
|
+
pending.push({
|
|
1792
1886
|
article,
|
|
1793
1887
|
existing,
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
this.#
|
|
1797
|
-
);
|
|
1798
|
-
imported.push({
|
|
1799
|
-
article: articleSummary(saved),
|
|
1800
|
-
semanticIndexed: vectors !== void 0,
|
|
1801
|
-
status: existing === void 0 ? "created" : "updated"
|
|
1888
|
+
semanticComplete,
|
|
1889
|
+
unchanged: fullyUnchanged,
|
|
1890
|
+
vectors: fullyUnchanged || options.lexicalOnly ? void 0 : await embedArticle(this.#embedder, article)
|
|
1802
1891
|
});
|
|
1803
1892
|
}
|
|
1893
|
+
database.exec("BEGIN IMMEDIATE");
|
|
1894
|
+
try {
|
|
1895
|
+
for (const item of pending) {
|
|
1896
|
+
if (item.unchanged && item.existing !== void 0) {
|
|
1897
|
+
imported.push({
|
|
1898
|
+
article: articleSummary(item.existing),
|
|
1899
|
+
semanticIndexed: item.semanticComplete,
|
|
1900
|
+
status: "unchanged"
|
|
1901
|
+
});
|
|
1902
|
+
continue;
|
|
1903
|
+
}
|
|
1904
|
+
const saved = saveArticle(
|
|
1905
|
+
database,
|
|
1906
|
+
item.article,
|
|
1907
|
+
item.existing,
|
|
1908
|
+
item.vectors,
|
|
1909
|
+
this.#now().toISOString(),
|
|
1910
|
+
this.#randomUUID,
|
|
1911
|
+
false
|
|
1912
|
+
);
|
|
1913
|
+
imported.push({
|
|
1914
|
+
article: articleSummary(saved),
|
|
1915
|
+
semanticIndexed: item.vectors !== void 0,
|
|
1916
|
+
status: item.existing === void 0 ? "created" : "updated"
|
|
1917
|
+
});
|
|
1918
|
+
}
|
|
1919
|
+
database.exec("COMMIT");
|
|
1920
|
+
} catch (error) {
|
|
1921
|
+
try {
|
|
1922
|
+
database.exec("ROLLBACK");
|
|
1923
|
+
} catch {
|
|
1924
|
+
}
|
|
1925
|
+
throw error;
|
|
1926
|
+
}
|
|
1804
1927
|
return contentKnowledgeImportResultSchema.parse({
|
|
1805
1928
|
command: "knowledge.import",
|
|
1806
1929
|
data: {
|
|
1807
1930
|
imported,
|
|
1808
|
-
model: options.lexicalOnly ? null : this.#embedder.model,
|
|
1809
1931
|
skipped
|
|
1810
1932
|
},
|
|
1811
1933
|
ok: true
|
|
@@ -1873,144 +1995,219 @@ var KnowledgeCli = class {
|
|
|
1873
1995
|
}
|
|
1874
1996
|
await this.#syncQuotes(true);
|
|
1875
1997
|
}
|
|
1876
|
-
async
|
|
1998
|
+
async #withQuoteLock(action) {
|
|
1877
1999
|
const sourcePath = quoteSourcePath(this.#homeDirectory);
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
2000
|
+
return withPrivateFileLocks([sourcePath], action).catch((error) => {
|
|
2001
|
+
if (error instanceof LocalStateError && error.failure === "busy") {
|
|
2002
|
+
throw new KnowledgeCliError(
|
|
2003
|
+
"DXC_KNOWLEDGE_BUSY",
|
|
2004
|
+
"\u91D1\u53E5\u5E93\u6B63\u5728\u88AB\u53E6\u4E00\u4E2A\u52A8\u4F5C\u66F4\u65B0\u3002",
|
|
2005
|
+
void 0,
|
|
2006
|
+
{
|
|
2007
|
+
recovery: "\u8BF7\u7B49\u5F85\u5F53\u524D\u91D1\u53E5\u52A8\u4F5C\u5B8C\u6210\u540E\u91CD\u8BD5\u540C\u4E00\u64CD\u4F5C\u3002",
|
|
2008
|
+
retryable: true
|
|
2009
|
+
}
|
|
2010
|
+
);
|
|
2011
|
+
}
|
|
2012
|
+
throw error;
|
|
2013
|
+
});
|
|
2014
|
+
}
|
|
2015
|
+
async listQuotes() {
|
|
2016
|
+
return this.#withQuoteLock(async () => {
|
|
2017
|
+
const sourcePath = quoteSourcePath(this.#homeDirectory);
|
|
2018
|
+
if (!await quoteSourceExists(sourcePath)) {
|
|
2019
|
+
await this.#initQuotes();
|
|
2020
|
+
} else {
|
|
2021
|
+
await this.#syncQuotes(true);
|
|
2022
|
+
}
|
|
2023
|
+
const source = await readQuoteSource(sourcePath);
|
|
2024
|
+
return contentKnowledgeQuoteListResultSchema.parse({
|
|
2025
|
+
command: "knowledge.quotes.list",
|
|
2026
|
+
data: { quotes: source.quotes.map(quoteRecord) },
|
|
2027
|
+
ok: true
|
|
2028
|
+
});
|
|
1888
2029
|
});
|
|
1889
2030
|
}
|
|
1890
2031
|
async addQuote(options) {
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
2032
|
+
if (options.origin !== "original" && options.origin !== "third-party") {
|
|
2033
|
+
throw new KnowledgeCliError("DXC_KNOWLEDGE_QUOTE_INVALID", "\u91D1\u53E5\u6765\u6E90\u5F52\u5C5E\u65E0\u6548\u3002", void 0, {
|
|
2034
|
+
candidates: ["original", "third-party"],
|
|
2035
|
+
expected: "\u672C\u4EBA\u539F\u521B\u6216\u7B2C\u4E09\u65B9\u6765\u6E90",
|
|
2036
|
+
field: "origin",
|
|
2037
|
+
recovery: "\u8BF7\u5148\u786E\u8BA4\u91D1\u53E5\u662F\u5426\u4E3A\u7528\u6237\u672C\u4EBA\u539F\u521B\uFF0C\u518D\u6309\u91D1\u53E5 Skill \u63D0\u4EA4\u6765\u6E90\u5F52\u5C5E\u3002"
|
|
2038
|
+
});
|
|
1894
2039
|
}
|
|
1895
|
-
const
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
2040
|
+
const origin = options.origin;
|
|
2041
|
+
return this.#withQuoteLock(async () => {
|
|
2042
|
+
const sourcePath = quoteSourcePath(this.#homeDirectory);
|
|
2043
|
+
if (!await quoteSourceExists(sourcePath)) {
|
|
2044
|
+
await this.#initQuotes();
|
|
2045
|
+
}
|
|
2046
|
+
const source = await readQuoteSource(sourcePath);
|
|
2047
|
+
const duplicate = source.quotes.find(
|
|
2048
|
+
(item) => item.status === "active" && item.text.trim() === options.text.trim()
|
|
2049
|
+
);
|
|
2050
|
+
if (duplicate !== void 0) {
|
|
2051
|
+
await this.#syncQuotes(false);
|
|
2052
|
+
return contentKnowledgeQuoteMutationResultSchema.parse({
|
|
2053
|
+
command: "knowledge.quotes.add",
|
|
2054
|
+
data: { quote: quoteRecord(duplicate), synced: true },
|
|
2055
|
+
ok: true
|
|
2056
|
+
});
|
|
2057
|
+
}
|
|
2058
|
+
const quote = quoteSourceItemSchema.safeParse({
|
|
2059
|
+
attribution: options.attribution ?? null,
|
|
2060
|
+
origin,
|
|
2061
|
+
quoteId: this.#randomUUID(),
|
|
2062
|
+
source: options.source ?? null,
|
|
2063
|
+
status: "active",
|
|
2064
|
+
tags: options.tags ?? [],
|
|
2065
|
+
text: options.text,
|
|
2066
|
+
verbatimUse: options.verbatimUse ?? (origin === "third-party" ? "needs-verification" : "original")
|
|
2067
|
+
});
|
|
2068
|
+
if (!quote.success) {
|
|
2069
|
+
throw new KnowledgeCliError("DXC_KNOWLEDGE_QUOTE_INVALID", "\u91D1\u53E5\u8F93\u5165\u65E0\u6548\u3002", void 0, {
|
|
2070
|
+
candidates: ["original", "third-party"],
|
|
2071
|
+
expected: "\u660E\u786E\u6765\u6E90\u5F52\u5C5E\uFF1B\u7B2C\u4E09\u65B9\u91D1\u53E5\u5FC5\u987B\u6709\u7F72\u540D",
|
|
2072
|
+
field: quote.error.issues[0]?.path.join(".") || "quote",
|
|
2073
|
+
recovery: "\u8BF7\u6309\u91D1\u53E5 Skill \u8865\u5145\u6765\u6E90\u5F52\u5C5E\u3001\u7F72\u540D\u548C\u4F7F\u7528\u8FB9\u754C\u3002"
|
|
2074
|
+
});
|
|
2075
|
+
}
|
|
2076
|
+
const nextQuotes = [...source.quotes, quote.data];
|
|
2077
|
+
const writtenSha256 = await writeQuoteSource(sourcePath, nextQuotes, source.contentSha256);
|
|
2078
|
+
try {
|
|
2079
|
+
await this.#syncQuotes(false);
|
|
2080
|
+
if ((await readQuoteSource(sourcePath)).contentSha256 !== writtenSha256) {
|
|
2081
|
+
throw new KnowledgeCliError(
|
|
2082
|
+
"DXC_KNOWLEDGE_REFERENCE_STALE",
|
|
2083
|
+
"\u91D1\u53E5\u5E93\u5728\u7D22\u5F15\u671F\u95F4\u88AB\u4FEE\u6539\u3002",
|
|
2084
|
+
void 0,
|
|
2085
|
+
{ recovery: "\u8BF7\u91CD\u65B0\u67E5\u770B\u91D1\u53E5\u5E93\u5E76\u786E\u8BA4\u672C\u6B21\u6536\u5F55\u7ED3\u679C\u3002" }
|
|
2086
|
+
);
|
|
2087
|
+
}
|
|
2088
|
+
} catch (error) {
|
|
2089
|
+
if (error instanceof KnowledgeCliError && error.code === "DXC_KNOWLEDGE_REFERENCE_STALE") {
|
|
2090
|
+
throw error;
|
|
2091
|
+
}
|
|
2092
|
+
await writeQuoteSource(sourcePath, source.quotes, writtenSha256);
|
|
2093
|
+
throw error;
|
|
2094
|
+
}
|
|
1901
2095
|
return contentKnowledgeQuoteMutationResultSchema.parse({
|
|
1902
2096
|
command: "knowledge.quotes.add",
|
|
1903
|
-
data: { quote: quoteRecord(
|
|
2097
|
+
data: { quote: quoteRecord(quote.data), synced: true },
|
|
1904
2098
|
ok: true
|
|
1905
2099
|
});
|
|
1906
|
-
}
|
|
1907
|
-
const quote = quoteSourceItemSchema.safeParse({
|
|
1908
|
-
attribution: options.attribution ?? null,
|
|
1909
|
-
origin: options.origin ?? "original",
|
|
1910
|
-
quoteId: this.#randomUUID(),
|
|
1911
|
-
source: options.source ?? null,
|
|
1912
|
-
status: "active",
|
|
1913
|
-
tags: options.tags ?? [],
|
|
1914
|
-
text: options.text,
|
|
1915
|
-
verbatimUse: options.verbatimUse ?? (options.origin === "third-party" ? "needs-verification" : "original")
|
|
1916
|
-
});
|
|
1917
|
-
if (!quote.success) {
|
|
1918
|
-
throw new KnowledgeCliError("DXC_KNOWLEDGE_QUOTE_INVALID", "Quote input is invalid");
|
|
1919
|
-
}
|
|
1920
|
-
const nextQuotes = [...source.quotes, quote.data];
|
|
1921
|
-
await writeQuoteSource(sourcePath, nextQuotes);
|
|
1922
|
-
try {
|
|
1923
|
-
await this.#syncQuotes(false);
|
|
1924
|
-
} catch (error) {
|
|
1925
|
-
await writeQuoteSource(sourcePath, source.quotes);
|
|
1926
|
-
throw error;
|
|
1927
|
-
}
|
|
1928
|
-
return contentKnowledgeQuoteMutationResultSchema.parse({
|
|
1929
|
-
command: "knowledge.quotes.add",
|
|
1930
|
-
data: { quote: quoteRecord(quote.data), synced: true },
|
|
1931
|
-
ok: true
|
|
1932
2100
|
});
|
|
1933
2101
|
}
|
|
1934
2102
|
async updateQuote(quoteId, options) {
|
|
1935
2103
|
if (!UUID_PATTERN.test(quoteId) || Object.keys(options).length === 0) {
|
|
1936
|
-
throw new KnowledgeCliError("DXC_KNOWLEDGE_QUOTE_INVALID", "
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
}
|
|
1942
|
-
const source = await readQuoteSource(sourcePath);
|
|
1943
|
-
const index = source.quotes.findIndex((quote) => quote.quoteId === quoteId);
|
|
1944
|
-
if (index < 0) {
|
|
1945
|
-
throw new KnowledgeCliError("DXC_KNOWLEDGE_QUOTE_INVALID", "Quote ID was not found");
|
|
1946
|
-
}
|
|
1947
|
-
const existing = source.quotes[index];
|
|
1948
|
-
if (existing === void 0) {
|
|
1949
|
-
throw new KnowledgeCliError(
|
|
1950
|
-
"DXC_KNOWLEDGE_STATE_INVALID",
|
|
1951
|
-
"Knowledge quote state is invalid"
|
|
1952
|
-
);
|
|
1953
|
-
}
|
|
1954
|
-
const updated = quoteSourceItemSchema.safeParse({
|
|
1955
|
-
...sourceQuote(existing),
|
|
1956
|
-
...options,
|
|
1957
|
-
attribution: options.attribution === void 0 ? existing.attribution ?? null : options.attribution,
|
|
1958
|
-
source: options.source === void 0 ? existing.source ?? null : options.source,
|
|
1959
|
-
tags: options.tags === void 0 ? existing.tags : options.tags,
|
|
1960
|
-
verbatimUse: options.verbatimUse ?? (options.origin === "third-party" && existing.origin !== "third-party" ? "needs-verification" : existing.verbatimUse)
|
|
1961
|
-
});
|
|
1962
|
-
if (!updated.success) {
|
|
1963
|
-
throw new KnowledgeCliError("DXC_KNOWLEDGE_QUOTE_INVALID", "Quote update is invalid");
|
|
1964
|
-
}
|
|
1965
|
-
const quotes = source.quotes.map(sourceQuote);
|
|
1966
|
-
quotes[index] = updated.data;
|
|
1967
|
-
await writeQuoteSource(sourcePath, quotes);
|
|
1968
|
-
try {
|
|
1969
|
-
await this.#syncQuotes(false);
|
|
1970
|
-
} catch (error) {
|
|
1971
|
-
await writeQuoteSource(sourcePath, source.quotes);
|
|
1972
|
-
throw error;
|
|
2104
|
+
throw new KnowledgeCliError("DXC_KNOWLEDGE_QUOTE_INVALID", "\u91D1\u53E5\u66F4\u65B0\u8F93\u5165\u65E0\u6548\u3002", void 0, {
|
|
2105
|
+
expected: "\u5F53\u524D\u91D1\u53E5 ID \u548C\u81F3\u5C11\u4E00\u4E2A\u53D8\u5316\u5B57\u6BB5",
|
|
2106
|
+
field: "quote",
|
|
2107
|
+
recovery: "\u8BF7\u91CD\u65B0\u5217\u51FA\u91D1\u53E5\u5E76\u53EA\u63D0\u4EA4\u7528\u6237\u660E\u786E\u4FEE\u6539\u7684\u5B57\u6BB5\u3002"
|
|
2108
|
+
});
|
|
1973
2109
|
}
|
|
1974
|
-
return
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
2110
|
+
return this.#withQuoteLock(async () => {
|
|
2111
|
+
const sourcePath = quoteSourcePath(this.#homeDirectory);
|
|
2112
|
+
if (!await quoteSourceExists(sourcePath)) {
|
|
2113
|
+
throw new KnowledgeCliError(
|
|
2114
|
+
"DXC_KNOWLEDGE_QUOTE_SOURCE_NOT_INITIALIZED",
|
|
2115
|
+
"\u91D1\u53E5\u5E93\u5C1A\u672A\u521B\u5EFA\u3002",
|
|
2116
|
+
void 0,
|
|
2117
|
+
{ recovery: "\u8BF7\u5148\u6536\u5F55\u7B2C\u4E00\u6761\u91D1\u53E5\uFF0C\u518D\u6267\u884C\u66F4\u65B0\u3002" }
|
|
2118
|
+
);
|
|
2119
|
+
}
|
|
2120
|
+
const source = await readQuoteSource(sourcePath);
|
|
2121
|
+
const index = source.quotes.findIndex((quote) => quote.quoteId === quoteId);
|
|
2122
|
+
if (index < 0) {
|
|
2123
|
+
throw new KnowledgeCliError(
|
|
2124
|
+
"DXC_KNOWLEDGE_QUOTE_INVALID",
|
|
2125
|
+
"\u6CA1\u6709\u627E\u5230\u8BE5\u91D1\u53E5 ID\u3002",
|
|
2126
|
+
void 0,
|
|
2127
|
+
{
|
|
2128
|
+
actual: quoteId,
|
|
2129
|
+
expected: "quotes list \u8FD4\u56DE\u7684 quoteId",
|
|
2130
|
+
field: "quoteId",
|
|
2131
|
+
recovery: "\u8BF7\u91CD\u65B0\u5217\u51FA\u91D1\u53E5\u5E76\u4F7F\u7528\u5F53\u524D ID\u3002"
|
|
2132
|
+
}
|
|
2133
|
+
);
|
|
2134
|
+
}
|
|
2135
|
+
const existing = source.quotes[index];
|
|
2136
|
+
const updated = quoteSourceItemSchema.safeParse({
|
|
2137
|
+
...sourceQuote(existing),
|
|
2138
|
+
...options,
|
|
2139
|
+
attribution: options.attribution === void 0 ? existing.attribution ?? null : options.attribution,
|
|
2140
|
+
source: options.source === void 0 ? existing.source ?? null : options.source,
|
|
2141
|
+
tags: options.tags === void 0 ? existing.tags : options.tags,
|
|
2142
|
+
verbatimUse: options.verbatimUse ?? (options.origin === "third-party" && existing.origin !== "third-party" ? "needs-verification" : existing.verbatimUse)
|
|
2143
|
+
});
|
|
2144
|
+
if (!updated.success) {
|
|
2145
|
+
throw new KnowledgeCliError("DXC_KNOWLEDGE_QUOTE_INVALID", "\u91D1\u53E5\u66F4\u65B0\u65E0\u6548\u3002", void 0, {
|
|
2146
|
+
field: updated.error.issues[0]?.path.join(".") || "quote",
|
|
2147
|
+
recovery: "\u8BF7\u8865\u9F50\u6765\u6E90\u3001\u7F72\u540D\u548C\u9010\u5B57\u4F7F\u7528\u8FB9\u754C\u540E\u91CD\u8BD5\u3002"
|
|
2148
|
+
});
|
|
2149
|
+
}
|
|
2150
|
+
const quotes = source.quotes.map(sourceQuote);
|
|
2151
|
+
quotes[index] = updated.data;
|
|
2152
|
+
const writtenSha256 = await writeQuoteSource(sourcePath, quotes, source.contentSha256);
|
|
2153
|
+
try {
|
|
2154
|
+
await this.#syncQuotes(false);
|
|
2155
|
+
} catch (error) {
|
|
2156
|
+
await writeQuoteSource(sourcePath, source.quotes, writtenSha256);
|
|
2157
|
+
throw error;
|
|
2158
|
+
}
|
|
2159
|
+
return contentKnowledgeQuoteMutationResultSchema.parse({
|
|
2160
|
+
command: "knowledge.quotes.update",
|
|
2161
|
+
data: { quote: quoteRecord(updated.data), synced: true },
|
|
2162
|
+
ok: true
|
|
2163
|
+
});
|
|
1978
2164
|
});
|
|
1979
2165
|
}
|
|
1980
2166
|
async archiveQuote(quoteId) {
|
|
1981
2167
|
if (!UUID_PATTERN.test(quoteId)) {
|
|
1982
2168
|
throw new KnowledgeCliError("DXC_KNOWLEDGE_QUOTE_INVALID", "Quote ID is invalid");
|
|
1983
2169
|
}
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
await
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2170
|
+
return this.#withQuoteLock(async () => {
|
|
2171
|
+
const sourcePath = quoteSourcePath(this.#homeDirectory);
|
|
2172
|
+
if (!await quoteSourceExists(sourcePath)) {
|
|
2173
|
+
throw new KnowledgeCliError(
|
|
2174
|
+
"DXC_KNOWLEDGE_QUOTE_SOURCE_NOT_INITIALIZED",
|
|
2175
|
+
"\u91D1\u53E5\u5E93\u5C1A\u672A\u521B\u5EFA\u3002",
|
|
2176
|
+
void 0,
|
|
2177
|
+
{ recovery: "\u65E0\u9700\u5F52\u6863\uFF1B\u5F53\u524D\u6CA1\u6709\u91D1\u53E5\u5E93\u3002" }
|
|
2178
|
+
);
|
|
2179
|
+
}
|
|
2180
|
+
const source = await readQuoteSource(sourcePath);
|
|
2181
|
+
const index = source.quotes.findIndex((quote) => quote.quoteId === quoteId);
|
|
2182
|
+
if (index < 0) {
|
|
2183
|
+
throw new KnowledgeCliError(
|
|
2184
|
+
"DXC_KNOWLEDGE_QUOTE_INVALID",
|
|
2185
|
+
"\u6CA1\u6709\u627E\u5230\u8BE5\u91D1\u53E5 ID\u3002",
|
|
2186
|
+
void 0,
|
|
2187
|
+
{
|
|
2188
|
+
actual: quoteId,
|
|
2189
|
+
expected: "quotes list \u8FD4\u56DE\u7684 quoteId",
|
|
2190
|
+
field: "quoteId",
|
|
2191
|
+
recovery: "\u8BF7\u91CD\u65B0\u5217\u51FA\u91D1\u53E5\u5E76\u4F7F\u7528\u5F53\u524D ID\u3002"
|
|
2192
|
+
}
|
|
2193
|
+
);
|
|
2194
|
+
}
|
|
2195
|
+
const existing = source.quotes[index];
|
|
2196
|
+
const archived = { ...sourceQuote(existing), status: "archived" };
|
|
2197
|
+
const quotes = source.quotes.map(sourceQuote);
|
|
2198
|
+
quotes[index] = archived;
|
|
2199
|
+
const writtenSha256 = await writeQuoteSource(sourcePath, quotes, source.contentSha256);
|
|
2200
|
+
try {
|
|
2201
|
+
await this.#syncQuotes(false);
|
|
2202
|
+
} catch (error) {
|
|
2203
|
+
await writeQuoteSource(sourcePath, source.quotes, writtenSha256);
|
|
2204
|
+
throw error;
|
|
2205
|
+
}
|
|
2206
|
+
return contentKnowledgeQuoteMutationResultSchema.parse({
|
|
2207
|
+
command: "knowledge.quotes.archive",
|
|
2208
|
+
data: { quote: quoteRecord(archived), synced: true },
|
|
2209
|
+
ok: true
|
|
2210
|
+
});
|
|
2014
2211
|
});
|
|
2015
2212
|
}
|
|
2016
2213
|
async quoteStatus() {
|
|
@@ -2021,9 +2218,7 @@ var KnowledgeCli = class {
|
|
|
2021
2218
|
data: {
|
|
2022
2219
|
activeCount: 0,
|
|
2023
2220
|
archivedCount: 0,
|
|
2024
|
-
sourceInitialized
|
|
2025
|
-
sourcePath: QUOTE_SOURCE_DISPLAY_PATH,
|
|
2026
|
-
sourceSha256: null
|
|
2221
|
+
sourceInitialized
|
|
2027
2222
|
},
|
|
2028
2223
|
ok: true
|
|
2029
2224
|
});
|
|
@@ -2083,58 +2278,89 @@ var KnowledgeCli = class {
|
|
|
2083
2278
|
database.close();
|
|
2084
2279
|
}
|
|
2085
2280
|
}
|
|
2086
|
-
async remove(
|
|
2087
|
-
|
|
2281
|
+
async remove(knowledgeRef) {
|
|
2282
|
+
const reference = decodeKnowledgeRef(knowledgeRef);
|
|
2283
|
+
if (reference.sourceType !== "history-article") {
|
|
2088
2284
|
throw new KnowledgeCliError(
|
|
2089
2285
|
"DXC_KNOWLEDGE_ARTICLE_INVALID",
|
|
2090
|
-
"
|
|
2286
|
+
"\u53EA\u6709\u5386\u53F2\u6587\u7AE0\u68C0\u7D22\u7ED3\u679C\u53EF\u4EE5\u7528\u4E8E\u5220\u9664\u6587\u7AE0\u3002",
|
|
2287
|
+
void 0,
|
|
2288
|
+
{ recovery: "\u8BF7\u91CD\u65B0\u68C0\u7D22\u5386\u53F2\u6587\u7AE0\uFF0C\u5E76\u539F\u6837\u4F7F\u7528\u76EE\u6807\u7ED3\u679C\u7684 knowledgeRef\u3002" }
|
|
2091
2289
|
);
|
|
2092
2290
|
}
|
|
2291
|
+
const articleId = reference.articleId;
|
|
2093
2292
|
if (!await databaseExists(this.#databasePath)) {
|
|
2094
2293
|
return contentKnowledgeRemoveResultSchema.parse({
|
|
2095
2294
|
command: "knowledge.remove",
|
|
2096
|
-
data: {
|
|
2295
|
+
data: { knowledgeRef, removed: false },
|
|
2097
2296
|
ok: true
|
|
2098
2297
|
});
|
|
2099
2298
|
}
|
|
2100
2299
|
const database = await openDatabase(this.#databasePath);
|
|
2101
2300
|
try {
|
|
2301
|
+
let removed = false;
|
|
2102
2302
|
database.exec("BEGIN IMMEDIATE");
|
|
2103
2303
|
try {
|
|
2304
|
+
const current = loadChunks(database).find(
|
|
2305
|
+
(chunk) => chunk.id === reference.chunkId && chunk.articleId === reference.articleId
|
|
2306
|
+
);
|
|
2307
|
+
if (current === void 0 || current.chunkSha256 !== reference.contentSha256) {
|
|
2308
|
+
throw new KnowledgeCliError(
|
|
2309
|
+
"DXC_KNOWLEDGE_REFERENCE_STALE",
|
|
2310
|
+
"\u5386\u53F2\u6587\u7AE0\u68C0\u7D22\u7ED3\u679C\u5DF2\u53D8\u5316\u3002",
|
|
2311
|
+
void 0,
|
|
2312
|
+
{ recovery: "\u8BF7\u91CD\u65B0\u68C0\u7D22\u5386\u53F2\u6587\u7AE0\uFF0C\u5E76\u8BA9\u7528\u6237\u91CD\u65B0\u9009\u62E9\u8981\u5220\u9664\u7684\u5F53\u524D\u7ED3\u679C\u3002" }
|
|
2313
|
+
);
|
|
2314
|
+
}
|
|
2104
2315
|
database.prepare("DELETE FROM chunk_search WHERE article_id = ?").run(articleId);
|
|
2105
2316
|
const result = database.prepare("DELETE FROM articles WHERE id = ?").run(articleId);
|
|
2317
|
+
removed = result.changes > 0;
|
|
2106
2318
|
database.exec("COMMIT");
|
|
2107
|
-
|
|
2108
|
-
command: "knowledge.remove",
|
|
2109
|
-
data: {
|
|
2110
|
-
articleId,
|
|
2111
|
-
removed: result.changes > 0
|
|
2112
|
-
},
|
|
2113
|
-
ok: true
|
|
2114
|
-
});
|
|
2115
|
-
} catch {
|
|
2319
|
+
} catch (error) {
|
|
2116
2320
|
database.exec("ROLLBACK");
|
|
2321
|
+
if (error instanceof KnowledgeCliError) {
|
|
2322
|
+
throw error;
|
|
2323
|
+
}
|
|
2117
2324
|
throw new KnowledgeCliError(
|
|
2118
2325
|
"DXC_KNOWLEDGE_IO_FAILED",
|
|
2119
2326
|
"Unable to remove knowledge article"
|
|
2120
2327
|
);
|
|
2121
2328
|
}
|
|
2329
|
+
return contentKnowledgeRemoveResultSchema.parse({
|
|
2330
|
+
command: "knowledge.remove",
|
|
2331
|
+
data: { knowledgeRef, removed },
|
|
2332
|
+
ok: true
|
|
2333
|
+
});
|
|
2122
2334
|
} finally {
|
|
2123
2335
|
database.close();
|
|
2124
2336
|
}
|
|
2125
2337
|
}
|
|
2126
|
-
async search(queryInput, modeInput, limitInput, choiceId) {
|
|
2338
|
+
async search(queryInput, modeInput, limitInput, choiceId, sourceFilterInput = "all") {
|
|
2127
2339
|
const query = queryInput.trim();
|
|
2128
2340
|
const modelAction = knowledgeModelChoices(
|
|
2129
2341
|
"search",
|
|
2130
|
-
sha2562(
|
|
2342
|
+
sha2562(
|
|
2343
|
+
JSON.stringify({
|
|
2344
|
+
limit: limitInput,
|
|
2345
|
+
mode: modeInput,
|
|
2346
|
+
query,
|
|
2347
|
+
sourceFilter: sourceFilterInput
|
|
2348
|
+
})
|
|
2349
|
+
)
|
|
2131
2350
|
);
|
|
2132
2351
|
const selectedMode = selectedKnowledgeMode(modelAction, choiceId);
|
|
2133
2352
|
const mode = contentKnowledgeSearchModeSchema.safeParse(
|
|
2134
2353
|
selectedMode === "lexical" ? "lexical" : modeInput
|
|
2135
2354
|
);
|
|
2136
|
-
|
|
2137
|
-
|
|
2355
|
+
const sourceFilter = contentKnowledgeSourceFilterSchema.safeParse(sourceFilterInput);
|
|
2356
|
+
if (query.length === 0 || query.length > 500 || !mode.success || !sourceFilter.success || !Number.isSafeInteger(limitInput) || limitInput < 1 || limitInput > MAXIMUM_RESULTS) {
|
|
2357
|
+
throw new KnowledgeCliError("DXC_KNOWLEDGE_QUERY_INVALID", "\u77E5\u8BC6\u68C0\u7D22\u8F93\u5165\u65E0\u6548\u3002", void 0, {
|
|
2358
|
+
actual: !mode.success ? modeInput : !sourceFilter.success ? sourceFilterInput : queryInput,
|
|
2359
|
+
candidates: !mode.success ? contentKnowledgeSearchModeSchema.options : contentKnowledgeSourceFilterSchema.options,
|
|
2360
|
+
expected: "\u6709\u6548\u67E5\u8BE2\u3001\u68C0\u7D22\u6A21\u5F0F\u3001\u6765\u6E90\u8303\u56F4\u548C 1\u201320 \u6761\u7ED3\u679C\u6570",
|
|
2361
|
+
field: !mode.success ? "mode" : !sourceFilter.success ? "source" : "query",
|
|
2362
|
+
recovery: "\u8BF7\u6309\u5BF9\u5E94 Skill \u58F0\u660E\u7684\u68C0\u7D22\u52A8\u4F5C\u4FEE\u6B63\u5931\u8D25\u5B57\u6BB5\u3002"
|
|
2363
|
+
});
|
|
2138
2364
|
}
|
|
2139
2365
|
if (!await databaseExists(this.#databasePath)) {
|
|
2140
2366
|
return contentKnowledgeSearchResultSchema.parse({
|
|
@@ -2143,15 +2369,16 @@ var KnowledgeCli = class {
|
|
|
2143
2369
|
mode: mode.data,
|
|
2144
2370
|
model: mode.data === "lexical" ? null : this.#embedder.model,
|
|
2145
2371
|
query,
|
|
2146
|
-
results: []
|
|
2372
|
+
results: [],
|
|
2373
|
+
sourceFilter: sourceFilter.data
|
|
2147
2374
|
},
|
|
2148
2375
|
ok: true
|
|
2149
2376
|
});
|
|
2150
2377
|
}
|
|
2151
2378
|
const database = await openDatabase(this.#databasePath);
|
|
2152
2379
|
try {
|
|
2153
|
-
const chunks = loadChunks(database);
|
|
2154
|
-
const quotes = loadActiveQuotes(database);
|
|
2380
|
+
const chunks = sourceFilter.data === "quotes" ? [] : loadChunks(database);
|
|
2381
|
+
const quotes = sourceFilter.data === "history" ? [] : loadActiveQuotes(database);
|
|
2155
2382
|
const usesSemantic = mode.data !== "lexical";
|
|
2156
2383
|
if (usesSemantic && (chunks.some((chunk) => chunk.embedding === null) || quotes.some((quote) => quote.embedding === null))) {
|
|
2157
2384
|
throw new KnowledgeCliError(
|
|
@@ -2182,13 +2409,13 @@ var KnowledgeCli = class {
|
|
|
2182
2409
|
command: "knowledge.search",
|
|
2183
2410
|
data: {
|
|
2184
2411
|
mode: mode.data,
|
|
2185
|
-
model: usesSemantic ? this.#embedder.model : null,
|
|
2186
2412
|
query,
|
|
2187
2413
|
results: mergeSearchResults(
|
|
2188
2414
|
fusedResults(chunks, mode.data, lexical, semantic, limitInput),
|
|
2189
2415
|
fusedQuoteResults(quotes, mode.data, quoteLexical, quoteSemantic, limitInput),
|
|
2190
2416
|
limitInput
|
|
2191
|
-
)
|
|
2417
|
+
),
|
|
2418
|
+
sourceFilter: sourceFilter.data
|
|
2192
2419
|
},
|
|
2193
2420
|
ok: true
|
|
2194
2421
|
});
|
|
@@ -2196,6 +2423,127 @@ var KnowledgeCli = class {
|
|
|
2196
2423
|
database.close();
|
|
2197
2424
|
}
|
|
2198
2425
|
}
|
|
2426
|
+
async adopt(projectId, knowledgeRef) {
|
|
2427
|
+
const payload = decodeKnowledgeRef(knowledgeRef);
|
|
2428
|
+
if (!await databaseExists(this.#databasePath)) {
|
|
2429
|
+
throw new KnowledgeCliError(
|
|
2430
|
+
"DXC_KNOWLEDGE_REFERENCE_STALE",
|
|
2431
|
+
"\u77E5\u8BC6\u5F15\u7528\u5BF9\u5E94\u7684\u672C\u5730\u7D22\u5F15\u4E0D\u5B58\u5728\u3002",
|
|
2432
|
+
void 0,
|
|
2433
|
+
{ recovery: "\u8BF7\u91CD\u65B0\u5BFC\u5165\u6216\u68C0\u7D22\u5185\u5BB9\uFF0C\u518D\u91C7\u7528\u65B0\u7684\u7ED3\u679C\u3002" }
|
|
2434
|
+
);
|
|
2435
|
+
}
|
|
2436
|
+
const database = await openDatabase(this.#databasePath);
|
|
2437
|
+
let adopted;
|
|
2438
|
+
let quoteVerbatimGuard;
|
|
2439
|
+
try {
|
|
2440
|
+
if (payload.sourceType === "history-article") {
|
|
2441
|
+
const chunk = loadChunks(database).find(
|
|
2442
|
+
(candidate) => candidate.id === payload.chunkId && candidate.articleId === payload.articleId
|
|
2443
|
+
);
|
|
2444
|
+
if (chunk === void 0 || chunk.chunkSha256 !== payload.contentSha256) {
|
|
2445
|
+
throw new KnowledgeCliError(
|
|
2446
|
+
"DXC_KNOWLEDGE_REFERENCE_STALE",
|
|
2447
|
+
"\u5386\u53F2\u6587\u7AE0\u7247\u6BB5\u5DF2\u53D8\u5316\u3002",
|
|
2448
|
+
void 0,
|
|
2449
|
+
{ recovery: "\u8BF7\u91CD\u65B0\u68C0\u7D22\u5E76\u8BA9\u7528\u6237\u91CD\u65B0\u9009\u62E9\u5F53\u524D\u7247\u6BB5\u3002" }
|
|
2450
|
+
);
|
|
2451
|
+
}
|
|
2452
|
+
adopted = contentWorkflowAdoptedKnowledgeSchema.parse({
|
|
2453
|
+
heading: chunk.heading,
|
|
2454
|
+
knowledgeRef,
|
|
2455
|
+
label: chunk.title,
|
|
2456
|
+
snippet: snippet(chunk.body),
|
|
2457
|
+
sourceType: "history-article"
|
|
2458
|
+
});
|
|
2459
|
+
} else {
|
|
2460
|
+
const quote = loadActiveQuotes(database).find(
|
|
2461
|
+
(candidate) => candidate.id === payload.quoteId
|
|
2462
|
+
);
|
|
2463
|
+
if (quote === void 0 || quote.contentSha256 !== payload.contentSha256) {
|
|
2464
|
+
throw new KnowledgeCliError(
|
|
2465
|
+
"DXC_KNOWLEDGE_REFERENCE_STALE",
|
|
2466
|
+
"\u91D1\u53E5\u5DF2\u53D8\u5316\u6216\u5DF2\u5F52\u6863\u3002",
|
|
2467
|
+
void 0,
|
|
2468
|
+
{ recovery: "\u8BF7\u91CD\u65B0\u68C0\u7D22\u5E76\u8BA9\u7528\u6237\u91CD\u65B0\u9009\u62E9\u5F53\u524D\u91D1\u53E5\u3002" }
|
|
2469
|
+
);
|
|
2470
|
+
}
|
|
2471
|
+
if (quote.verbatimUse === "do-not-use-verbatim") {
|
|
2472
|
+
throw new KnowledgeCliError(
|
|
2473
|
+
"DXC_KNOWLEDGE_REFERENCE_INVALID",
|
|
2474
|
+
"\u8BE5\u91D1\u53E5\u7981\u6B62\u91C7\u7528\u5230\u6587\u7AE0\u9879\u76EE\u3002",
|
|
2475
|
+
void 0,
|
|
2476
|
+
{ recovery: "\u8BF7\u4FDD\u7559\u5B83\u4EC5\u4F9B\u4EBA\u5DE5\u67E5\u770B\uFF0C\u6216\u91CD\u65B0\u68C0\u7D22\u5E76\u9009\u62E9\u5141\u8BB8\u91C7\u7528\u7684\u5176\u4ED6\u91D1\u53E5\u3002" }
|
|
2477
|
+
);
|
|
2478
|
+
}
|
|
2479
|
+
adopted = contentWorkflowAdoptedKnowledgeSchema.parse({
|
|
2480
|
+
attribution: quote.attribution,
|
|
2481
|
+
knowledgeRef,
|
|
2482
|
+
label: quote.attribution ?? quote.sourceLabel ?? "\u5DF2\u91C7\u7528\u91D1\u53E5",
|
|
2483
|
+
snippet: snippet(quote.text),
|
|
2484
|
+
sourceType: "quote",
|
|
2485
|
+
verbatimUse: quote.verbatimUse
|
|
2486
|
+
});
|
|
2487
|
+
if (quote.verbatimUse === "needs-verification") {
|
|
2488
|
+
quoteVerbatimGuard = quote.text;
|
|
2489
|
+
}
|
|
2490
|
+
}
|
|
2491
|
+
} finally {
|
|
2492
|
+
database.close();
|
|
2493
|
+
}
|
|
2494
|
+
const project = await new ProjectCli({
|
|
2495
|
+
currentDirectory: this.#currentDirectory,
|
|
2496
|
+
homeDirectory: this.#homeDirectory,
|
|
2497
|
+
now: this.#now
|
|
2498
|
+
}).locateByProjectId(projectId);
|
|
2499
|
+
const target = path2.join(project.directory, PROJECT_CONTEXT_FILE);
|
|
2500
|
+
return withPrivateFileLocks([target], async () => {
|
|
2501
|
+
let store = {
|
|
2502
|
+
adoptedKnowledge: [],
|
|
2503
|
+
quoteVerbatimGuards: [],
|
|
2504
|
+
schemaVersion: "1"
|
|
2505
|
+
};
|
|
2506
|
+
try {
|
|
2507
|
+
store = projectContextStoreSchema.parse(
|
|
2508
|
+
JSON.parse(await readPrivateFile(target, PROJECT_CONTEXT_MAXIMUM_BYTES))
|
|
2509
|
+
);
|
|
2510
|
+
} catch (error) {
|
|
2511
|
+
if (!(error instanceof LocalStateError && error.failure === "missing")) {
|
|
2512
|
+
throw error;
|
|
2513
|
+
}
|
|
2514
|
+
}
|
|
2515
|
+
const adoptedKnowledge = [
|
|
2516
|
+
...store.adoptedKnowledge.filter(
|
|
2517
|
+
(item) => !sameKnowledgeEntity(item.knowledgeRef, payload)
|
|
2518
|
+
),
|
|
2519
|
+
adopted
|
|
2520
|
+
].slice(-20);
|
|
2521
|
+
const quoteVerbatimGuards = [
|
|
2522
|
+
...store.quoteVerbatimGuards.filter(
|
|
2523
|
+
(item) => !sameKnowledgeEntity(item.knowledgeRef, payload)
|
|
2524
|
+
),
|
|
2525
|
+
...quoteVerbatimGuard === void 0 ? [] : [{ knowledgeRef, text: quoteVerbatimGuard }]
|
|
2526
|
+
].slice(-20);
|
|
2527
|
+
await writePrivateJson(target, {
|
|
2528
|
+
adoptedKnowledge,
|
|
2529
|
+
quoteVerbatimGuards,
|
|
2530
|
+
schemaVersion: "1"
|
|
2531
|
+
});
|
|
2532
|
+
return contentKnowledgeAdoptResultSchema.parse({
|
|
2533
|
+
command: "knowledge.adopt",
|
|
2534
|
+
data: { adopted, projectId: project.manifest.projectId },
|
|
2535
|
+
ok: true
|
|
2536
|
+
});
|
|
2537
|
+
}).catch((error) => {
|
|
2538
|
+
if (error instanceof LocalStateError && error.failure === "busy") {
|
|
2539
|
+
throw new KnowledgeCliError("DXC_KNOWLEDGE_BUSY", "\u9879\u76EE\u77E5\u8BC6\u4E0A\u4E0B\u6587\u6B63\u5728\u66F4\u65B0\u3002", void 0, {
|
|
2540
|
+
recovery: "\u8BF7\u7B49\u5F85\u5F53\u524D\u91C7\u7528\u52A8\u4F5C\u5B8C\u6210\u540E\u91CD\u8BD5\u540C\u4E00 knowledgeRef\u3002",
|
|
2541
|
+
retryable: true
|
|
2542
|
+
});
|
|
2543
|
+
}
|
|
2544
|
+
throw error;
|
|
2545
|
+
});
|
|
2546
|
+
}
|
|
2199
2547
|
async status() {
|
|
2200
2548
|
let articleCount = 0;
|
|
2201
2549
|
let chunkCount = 0;
|
|
@@ -2203,9 +2551,7 @@ var KnowledgeCli = class {
|
|
|
2203
2551
|
let quoteSummary = {
|
|
2204
2552
|
activeCount: 0,
|
|
2205
2553
|
archivedCount: 0,
|
|
2206
|
-
sourceInitialized: await quoteSourceExists(quoteSourcePath(this.#homeDirectory))
|
|
2207
|
-
sourcePath: QUOTE_SOURCE_DISPLAY_PATH,
|
|
2208
|
-
sourceSha256: null
|
|
2554
|
+
sourceInitialized: await quoteSourceExists(quoteSourcePath(this.#homeDirectory))
|
|
2209
2555
|
};
|
|
2210
2556
|
if (await databaseExists(this.#databasePath)) {
|
|
2211
2557
|
const database = await openDatabase(this.#databasePath);
|
|
@@ -2251,13 +2597,6 @@ var KnowledgeCli = class {
|
|
|
2251
2597
|
data: {
|
|
2252
2598
|
articleCount,
|
|
2253
2599
|
chunkCount,
|
|
2254
|
-
databasePath: DATABASE_DISPLAY_PATH,
|
|
2255
|
-
model: contentKnowledgeModelSchema.parse({
|
|
2256
|
-
dimensions: CONTENT_KNOWLEDGE_EMBEDDING_DIMENSIONS,
|
|
2257
|
-
id: CONTENT_KNOWLEDGE_EMBEDDING_MODEL,
|
|
2258
|
-
quantization: CONTENT_KNOWLEDGE_EMBEDDING_QUANTIZATION,
|
|
2259
|
-
revision: CONTENT_KNOWLEDGE_EMBEDDING_REVISION
|
|
2260
|
-
}),
|
|
2261
2600
|
modelCached: await this.#isModelCached(),
|
|
2262
2601
|
semanticIndexedChunkCount,
|
|
2263
2602
|
quotes: quoteSummary
|