@deployxai/dxc 0.2.5 → 0.3.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/README.md +13 -4
- package/dist/chunks/{chunk-JB5USZ4F.js → chunk-6JNQZHAQ.js} +245 -56
- package/dist/chunks/{knowledge-YPR7JKUT.js → knowledge-JCYMCMSP.js} +140 -65
- package/dist/index.js +1976 -937
- package/package.json +1 -1
- package/skills/dxc-article-outline/SKILL.md +7 -20
- package/skills/dxc-article-write/SKILL.md +7 -35
- package/skills/dxc-content-brief/SKILL.md +8 -26
- package/skills/dxc-content-review/SKILL.md +7 -30
- package/skills/dxc-content-workflow/SKILL.md +20 -109
- package/skills/dxc-content-workflow/references/onboarding-questions.md +4 -174
- package/skills/dxc-content-workflow/references/stages.md +6 -79
- package/skills/dxc-knowledge/SKILL.md +11 -25
- package/skills/dxc-memory/SKILL.md +10 -25
- package/skills/dxc-profile/SKILL.md +11 -35
- package/skills/dxc-project-overview/SKILL.md +7 -18
- package/skills/dxc-quote-curator/SKILL.md +10 -28
- package/skills/dxc-research/SKILL.md +8 -34
- package/skills/dxc-title-write/SKILL.md +8 -27
- package/skills/dxc-visual-plan/SKILL.md +17 -37
- package/skills/dxc-wechat-publisher/SKILL.md +11 -29
|
@@ -9,11 +9,9 @@ import {
|
|
|
9
9
|
LocalStateError,
|
|
10
10
|
contentKnowledgeImportResultSchema,
|
|
11
11
|
contentKnowledgeModelSchema,
|
|
12
|
-
contentKnowledgeQuoteInitResultSchema,
|
|
13
12
|
contentKnowledgeQuoteListResultSchema,
|
|
14
13
|
contentKnowledgeQuoteMutationResultSchema,
|
|
15
14
|
contentKnowledgeQuoteStatusResultSchema,
|
|
16
|
-
contentKnowledgeQuoteSyncResultSchema,
|
|
17
15
|
contentKnowledgeRemoveResultSchema,
|
|
18
16
|
contentKnowledgeSearchModeSchema,
|
|
19
17
|
contentKnowledgeSearchResultSchema,
|
|
@@ -25,7 +23,7 @@ import {
|
|
|
25
23
|
resolveUserPath,
|
|
26
24
|
writePrivateBuffer,
|
|
27
25
|
writePrivateJson
|
|
28
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-6JNQZHAQ.js";
|
|
29
27
|
|
|
30
28
|
// apps/cli/src/knowledge.ts
|
|
31
29
|
import { createHash as createHash2, randomUUID } from "node:crypto";
|
|
@@ -351,12 +349,14 @@ var MAXIMUM_DIRECTORY_ARTICLES = 1e3;
|
|
|
351
349
|
var MAXIMUM_DIRECTORY_DEPTH = 32;
|
|
352
350
|
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;
|
|
353
351
|
var KnowledgeCliError = class extends Error {
|
|
354
|
-
constructor(code, message) {
|
|
352
|
+
constructor(code, message, details) {
|
|
355
353
|
super(message);
|
|
356
354
|
this.code = code;
|
|
355
|
+
this.details = details;
|
|
357
356
|
this.name = "KnowledgeCliError";
|
|
358
357
|
}
|
|
359
358
|
code;
|
|
359
|
+
details;
|
|
360
360
|
};
|
|
361
361
|
var quoteMetadataValueSchema = z.string().trim().min(1).max(300).refine((value) => !/[\r\n]/u.test(value) && value !== "\uFF08\u65E0\uFF09", {
|
|
362
362
|
message: "quote metadata must stay on one line"
|
|
@@ -426,6 +426,39 @@ function skippedArticle(error, inputPath) {
|
|
|
426
426
|
function sha2562(value) {
|
|
427
427
|
return createHash2("sha256").update(value).digest("hex");
|
|
428
428
|
}
|
|
429
|
+
function knowledgeModelChoices(operation, inputFingerprint) {
|
|
430
|
+
const choiceId = (mode) => {
|
|
431
|
+
const payload = Buffer.from(
|
|
432
|
+
JSON.stringify({ inputFingerprint, mode, operation, version: 1 }),
|
|
433
|
+
"utf8"
|
|
434
|
+
).toString("base64url");
|
|
435
|
+
return `knowledge-choice1_${payload}.${sha2562(payload).slice(0, 32)}`;
|
|
436
|
+
};
|
|
437
|
+
return {
|
|
438
|
+
choices: [
|
|
439
|
+
{ choiceId: choiceId("retry-semantic"), label: "\u91CD\u8BD5\u672C\u5730\u8BED\u4E49\u6A21\u578B" },
|
|
440
|
+
{ choiceId: choiceId("lexical"), label: "\u672C\u6B21\u4EC5\u4F7F\u7528\u5173\u952E\u8BCD" }
|
|
441
|
+
],
|
|
442
|
+
purpose: "knowledge-model-unavailable",
|
|
443
|
+
type: "select-choice"
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
function selectedKnowledgeMode(action, choiceId) {
|
|
447
|
+
if (choiceId === void 0) {
|
|
448
|
+
return "default";
|
|
449
|
+
}
|
|
450
|
+
const selected = action.choices.find((choice) => choice.choiceId === choiceId);
|
|
451
|
+
if (selected === void 0) {
|
|
452
|
+
throw new KnowledgeCliError(
|
|
453
|
+
"DXC_KNOWLEDGE_QUERY_INVALID",
|
|
454
|
+
"Knowledge choice does not belong to the current operation"
|
|
455
|
+
);
|
|
456
|
+
}
|
|
457
|
+
return selected.label === "\u672C\u6B21\u4EC5\u4F7F\u7528\u5173\u952E\u8BCD" ? "lexical" : "retry-semantic";
|
|
458
|
+
}
|
|
459
|
+
function knowledgeModelUnavailable(message, action, code) {
|
|
460
|
+
return new KnowledgeCliError(code, message, { nextAction: action });
|
|
461
|
+
}
|
|
429
462
|
function normalizedMarkdown(value) {
|
|
430
463
|
return value.replaceAll("\r\n", "\n").replaceAll("\r", "\n").trim();
|
|
431
464
|
}
|
|
@@ -1787,44 +1820,65 @@ var KnowledgeCli = class {
|
|
|
1787
1820
|
lexicalOnly
|
|
1788
1821
|
});
|
|
1789
1822
|
}
|
|
1790
|
-
async
|
|
1823
|
+
async importSource(source, lexicalOnly, choiceId) {
|
|
1824
|
+
const target = resolveUserPath({
|
|
1825
|
+
currentDirectory: this.#currentDirectory,
|
|
1826
|
+
homeDirectory: this.#homeDirectory,
|
|
1827
|
+
input: source
|
|
1828
|
+
});
|
|
1829
|
+
let metadata;
|
|
1830
|
+
try {
|
|
1831
|
+
metadata = await lstat(target);
|
|
1832
|
+
} catch {
|
|
1833
|
+
throw new KnowledgeCliError(
|
|
1834
|
+
"DXC_KNOWLEDGE_INPUT_NOT_FOUND",
|
|
1835
|
+
"Knowledge import source was not found"
|
|
1836
|
+
);
|
|
1837
|
+
}
|
|
1838
|
+
if (metadata.isSymbolicLink()) {
|
|
1839
|
+
throw new KnowledgeCliError(
|
|
1840
|
+
"DXC_KNOWLEDGE_INPUT_NOT_FOUND",
|
|
1841
|
+
"Knowledge import source must not be a symbolic link"
|
|
1842
|
+
);
|
|
1843
|
+
}
|
|
1844
|
+
const action = knowledgeModelChoices("import", sha2562(target));
|
|
1845
|
+
const selectedMode = selectedKnowledgeMode(action, choiceId);
|
|
1846
|
+
const effectiveLexicalOnly = selectedMode === "lexical" || selectedMode === "default" && lexicalOnly;
|
|
1847
|
+
try {
|
|
1848
|
+
if (metadata.isDirectory()) {
|
|
1849
|
+
return await this.importDirectory(target, effectiveLexicalOnly);
|
|
1850
|
+
}
|
|
1851
|
+
if (metadata.isFile()) {
|
|
1852
|
+
return await this.importArticles({ files: [target], lexicalOnly: effectiveLexicalOnly });
|
|
1853
|
+
}
|
|
1854
|
+
throw new KnowledgeCliError(
|
|
1855
|
+
"DXC_KNOWLEDGE_INPUT_NOT_FOUND",
|
|
1856
|
+
"Knowledge import source must be a file or directory"
|
|
1857
|
+
);
|
|
1858
|
+
} catch (error) {
|
|
1859
|
+
if (error instanceof KnowledgeCliError && error.code === "DXC_KNOWLEDGE_MODEL_FAILED" && !effectiveLexicalOnly) {
|
|
1860
|
+
throw knowledgeModelUnavailable(error.message, action, error.code);
|
|
1861
|
+
}
|
|
1862
|
+
throw error;
|
|
1863
|
+
}
|
|
1864
|
+
}
|
|
1865
|
+
async #initQuotes() {
|
|
1791
1866
|
const sourcePath = quoteSourcePath(this.#homeDirectory);
|
|
1792
1867
|
const exists = await quoteSourceExists(sourcePath);
|
|
1793
1868
|
if (!exists) {
|
|
1794
1869
|
const legacyPath = legacyQuoteSourcePath(this.#homeDirectory);
|
|
1795
1870
|
const legacyExists = await quoteSourceExists(legacyPath);
|
|
1796
|
-
const quotes = legacyExists ? (await readQuoteSource(legacyPath, true)).quotes : [
|
|
1797
|
-
{
|
|
1798
|
-
quoteId: this.#randomUUID(),
|
|
1799
|
-
status: "active",
|
|
1800
|
-
text: "\u628A\u8FD9\u53E5\u66FF\u6362\u6210\u4F60\u81EA\u5DF1\u7684\u91D1\u53E5\uFF1B\u91D1\u53E5 ID \u4E00\u65E6\u521B\u5EFA\u5C31\u4E0D\u8981\u4FEE\u6539\u3002",
|
|
1801
|
-
tags: ["\u793A\u4F8B"],
|
|
1802
|
-
source: "\u4E2A\u4EBA\u539F\u521B",
|
|
1803
|
-
origin: "original",
|
|
1804
|
-
attribution: null,
|
|
1805
|
-
verbatimUse: "original"
|
|
1806
|
-
}
|
|
1807
|
-
];
|
|
1871
|
+
const quotes = legacyExists ? (await readQuoteSource(legacyPath, true)).quotes : [];
|
|
1808
1872
|
await writeQuoteSource(sourcePath, quotes);
|
|
1809
1873
|
}
|
|
1810
|
-
|
|
1811
|
-
try {
|
|
1812
|
-
return contentKnowledgeQuoteInitResultSchema.parse({
|
|
1813
|
-
command: "knowledge.quotes.init",
|
|
1814
|
-
data: { ...quoteSourceSummary(database, true), created: !exists },
|
|
1815
|
-
ok: true
|
|
1816
|
-
});
|
|
1817
|
-
} finally {
|
|
1818
|
-
database.close();
|
|
1819
|
-
}
|
|
1874
|
+
await this.#syncQuotes(true);
|
|
1820
1875
|
}
|
|
1821
1876
|
async listQuotes() {
|
|
1822
1877
|
const sourcePath = quoteSourcePath(this.#homeDirectory);
|
|
1823
1878
|
if (!await quoteSourceExists(sourcePath)) {
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
);
|
|
1879
|
+
await this.#initQuotes();
|
|
1880
|
+
} else {
|
|
1881
|
+
await this.#syncQuotes(true);
|
|
1828
1882
|
}
|
|
1829
1883
|
const source = await readQuoteSource(sourcePath);
|
|
1830
1884
|
return contentKnowledgeQuoteListResultSchema.parse({
|
|
@@ -1836,12 +1890,20 @@ var KnowledgeCli = class {
|
|
|
1836
1890
|
async addQuote(options) {
|
|
1837
1891
|
const sourcePath = quoteSourcePath(this.#homeDirectory);
|
|
1838
1892
|
if (!await quoteSourceExists(sourcePath)) {
|
|
1839
|
-
|
|
1840
|
-
"DXC_KNOWLEDGE_QUOTE_SOURCE_NOT_INITIALIZED",
|
|
1841
|
-
"Quote source file is not initialized; run knowledge quotes init first"
|
|
1842
|
-
);
|
|
1893
|
+
await this.#initQuotes();
|
|
1843
1894
|
}
|
|
1844
1895
|
const source = await readQuoteSource(sourcePath);
|
|
1896
|
+
const duplicate = source.quotes.find(
|
|
1897
|
+
(item) => item.status === "active" && item.text.trim() === options.text.trim()
|
|
1898
|
+
);
|
|
1899
|
+
if (duplicate !== void 0) {
|
|
1900
|
+
await this.#syncQuotes(false);
|
|
1901
|
+
return contentKnowledgeQuoteMutationResultSchema.parse({
|
|
1902
|
+
command: "knowledge.quotes.add",
|
|
1903
|
+
data: { quote: quoteRecord(duplicate), synced: true },
|
|
1904
|
+
ok: true
|
|
1905
|
+
});
|
|
1906
|
+
}
|
|
1845
1907
|
const quote = quoteSourceItemSchema.safeParse({
|
|
1846
1908
|
attribution: options.attribution ?? null,
|
|
1847
1909
|
origin: options.origin ?? "original",
|
|
@@ -1855,10 +1917,17 @@ var KnowledgeCli = class {
|
|
|
1855
1917
|
if (!quote.success) {
|
|
1856
1918
|
throw new KnowledgeCliError("DXC_KNOWLEDGE_QUOTE_INVALID", "Quote input is invalid");
|
|
1857
1919
|
}
|
|
1858
|
-
|
|
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
|
+
}
|
|
1859
1928
|
return contentKnowledgeQuoteMutationResultSchema.parse({
|
|
1860
1929
|
command: "knowledge.quotes.add",
|
|
1861
|
-
data: {
|
|
1930
|
+
data: { quote: quoteRecord(quote.data), synced: true },
|
|
1862
1931
|
ok: true
|
|
1863
1932
|
});
|
|
1864
1933
|
}
|
|
@@ -1868,10 +1937,7 @@ var KnowledgeCli = class {
|
|
|
1868
1937
|
}
|
|
1869
1938
|
const sourcePath = quoteSourcePath(this.#homeDirectory);
|
|
1870
1939
|
if (!await quoteSourceExists(sourcePath)) {
|
|
1871
|
-
|
|
1872
|
-
"DXC_KNOWLEDGE_QUOTE_SOURCE_NOT_INITIALIZED",
|
|
1873
|
-
"Quote source file is not initialized; run knowledge quotes init first"
|
|
1874
|
-
);
|
|
1940
|
+
await this.#initQuotes();
|
|
1875
1941
|
}
|
|
1876
1942
|
const source = await readQuoteSource(sourcePath);
|
|
1877
1943
|
const index = source.quotes.findIndex((quote) => quote.quoteId === quoteId);
|
|
@@ -1899,9 +1965,15 @@ var KnowledgeCli = class {
|
|
|
1899
1965
|
const quotes = source.quotes.map(sourceQuote);
|
|
1900
1966
|
quotes[index] = updated.data;
|
|
1901
1967
|
await writeQuoteSource(sourcePath, quotes);
|
|
1968
|
+
try {
|
|
1969
|
+
await this.#syncQuotes(false);
|
|
1970
|
+
} catch (error) {
|
|
1971
|
+
await writeQuoteSource(sourcePath, source.quotes);
|
|
1972
|
+
throw error;
|
|
1973
|
+
}
|
|
1902
1974
|
return contentKnowledgeQuoteMutationResultSchema.parse({
|
|
1903
1975
|
command: "knowledge.quotes.update",
|
|
1904
|
-
data: {
|
|
1976
|
+
data: { quote: quoteRecord(updated.data), synced: true },
|
|
1905
1977
|
ok: true
|
|
1906
1978
|
});
|
|
1907
1979
|
}
|
|
@@ -1911,10 +1983,7 @@ var KnowledgeCli = class {
|
|
|
1911
1983
|
}
|
|
1912
1984
|
const sourcePath = quoteSourcePath(this.#homeDirectory);
|
|
1913
1985
|
if (!await quoteSourceExists(sourcePath)) {
|
|
1914
|
-
|
|
1915
|
-
"DXC_KNOWLEDGE_QUOTE_SOURCE_NOT_INITIALIZED",
|
|
1916
|
-
"Quote source file is not initialized; run knowledge quotes init first"
|
|
1917
|
-
);
|
|
1986
|
+
await this.#initQuotes();
|
|
1918
1987
|
}
|
|
1919
1988
|
const source = await readQuoteSource(sourcePath);
|
|
1920
1989
|
const index = source.quotes.findIndex((quote) => quote.quoteId === quoteId);
|
|
@@ -1932,9 +2001,15 @@ var KnowledgeCli = class {
|
|
|
1932
2001
|
const quotes = source.quotes.map(sourceQuote);
|
|
1933
2002
|
quotes[index] = archived;
|
|
1934
2003
|
await writeQuoteSource(sourcePath, quotes);
|
|
2004
|
+
try {
|
|
2005
|
+
await this.#syncQuotes(false);
|
|
2006
|
+
} catch (error) {
|
|
2007
|
+
await writeQuoteSource(sourcePath, source.quotes);
|
|
2008
|
+
throw error;
|
|
2009
|
+
}
|
|
1935
2010
|
return contentKnowledgeQuoteMutationResultSchema.parse({
|
|
1936
2011
|
command: "knowledge.quotes.archive",
|
|
1937
|
-
data: {
|
|
2012
|
+
data: { quote: quoteRecord(archived), synced: true },
|
|
1938
2013
|
ok: true
|
|
1939
2014
|
});
|
|
1940
2015
|
}
|
|
@@ -1964,12 +2039,12 @@ var KnowledgeCli = class {
|
|
|
1964
2039
|
database.close();
|
|
1965
2040
|
}
|
|
1966
2041
|
}
|
|
1967
|
-
async syncQuotes(lexicalOnly) {
|
|
2042
|
+
async #syncQuotes(lexicalOnly) {
|
|
1968
2043
|
const sourcePath = quoteSourcePath(this.#homeDirectory);
|
|
1969
2044
|
if (!await quoteSourceExists(sourcePath)) {
|
|
1970
2045
|
throw new KnowledgeCliError(
|
|
1971
2046
|
"DXC_KNOWLEDGE_QUOTE_SOURCE_NOT_INITIALIZED",
|
|
1972
|
-
"Quote source file is not initialized
|
|
2047
|
+
"Quote source file is not initialized"
|
|
1973
2048
|
);
|
|
1974
2049
|
}
|
|
1975
2050
|
if (!lexicalOnly) {
|
|
@@ -1996,7 +2071,7 @@ var KnowledgeCli = class {
|
|
|
1996
2071
|
}
|
|
1997
2072
|
}
|
|
1998
2073
|
}
|
|
1999
|
-
|
|
2074
|
+
syncQuotes(
|
|
2000
2075
|
database,
|
|
2001
2076
|
source.quotes,
|
|
2002
2077
|
source.contentSha256,
|
|
@@ -2004,15 +2079,6 @@ var KnowledgeCli = class {
|
|
|
2004
2079
|
this.#now().toISOString(),
|
|
2005
2080
|
unchanged
|
|
2006
2081
|
);
|
|
2007
|
-
return contentKnowledgeQuoteSyncResultSchema.parse({
|
|
2008
|
-
command: "knowledge.quotes.sync",
|
|
2009
|
-
data: {
|
|
2010
|
-
...quoteSourceSummary(database, true),
|
|
2011
|
-
model: lexicalOnly ? null : this.#embedder.model,
|
|
2012
|
-
status
|
|
2013
|
-
},
|
|
2014
|
-
ok: true
|
|
2015
|
-
});
|
|
2016
2082
|
} finally {
|
|
2017
2083
|
database.close();
|
|
2018
2084
|
}
|
|
@@ -2057,9 +2123,16 @@ var KnowledgeCli = class {
|
|
|
2057
2123
|
database.close();
|
|
2058
2124
|
}
|
|
2059
2125
|
}
|
|
2060
|
-
async search(queryInput, modeInput, limitInput) {
|
|
2126
|
+
async search(queryInput, modeInput, limitInput, choiceId) {
|
|
2061
2127
|
const query = queryInput.trim();
|
|
2062
|
-
const
|
|
2128
|
+
const modelAction = knowledgeModelChoices(
|
|
2129
|
+
"search",
|
|
2130
|
+
sha2562(JSON.stringify({ limit: limitInput, mode: modeInput, query }))
|
|
2131
|
+
);
|
|
2132
|
+
const selectedMode = selectedKnowledgeMode(modelAction, choiceId);
|
|
2133
|
+
const mode = contentKnowledgeSearchModeSchema.safeParse(
|
|
2134
|
+
selectedMode === "lexical" ? "lexical" : modeInput
|
|
2135
|
+
);
|
|
2063
2136
|
if (query.length === 0 || query.length > 500 || !mode.success || !Number.isSafeInteger(limitInput) || limitInput < 1 || limitInput > MAXIMUM_RESULTS) {
|
|
2064
2137
|
throw new KnowledgeCliError("DXC_KNOWLEDGE_QUERY_INVALID", "Knowledge query is invalid");
|
|
2065
2138
|
}
|
|
@@ -2083,7 +2156,8 @@ var KnowledgeCli = class {
|
|
|
2083
2156
|
if (usesSemantic && (chunks.some((chunk) => chunk.embedding === null) || quotes.some((quote) => quote.embedding === null))) {
|
|
2084
2157
|
throw new KnowledgeCliError(
|
|
2085
2158
|
"DXC_KNOWLEDGE_SEMANTIC_NOT_READY",
|
|
2086
|
-
"All active knowledge items must have a semantic index before hybrid search"
|
|
2159
|
+
"All active knowledge items must have a semantic index before hybrid search",
|
|
2160
|
+
{ nextAction: modelAction }
|
|
2087
2161
|
);
|
|
2088
2162
|
}
|
|
2089
2163
|
const lexical = mode.data === "semantic" ? [] : lexicalRanking(database, query);
|
|
@@ -2095,9 +2169,10 @@ var KnowledgeCli = class {
|
|
|
2095
2169
|
try {
|
|
2096
2170
|
queryVector = await this.#embedder.embedQuery(query);
|
|
2097
2171
|
} catch {
|
|
2098
|
-
throw
|
|
2099
|
-
"
|
|
2100
|
-
|
|
2172
|
+
throw knowledgeModelUnavailable(
|
|
2173
|
+
"Local semantic model could not process the query",
|
|
2174
|
+
modelAction,
|
|
2175
|
+
"DXC_KNOWLEDGE_MODEL_FAILED"
|
|
2101
2176
|
);
|
|
2102
2177
|
}
|
|
2103
2178
|
semantic = semanticRanking(chunks, queryVector);
|