@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
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { createRequire as __dxcCreateRequire } from "node:module"; const require = __dxcCreateRequire(import.meta.url);
|
|
3
3
|
import {
|
|
4
4
|
CONTENT_ARTIFACT_KINDS,
|
|
5
|
-
|
|
5
|
+
CONTENT_STAGE_DEFINITIONS,
|
|
6
6
|
CONTENT_WORKFLOW_ID,
|
|
7
7
|
LocalStateError,
|
|
8
8
|
__commonJS,
|
|
@@ -15,15 +15,14 @@ import {
|
|
|
15
15
|
articleBundleSchema,
|
|
16
16
|
contentMemoryAddResultSchema,
|
|
17
17
|
contentMemoryArchiveResultSchema,
|
|
18
|
+
contentMemoryCorrectResultSchema,
|
|
18
19
|
contentMemoryInputSchema,
|
|
19
20
|
contentMemoryListResultSchema,
|
|
20
21
|
contentMemoryStoreSchema,
|
|
21
22
|
contentProfileInputSchema,
|
|
22
|
-
contentProfileSaveResultSchema,
|
|
23
23
|
contentProfileSchema,
|
|
24
|
+
contentProfileSessionResultSchema,
|
|
24
25
|
contentProfileStatusResultSchema,
|
|
25
|
-
contentProfileUpdateInputSchema,
|
|
26
|
-
contentProfileUpdateResultSchema,
|
|
27
26
|
contentProjectIndexSchema,
|
|
28
27
|
contentProjectManifestSchema,
|
|
29
28
|
createDeviceBindingSessionResponseSchema,
|
|
@@ -38,6 +37,7 @@ import {
|
|
|
38
37
|
proveDeviceBindingSessionResponseSchema,
|
|
39
38
|
publishingApprovalSchema,
|
|
40
39
|
publishingArticleSchema,
|
|
40
|
+
publishingDraftAttentionDiagnosticsSchema,
|
|
41
41
|
publishingDraftIntentResponseSchema,
|
|
42
42
|
publishingPreviewLinkSchema,
|
|
43
43
|
publishingPreviewSelectionStateSchema,
|
|
@@ -52,7 +52,7 @@ import {
|
|
|
52
52
|
wechatRenderResultSchema,
|
|
53
53
|
writePrivateBuffer,
|
|
54
54
|
writePrivateJson
|
|
55
|
-
} from "./chunks/chunk-
|
|
55
|
+
} from "./chunks/chunk-6JNQZHAQ.js";
|
|
56
56
|
|
|
57
57
|
// node_modules/.pnpm/pino-std-serializers@7.1.0/node_modules/pino-std-serializers/lib/err-helpers.js
|
|
58
58
|
var require_err_helpers = __commonJS({
|
|
@@ -1306,7 +1306,7 @@ var require_sonic_boom = __commonJS({
|
|
|
1306
1306
|
if (!(this instanceof SonicBoom)) {
|
|
1307
1307
|
return new SonicBoom(opts);
|
|
1308
1308
|
}
|
|
1309
|
-
let { fd, dest, minLength, maxLength, maxWrite, periodicFlush, sync, append: append2 = true, mkdir:
|
|
1309
|
+
let { fd, dest, minLength, maxLength, maxWrite, periodicFlush, sync, append: append2 = true, mkdir: mkdir6, retryEAGAIN, fsync, contentMode, mode } = opts || {};
|
|
1310
1310
|
fd = fd || dest;
|
|
1311
1311
|
this._len = 0;
|
|
1312
1312
|
this.fd = -1;
|
|
@@ -1331,7 +1331,7 @@ var require_sonic_boom = __commonJS({
|
|
|
1331
1331
|
this.append = append2 || false;
|
|
1332
1332
|
this.mode = mode;
|
|
1333
1333
|
this.retryEAGAIN = retryEAGAIN || (() => true);
|
|
1334
|
-
this.mkdir =
|
|
1334
|
+
this.mkdir = mkdir6 || false;
|
|
1335
1335
|
let fsWriteSync;
|
|
1336
1336
|
let fsWrite;
|
|
1337
1337
|
if (contentMode === kContentModeBuffer) {
|
|
@@ -23266,7 +23266,7 @@ import os3 from "node:os";
|
|
|
23266
23266
|
// apps/cli/package.json
|
|
23267
23267
|
var package_default = {
|
|
23268
23268
|
name: "@dxc/cli",
|
|
23269
|
-
version: "0.
|
|
23269
|
+
version: "0.3.0",
|
|
23270
23270
|
private: true,
|
|
23271
23271
|
type: "module",
|
|
23272
23272
|
bin: {
|
|
@@ -26711,13 +26711,78 @@ async function runDoctor(runtime) {
|
|
|
26711
26711
|
|
|
26712
26712
|
// apps/cli/src/profile.ts
|
|
26713
26713
|
import { randomUUID } from "node:crypto";
|
|
26714
|
-
import {
|
|
26714
|
+
import { unlink } from "node:fs/promises";
|
|
26715
26715
|
import path2 from "node:path";
|
|
26716
26716
|
var PROFILE_DISPLAY_PATH = "~/.dxc/content-profile.json";
|
|
26717
26717
|
var MEMORY_DISPLAY_PATH = "~/.dxc/content-memory.json";
|
|
26718
26718
|
var USER_MEMORY_DISPLAY_PATH = "~/.dxc/USER.md";
|
|
26719
26719
|
var PROFILE_MAXIMUM_BYTES = 64 * 1024;
|
|
26720
26720
|
var MEMORY_MAXIMUM_BYTES = 128 * 1024;
|
|
26721
|
+
var PROFILE_SESSION_MAXIMUM_BYTES = 32 * 1024;
|
|
26722
|
+
var PROFILE_QUESTIONS = [
|
|
26723
|
+
{
|
|
26724
|
+
choices: [
|
|
26725
|
+
{ choiceId: "profile_creator.expert", label: "\u4E2A\u4EBA\u4E13\u5BB6\u6216\u987E\u95EE" },
|
|
26726
|
+
{ choiceId: "profile_creator.creator", label: "\u804C\u4E1A\u5185\u5BB9\u521B\u4F5C\u8005" },
|
|
26727
|
+
{ choiceId: "profile_creator.brand", label: "\u54C1\u724C\u6216\u4F01\u4E1A\u5185\u5BB9\u56E2\u961F" },
|
|
26728
|
+
{ choiceId: "profile_creator.educator", label: "\u6559\u80B2\u6216\u57F9\u8BAD\u8005" }
|
|
26729
|
+
],
|
|
26730
|
+
inputType: "single-choice",
|
|
26731
|
+
prompt: "\u8BF7\u9009\u62E9\u6700\u7B26\u5408\u4F60\u7684\u535A\u4E3B\u8EAB\u4EFD\u3002",
|
|
26732
|
+
questionId: "creator-role"
|
|
26733
|
+
},
|
|
26734
|
+
{
|
|
26735
|
+
choices: [],
|
|
26736
|
+
inputType: "text",
|
|
26737
|
+
prompt: "\u8BF7\u8F93\u5165\u5E0C\u671B\u8BFB\u8005\u770B\u5230\u7684\u540D\u79F0\u6216\u7B14\u540D\u3002",
|
|
26738
|
+
questionId: "display-name"
|
|
26739
|
+
},
|
|
26740
|
+
{
|
|
26741
|
+
choices: [
|
|
26742
|
+
{ choiceId: "profile_domain.business", label: "\u5546\u4E1A\u4E0E\u521B\u4E1A" },
|
|
26743
|
+
{ choiceId: "profile_domain.technology", label: "\u6280\u672F\u4E0E AI" },
|
|
26744
|
+
{ choiceId: "profile_domain.career", label: "\u804C\u573A\u4E0E\u4E2A\u4EBA\u6210\u957F" },
|
|
26745
|
+
{ choiceId: "profile_domain.lifestyle", label: "\u751F\u6D3B\u65B9\u5F0F" },
|
|
26746
|
+
{ choiceId: "profile_domain.education", label: "\u6559\u80B2\u4E0E\u77E5\u8BC6\u4F20\u64AD" }
|
|
26747
|
+
],
|
|
26748
|
+
inputType: "multi-choice",
|
|
26749
|
+
prompt: "\u8BF7\u9009\u62E9 1\u20135 \u4E2A\u4E3B\u8981\u5185\u5BB9\u9886\u57DF\u3002",
|
|
26750
|
+
questionId: "primary-domains"
|
|
26751
|
+
},
|
|
26752
|
+
{
|
|
26753
|
+
choices: [
|
|
26754
|
+
{ choiceId: "profile_audience.beginner", label: "\u521A\u5F00\u59CB\u4E86\u89E3" },
|
|
26755
|
+
{ choiceId: "profile_audience.problem-aware", label: "\u5DF2\u610F\u8BC6\u5230\u95EE\u9898" },
|
|
26756
|
+
{ choiceId: "profile_audience.evaluating", label: "\u6B63\u5728\u6BD4\u8F83\u65B9\u6848" },
|
|
26757
|
+
{ choiceId: "profile_audience.customer", label: "\u5DF2\u6709\u7ECF\u9A8C\u6216\u5BA2\u6237" }
|
|
26758
|
+
],
|
|
26759
|
+
inputType: "single-choice",
|
|
26760
|
+
prompt: "\u8BF7\u9009\u62E9\u6838\u5FC3\u8BFB\u8005\u5F53\u524D\u6240\u5904\u9636\u6BB5\u3002",
|
|
26761
|
+
questionId: "target-audience"
|
|
26762
|
+
},
|
|
26763
|
+
{
|
|
26764
|
+
choices: [
|
|
26765
|
+
{ choiceId: "profile_value.action", label: "\u7ED9\u4E00\u4E2A\u53EF\u6267\u884C\u7684\u65B9\u6CD5" },
|
|
26766
|
+
{ choiceId: "profile_value.explain", label: "\u89E3\u91CA\u590D\u6742\u95EE\u9898" },
|
|
26767
|
+
{ choiceId: "profile_value.case", label: "\u63D0\u4F9B\u771F\u5B9E\u6848\u4F8B" },
|
|
26768
|
+
{ choiceId: "profile_value.decision", label: "\u5E2E\u52A9\u505A\u51B3\u7B56" },
|
|
26769
|
+
{ choiceId: "profile_value.trust", label: "\u5EFA\u7ACB\u4E13\u4E1A\u4FE1\u4EFB" }
|
|
26770
|
+
],
|
|
26771
|
+
inputType: "single-choice",
|
|
26772
|
+
prompt: "\u8BF7\u9009\u62E9\u5185\u5BB9\u6700\u6838\u5FC3\u7684\u8BFB\u8005\u627F\u8BFA\u3002",
|
|
26773
|
+
questionId: "content-value-promise"
|
|
26774
|
+
},
|
|
26775
|
+
{
|
|
26776
|
+
choices: [
|
|
26777
|
+
{ choiceId: "profile_confirmation.guided", label: "\u5173\u952E\u9636\u6BB5\u786E\u8BA4" },
|
|
26778
|
+
{ choiceId: "profile_confirmation.review-every-stage", label: "\u6BCF\u4E2A\u5185\u5BB9\u9636\u6BB5\u90FD\u786E\u8BA4" },
|
|
26779
|
+
{ choiceId: "profile_confirmation.auto-until-delivery", label: "\u53EA\u5728\u6700\u7EC8\u9884\u89C8\u786E\u8BA4" }
|
|
26780
|
+
],
|
|
26781
|
+
inputType: "single-choice",
|
|
26782
|
+
prompt: "\u8BF7\u9009\u62E9\u5185\u5BB9\u5DE5\u4F5C\u6D41\u7684\u786E\u8BA4\u65B9\u5F0F\u3002",
|
|
26783
|
+
questionId: "confirmation-policy"
|
|
26784
|
+
}
|
|
26785
|
+
];
|
|
26721
26786
|
var ProfileCliError = class extends Error {
|
|
26722
26787
|
constructor(code, message, hint, fields) {
|
|
26723
26788
|
super(message);
|
|
@@ -26747,6 +26812,23 @@ function userMemoryPath(homeDirectory) {
|
|
|
26747
26812
|
function memoryPath(homeDirectory) {
|
|
26748
26813
|
return path2.join(homeDirectory, ".dxc", "content-memory.json");
|
|
26749
26814
|
}
|
|
26815
|
+
function profileSessionPath(homeDirectory, profileSessionId) {
|
|
26816
|
+
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu.test(
|
|
26817
|
+
profileSessionId
|
|
26818
|
+
)) {
|
|
26819
|
+
throw new ProfileCliError("DXC_PROFILE_INPUT_INVALID", "\u753B\u50CF\u4F1A\u8BDD ID \u65E0\u6548\u3002");
|
|
26820
|
+
}
|
|
26821
|
+
return path2.join(homeDirectory, ".dxc", "profile-sessions", `${profileSessionId}.json`);
|
|
26822
|
+
}
|
|
26823
|
+
function profileSession(value, expectedId) {
|
|
26824
|
+
if (typeof value !== "object" || value === null || Array.isArray(value) || !("version" in value) || value.version !== 1 || !("profileSessionId" in value) || value.profileSessionId !== expectedId || !("index" in value) || !Number.isInteger(value.index) || Number(value.index) < 0 || Number(value.index) > PROFILE_QUESTIONS.length || !("createdAt" in value) || typeof value.createdAt !== "string" || !("answers" in value) || typeof value.answers !== "object" || value.answers === null || Array.isArray(value.answers)) {
|
|
26825
|
+
return void 0;
|
|
26826
|
+
}
|
|
26827
|
+
return value;
|
|
26828
|
+
}
|
|
26829
|
+
function choiceLabel(questionIndex, choiceId) {
|
|
26830
|
+
return PROFILE_QUESTIONS[questionIndex]?.choices.find((choice) => choice.choiceId === choiceId)?.label;
|
|
26831
|
+
}
|
|
26750
26832
|
function singleLine(value) {
|
|
26751
26833
|
return value.replace(/[\r\n]+/gu, " ").replace(/\s+/gu, " ").trim();
|
|
26752
26834
|
}
|
|
@@ -26906,149 +26988,133 @@ async function refreshUserMemory(homeDirectory, user, now) {
|
|
|
26906
26988
|
Buffer.from(renderUserMemory(user, memory.memories))
|
|
26907
26989
|
);
|
|
26908
26990
|
}
|
|
26909
|
-
async function readProfileInput(currentDirectory, homeDirectory, inputPath) {
|
|
26910
|
-
try {
|
|
26911
|
-
const target = resolveUserPath({ currentDirectory, homeDirectory, input: inputPath });
|
|
26912
|
-
const metadata = await stat(target);
|
|
26913
|
-
if (!metadata.isFile() || metadata.size > PROFILE_MAXIMUM_BYTES) {
|
|
26914
|
-
throw new ProfileCliError("DXC_PROFILE_INPUT_INVALID", "Profile input is invalid");
|
|
26915
|
-
}
|
|
26916
|
-
return parseJson(
|
|
26917
|
-
await readFile(target, "utf8"),
|
|
26918
|
-
"DXC_PROFILE_INPUT_INVALID",
|
|
26919
|
-
"Profile input is invalid"
|
|
26920
|
-
);
|
|
26921
|
-
} catch (error) {
|
|
26922
|
-
if (error instanceof ProfileCliError) {
|
|
26923
|
-
throw error;
|
|
26924
|
-
}
|
|
26925
|
-
throw new ProfileCliError(
|
|
26926
|
-
"DXC_PROFILE_INPUT_INVALID",
|
|
26927
|
-
"\u753B\u50CF\u8F93\u5165\u6587\u4EF6\u65E0\u6CD5\u8BFB\u53D6\u6216\u4E0D\u662F\u6709\u6548 JSON\u3002",
|
|
26928
|
-
"\u8BF7\u8BA9 DxC \u5DE5\u4F5C\u6D41\u91CD\u65B0\u751F\u6210\u753B\u50CF\u8F93\u5165\uFF1B\u65E0\u9700\u624B\u52A8\u4FEE\u6539\u8DEF\u5F84\u6216\u5E94\u7528\u6570\u636E\u6587\u4EF6\u3002"
|
|
26929
|
-
);
|
|
26930
|
-
}
|
|
26931
|
-
}
|
|
26932
|
-
function issueFields(issues) {
|
|
26933
|
-
return [
|
|
26934
|
-
...new Set(
|
|
26935
|
-
issues.map((issue) => issue.path.map(String).join(".")).filter((field) => field.length > 0)
|
|
26936
|
-
)
|
|
26937
|
-
];
|
|
26938
|
-
}
|
|
26939
|
-
async function readProfileForSave(target, timestamp) {
|
|
26940
|
-
try {
|
|
26941
|
-
return await readProfile(target);
|
|
26942
|
-
} catch (error) {
|
|
26943
|
-
if (!(error instanceof ProfileCliError) || error.code !== "DXC_PROFILE_INVALID") {
|
|
26944
|
-
throw error;
|
|
26945
|
-
}
|
|
26946
|
-
try {
|
|
26947
|
-
const metadata = await lstat(target);
|
|
26948
|
-
if (!metadata.isFile() || metadata.isSymbolicLink()) {
|
|
26949
|
-
throw error;
|
|
26950
|
-
}
|
|
26951
|
-
const suffix = timestamp.replaceAll(":", "-");
|
|
26952
|
-
await rename(target, `${target}.invalid-${suffix}.bak`);
|
|
26953
|
-
return void 0;
|
|
26954
|
-
} catch (recoveryError) {
|
|
26955
|
-
if (recoveryError === error) {
|
|
26956
|
-
throw error;
|
|
26957
|
-
}
|
|
26958
|
-
throw new ProfileCliError(
|
|
26959
|
-
"DXC_PROFILE_INVALID",
|
|
26960
|
-
"\u53D1\u73B0\u65E0\u6548\u7684\u65E7\u753B\u50CF\uFF0C\u4F46\u65E0\u6CD5\u5B89\u5168\u5907\u4EFD\u5E76\u6062\u590D\u3002",
|
|
26961
|
-
"\u8BF7\u8BA9 DxC \u5DE5\u4F5C\u6D41\u91CD\u8BD5\uFF1B\u4E0D\u8981\u624B\u52A8\u5220\u9664 ~/.dxc \u4E2D\u7684\u6587\u4EF6\u3002"
|
|
26962
|
-
);
|
|
26963
|
-
}
|
|
26964
|
-
}
|
|
26965
|
-
}
|
|
26966
26991
|
var ProfileCli = class {
|
|
26967
|
-
#currentDirectory;
|
|
26968
26992
|
#homeDirectory;
|
|
26969
26993
|
#now;
|
|
26970
26994
|
#randomUUID;
|
|
26971
26995
|
constructor(dependencies) {
|
|
26972
|
-
this.#currentDirectory = dependencies.currentDirectory;
|
|
26973
26996
|
this.#homeDirectory = dependencies.homeDirectory;
|
|
26974
26997
|
this.#now = dependencies.now ?? (() => /* @__PURE__ */ new Date());
|
|
26975
26998
|
this.#randomUUID = dependencies.randomUUID ?? randomUUID;
|
|
26976
26999
|
}
|
|
26977
|
-
async
|
|
26978
|
-
const
|
|
26979
|
-
|
|
26980
|
-
|
|
26981
|
-
|
|
26982
|
-
|
|
26983
|
-
|
|
26984
|
-
|
|
26985
|
-
|
|
26986
|
-
|
|
26987
|
-
|
|
26988
|
-
|
|
26989
|
-
|
|
26990
|
-
const target = profilePath(this.#homeDirectory);
|
|
26991
|
-
const timestamp = this.#now().toISOString();
|
|
26992
|
-
const existing = await readProfileForSave(target, timestamp);
|
|
26993
|
-
const profile = contentProfileSchema.parse({
|
|
26994
|
-
...input.data,
|
|
26995
|
-
createdAt: existing?.createdAt ?? timestamp,
|
|
26996
|
-
profileId: existing?.profileId ?? this.#randomUUID(),
|
|
26997
|
-
schemaVersion: "1",
|
|
26998
|
-
updatedAt: timestamp
|
|
26999
|
-
});
|
|
27000
|
-
try {
|
|
27001
|
-
await writePrivateJson(target, profile);
|
|
27002
|
-
await refreshUserMemory(this.#homeDirectory, profile.user, this.#now());
|
|
27003
|
-
} catch {
|
|
27004
|
-
throw new ProfileCliError("DXC_PROFILE_IO_FAILED", "Unable to save local content profile");
|
|
27005
|
-
}
|
|
27006
|
-
return contentProfileSaveResultSchema.parse({
|
|
27007
|
-
command: "profile.save",
|
|
27008
|
-
data: {
|
|
27009
|
-
profile,
|
|
27010
|
-
profilePath: PROFILE_DISPLAY_PATH,
|
|
27011
|
-
userMemoryPath: USER_MEMORY_DISPLAY_PATH
|
|
27012
|
-
},
|
|
27000
|
+
async begin() {
|
|
27001
|
+
const profileSessionId = this.#randomUUID();
|
|
27002
|
+
const session = {
|
|
27003
|
+
answers: {},
|
|
27004
|
+
createdAt: this.#now().toISOString(),
|
|
27005
|
+
index: 0,
|
|
27006
|
+
profileSessionId,
|
|
27007
|
+
version: 1
|
|
27008
|
+
};
|
|
27009
|
+
await writePrivateJson(profileSessionPath(this.#homeDirectory, profileSessionId), session);
|
|
27010
|
+
return contentProfileSessionResultSchema.parse({
|
|
27011
|
+
command: "profile.begin",
|
|
27012
|
+
data: { profileSessionId, question: PROFILE_QUESTIONS[0], status: "question" },
|
|
27013
27013
|
ok: true
|
|
27014
27014
|
});
|
|
27015
27015
|
}
|
|
27016
|
-
async
|
|
27017
|
-
const
|
|
27018
|
-
|
|
27019
|
-
|
|
27020
|
-
|
|
27021
|
-
|
|
27016
|
+
async answer(profileSessionId, input) {
|
|
27017
|
+
const target = profileSessionPath(this.#homeDirectory, profileSessionId);
|
|
27018
|
+
let session;
|
|
27019
|
+
try {
|
|
27020
|
+
const parsed = profileSession(
|
|
27021
|
+
JSON.parse(await readPrivateFile(target, PROFILE_SESSION_MAXIMUM_BYTES)),
|
|
27022
|
+
profileSessionId
|
|
27023
|
+
);
|
|
27024
|
+
if (parsed === void 0) {
|
|
27025
|
+
throw new ProfileCliError("DXC_PROFILE_INPUT_INVALID", "\u753B\u50CF\u4F1A\u8BDD\u5DF2\u635F\u574F\u3002");
|
|
27026
|
+
}
|
|
27027
|
+
session = parsed;
|
|
27028
|
+
} catch (error) {
|
|
27029
|
+
if (error instanceof ProfileCliError) {
|
|
27030
|
+
throw error;
|
|
27031
|
+
}
|
|
27032
|
+
throw new ProfileCliError("DXC_PROFILE_INPUT_INVALID", "\u753B\u50CF\u4F1A\u8BDD\u4E0D\u5B58\u5728\u6216\u5DF2\u5B8C\u6210\u3002");
|
|
27033
|
+
}
|
|
27034
|
+
const question = PROFILE_QUESTIONS[session.index];
|
|
27035
|
+
if (question === void 0) {
|
|
27036
|
+
throw new ProfileCliError("DXC_PROFILE_INPUT_INVALID", "\u753B\u50CF\u4F1A\u8BDD\u5DF2\u7ECF\u5B8C\u6210\u3002");
|
|
27022
27037
|
}
|
|
27023
|
-
const
|
|
27024
|
-
|
|
27025
|
-
|
|
27026
|
-
|
|
27038
|
+
const choices = [...new Set(input.choices)];
|
|
27039
|
+
if (question.inputType === "text") {
|
|
27040
|
+
if (input.text === void 0 || input.text.trim().length === 0 || input.text.length > 120) {
|
|
27041
|
+
throw new ProfileCliError("DXC_PROFILE_INPUT_INVALID", "\u5F53\u524D\u753B\u50CF\u95EE\u9898\u9700\u8981\u6709\u6548\u6587\u672C\u7B54\u6848\u3002");
|
|
27042
|
+
}
|
|
27043
|
+
} else {
|
|
27044
|
+
const maximum = question.inputType === "multi-choice" ? 5 : 1;
|
|
27045
|
+
if (choices.length < 1 || choices.length > maximum || choices.some((choice) => choiceLabel(session.index, choice) === void 0)) {
|
|
27046
|
+
throw new ProfileCliError("DXC_PROFILE_INPUT_INVALID", "\u753B\u50CF\u9009\u62E9\u4E0D\u5C5E\u4E8E\u5F53\u524D\u95EE\u9898\u3002");
|
|
27047
|
+
}
|
|
27048
|
+
}
|
|
27049
|
+
const answer = {
|
|
27050
|
+
choices,
|
|
27051
|
+
...input.note === void 0 ? {} : { note: input.note.trim().slice(0, 500) },
|
|
27052
|
+
...input.text === void 0 ? {} : { text: input.text.trim() }
|
|
27053
|
+
};
|
|
27054
|
+
const answers = { ...session.answers, [question.questionId]: answer };
|
|
27055
|
+
const nextIndex = session.index + 1;
|
|
27056
|
+
if (nextIndex < PROFILE_QUESTIONS.length) {
|
|
27057
|
+
await writePrivateJson(target, { ...session, answers, index: nextIndex });
|
|
27058
|
+
return contentProfileSessionResultSchema.parse({
|
|
27059
|
+
command: "profile.answer",
|
|
27060
|
+
data: {
|
|
27061
|
+
profileSessionId,
|
|
27062
|
+
question: PROFILE_QUESTIONS[nextIndex],
|
|
27063
|
+
status: "question"
|
|
27064
|
+
},
|
|
27065
|
+
ok: true
|
|
27066
|
+
});
|
|
27027
27067
|
}
|
|
27028
|
-
const
|
|
27029
|
-
|
|
27068
|
+
const creatorRole = choiceLabel(0, answers["creator-role"]?.choices[0] ?? "");
|
|
27069
|
+
const displayName = answers["display-name"]?.text;
|
|
27070
|
+
const primaryDomains = (answers["primary-domains"]?.choices ?? []).map((choice) => choiceLabel(2, choice)).filter((label) => label !== void 0);
|
|
27071
|
+
const targetAudience = choiceLabel(3, answers["target-audience"]?.choices[0] ?? "");
|
|
27072
|
+
const contentValuePromise = choiceLabel(4, answers["content-value-promise"]?.choices[0] ?? "");
|
|
27073
|
+
const confirmationChoice = answers["confirmation-policy"]?.choices[0];
|
|
27074
|
+
const confirmationPolicy = confirmationChoice?.replace("profile_confirmation.", "");
|
|
27075
|
+
const existing = await readProfile(profilePath(this.#homeDirectory));
|
|
27076
|
+
const existingUser = existing?.user;
|
|
27077
|
+
const userWithoutRetiredPolicy = existingUser === void 0 ? {} : Object.fromEntries(
|
|
27078
|
+
Object.entries(existingUser).filter(([key]) => key !== "visualGenerationAuthorization")
|
|
27030
27079
|
);
|
|
27031
|
-
|
|
27032
|
-
|
|
27080
|
+
const parsedInput = contentProfileInputSchema.safeParse({
|
|
27081
|
+
answers: existing?.answers ?? [],
|
|
27082
|
+
questionnaireVersion: "dxc-onboarding@1",
|
|
27083
|
+
user: {
|
|
27084
|
+
...userWithoutRetiredPolicy,
|
|
27085
|
+
confirmationPolicy,
|
|
27086
|
+
contentValuePromise,
|
|
27087
|
+
creatorRole,
|
|
27088
|
+
displayName,
|
|
27089
|
+
primaryDomains,
|
|
27090
|
+
primaryPlatform: "wechat-official-account",
|
|
27091
|
+
targetAudience
|
|
27092
|
+
}
|
|
27093
|
+
});
|
|
27094
|
+
if (!parsedInput.success) {
|
|
27095
|
+
throw new ProfileCliError("DXC_PROFILE_INPUT_INVALID", "\u753B\u50CF\u7B54\u6848\u65E0\u6CD5\u5F62\u6210\u6709\u6548\u753B\u50CF\u3002");
|
|
27033
27096
|
}
|
|
27034
27097
|
const timestamp = this.#now().toISOString();
|
|
27035
27098
|
const profile = contentProfileSchema.parse({
|
|
27036
|
-
...
|
|
27037
|
-
|
|
27038
|
-
|
|
27099
|
+
...parsedInput.data,
|
|
27100
|
+
createdAt: existing?.createdAt ?? timestamp,
|
|
27101
|
+
profileId: existing?.profileId ?? this.#randomUUID(),
|
|
27102
|
+
schemaVersion: "1",
|
|
27039
27103
|
updatedAt: timestamp
|
|
27040
27104
|
});
|
|
27041
27105
|
try {
|
|
27042
|
-
await writePrivateJson(
|
|
27106
|
+
await writePrivateJson(profilePath(this.#homeDirectory), profile);
|
|
27043
27107
|
await refreshUserMemory(this.#homeDirectory, profile.user, this.#now());
|
|
27108
|
+
await unlink(target);
|
|
27044
27109
|
} catch {
|
|
27045
|
-
throw new ProfileCliError("DXC_PROFILE_IO_FAILED", "
|
|
27110
|
+
throw new ProfileCliError("DXC_PROFILE_IO_FAILED", "\u65E0\u6CD5\u539F\u5B50\u4FDD\u5B58\u753B\u50CF\u95EE\u7B54\u7ED3\u679C\u3002");
|
|
27046
27111
|
}
|
|
27047
|
-
return
|
|
27048
|
-
command: "profile.
|
|
27112
|
+
return contentProfileSessionResultSchema.parse({
|
|
27113
|
+
command: "profile.answer",
|
|
27049
27114
|
data: {
|
|
27050
27115
|
profile,
|
|
27051
27116
|
profilePath: PROFILE_DISPLAY_PATH,
|
|
27117
|
+
status: "completed",
|
|
27052
27118
|
userMemoryPath: USER_MEMORY_DISPLAY_PATH
|
|
27053
27119
|
},
|
|
27054
27120
|
ok: true
|
|
@@ -27073,20 +27139,16 @@ var ProfileCli = class {
|
|
|
27073
27139
|
}
|
|
27074
27140
|
};
|
|
27075
27141
|
var ContentMemoryCli = class {
|
|
27076
|
-
#currentDirectory;
|
|
27077
27142
|
#homeDirectory;
|
|
27078
27143
|
#now;
|
|
27079
27144
|
#randomUUID;
|
|
27080
27145
|
constructor(dependencies) {
|
|
27081
|
-
this.#currentDirectory = dependencies.currentDirectory;
|
|
27082
27146
|
this.#homeDirectory = dependencies.homeDirectory;
|
|
27083
27147
|
this.#now = dependencies.now ?? (() => /* @__PURE__ */ new Date());
|
|
27084
27148
|
this.#randomUUID = dependencies.randomUUID ?? randomUUID;
|
|
27085
27149
|
}
|
|
27086
|
-
async add(
|
|
27087
|
-
const input = contentMemoryInputSchema.safeParse(
|
|
27088
|
-
await readProfileInput(this.#currentDirectory, this.#homeDirectory, inputPath)
|
|
27089
|
-
);
|
|
27150
|
+
async add(inputValue) {
|
|
27151
|
+
const input = contentMemoryInputSchema.safeParse(inputValue);
|
|
27090
27152
|
if (!input.success) {
|
|
27091
27153
|
throw new ContentMemoryCliError(
|
|
27092
27154
|
"DXC_MEMORY_INPUT_INVALID",
|
|
@@ -27181,11 +27243,73 @@ var ContentMemoryCli = class {
|
|
|
27181
27243
|
ok: true
|
|
27182
27244
|
});
|
|
27183
27245
|
}
|
|
27246
|
+
async correct(memoryId, inputValue) {
|
|
27247
|
+
const input = contentMemoryInputSchema.safeParse(inputValue);
|
|
27248
|
+
if (!input.success) {
|
|
27249
|
+
throw new ContentMemoryCliError(
|
|
27250
|
+
"DXC_MEMORY_INPUT_INVALID",
|
|
27251
|
+
"Content memory correction is invalid"
|
|
27252
|
+
);
|
|
27253
|
+
}
|
|
27254
|
+
const target = memoryPath(this.#homeDirectory);
|
|
27255
|
+
const store = await readMemoryStore(target);
|
|
27256
|
+
const index = store.memories.findIndex(
|
|
27257
|
+
(memory2) => memory2.id === memoryId && memory2.status === "active"
|
|
27258
|
+
);
|
|
27259
|
+
if (index < 0) {
|
|
27260
|
+
throw new ContentMemoryCliError(
|
|
27261
|
+
"DXC_MEMORY_NOT_FOUND",
|
|
27262
|
+
"Active content memory was not found"
|
|
27263
|
+
);
|
|
27264
|
+
}
|
|
27265
|
+
if (store.memories.length >= 100) {
|
|
27266
|
+
throw new ContentMemoryCliError("DXC_MEMORY_IO_FAILED", "Content memory capacity is reached");
|
|
27267
|
+
}
|
|
27268
|
+
const timestamp = this.#now().toISOString();
|
|
27269
|
+
const archivedMemory = {
|
|
27270
|
+
...store.memories[index],
|
|
27271
|
+
status: "archived",
|
|
27272
|
+
updatedAt: timestamp
|
|
27273
|
+
};
|
|
27274
|
+
const memory = {
|
|
27275
|
+
...input.data,
|
|
27276
|
+
createdAt: timestamp,
|
|
27277
|
+
id: this.#randomUUID(),
|
|
27278
|
+
source: "user-stated",
|
|
27279
|
+
status: "active",
|
|
27280
|
+
updatedAt: timestamp
|
|
27281
|
+
};
|
|
27282
|
+
const memories = [
|
|
27283
|
+
...store.memories.map((entry, entryIndex) => entryIndex === index ? archivedMemory : entry),
|
|
27284
|
+
memory
|
|
27285
|
+
];
|
|
27286
|
+
const next = contentMemoryStoreSchema.parse({ ...store, memories });
|
|
27287
|
+
try {
|
|
27288
|
+
await writePrivateJson(target, next);
|
|
27289
|
+
const profile = await readProfile(profilePath(this.#homeDirectory));
|
|
27290
|
+
await refreshUserMemory(this.#homeDirectory, profile?.user, this.#now());
|
|
27291
|
+
} catch (error) {
|
|
27292
|
+
if (error instanceof ContentMemoryCliError || error instanceof ProfileCliError) {
|
|
27293
|
+
throw error;
|
|
27294
|
+
}
|
|
27295
|
+
throw new ContentMemoryCliError("DXC_MEMORY_IO_FAILED", "Unable to correct content memory");
|
|
27296
|
+
}
|
|
27297
|
+
return contentMemoryCorrectResultSchema.parse({
|
|
27298
|
+
command: "memory.correct",
|
|
27299
|
+
data: {
|
|
27300
|
+
archivedMemory,
|
|
27301
|
+
memories: next.memories.filter((entry) => entry.status === "active"),
|
|
27302
|
+
memory,
|
|
27303
|
+
memoryPath: MEMORY_DISPLAY_PATH
|
|
27304
|
+
},
|
|
27305
|
+
ok: true
|
|
27306
|
+
});
|
|
27307
|
+
}
|
|
27184
27308
|
};
|
|
27185
27309
|
|
|
27186
27310
|
// apps/cli/src/project.ts
|
|
27187
27311
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
27188
|
-
import { lstat
|
|
27312
|
+
import { lstat, mkdir } from "node:fs/promises";
|
|
27189
27313
|
import path3 from "node:path";
|
|
27190
27314
|
var MANIFEST_NAME = "dxc.project.json";
|
|
27191
27315
|
var MANIFEST_MAXIMUM_BYTES = 32 * 1024;
|
|
@@ -27291,7 +27415,7 @@ var ProjectCli = class {
|
|
|
27291
27415
|
});
|
|
27292
27416
|
const manifestTarget = path3.join(directory, MANIFEST_NAME);
|
|
27293
27417
|
try {
|
|
27294
|
-
await
|
|
27418
|
+
await lstat(manifestTarget);
|
|
27295
27419
|
throw new ProjectCliError("DXC_PROJECT_EXISTS", "\u8BE5\u76EE\u5F55\u5DF2\u7ECF\u662F DxC \u5185\u5BB9\u9879\u76EE\u3002");
|
|
27296
27420
|
} catch (error) {
|
|
27297
27421
|
if (error instanceof ProjectCliError) {
|
|
@@ -27427,7 +27551,17 @@ var ProjectCli = class {
|
|
|
27427
27551
|
};
|
|
27428
27552
|
|
|
27429
27553
|
// apps/cli/src/skills.ts
|
|
27430
|
-
import {
|
|
27554
|
+
import {
|
|
27555
|
+
cp,
|
|
27556
|
+
lstat as lstat2,
|
|
27557
|
+
mkdir as mkdir2,
|
|
27558
|
+
mkdtemp,
|
|
27559
|
+
readFile,
|
|
27560
|
+
readdir,
|
|
27561
|
+
rename,
|
|
27562
|
+
rm,
|
|
27563
|
+
writeFile
|
|
27564
|
+
} from "node:fs/promises";
|
|
27431
27565
|
import os from "node:os";
|
|
27432
27566
|
import path4 from "node:path";
|
|
27433
27567
|
import { fileURLToPath } from "node:url";
|
|
@@ -27457,7 +27591,7 @@ var SkillInstallerError = class extends Error {
|
|
|
27457
27591
|
};
|
|
27458
27592
|
async function isDirectory(directory) {
|
|
27459
27593
|
try {
|
|
27460
|
-
return (await
|
|
27594
|
+
return (await lstat2(directory)).isDirectory();
|
|
27461
27595
|
} catch {
|
|
27462
27596
|
return false;
|
|
27463
27597
|
}
|
|
@@ -27481,7 +27615,7 @@ async function findBundledSkills() {
|
|
|
27481
27615
|
async function assertRegularSkillTree(directory) {
|
|
27482
27616
|
for (const entry of await readdir(directory, { withFileTypes: true })) {
|
|
27483
27617
|
const entryPath = path4.join(directory, entry.name);
|
|
27484
|
-
const entryStat = await
|
|
27618
|
+
const entryStat = await lstat2(entryPath);
|
|
27485
27619
|
if (entryStat.isSymbolicLink()) {
|
|
27486
27620
|
throw new SkillInstallerError(
|
|
27487
27621
|
"DXC_SKILL_SOURCE_UNSAFE",
|
|
@@ -27500,6 +27634,26 @@ async function assertRegularSkillTree(directory) {
|
|
|
27500
27634
|
}
|
|
27501
27635
|
}
|
|
27502
27636
|
}
|
|
27637
|
+
async function renderCliInvocation(sourceRoot, stagedSkill) {
|
|
27638
|
+
const skillFile = path4.join(stagedSkill, "SKILL.md");
|
|
27639
|
+
const skill = await readFile(skillFile, "utf8");
|
|
27640
|
+
if (!skill.includes("{{DXC_CLI_INVOCATION}}")) {
|
|
27641
|
+
return;
|
|
27642
|
+
}
|
|
27643
|
+
const invocationTemplate = await readFile(
|
|
27644
|
+
path4.join(sourceRoot, ".dxc-cli-invocation.template.md"),
|
|
27645
|
+
"utf8"
|
|
27646
|
+
);
|
|
27647
|
+
const invocation = invocationTemplate.replaceAll("{{VERSION}}", package_default.version).trim();
|
|
27648
|
+
const rendered = skill.replaceAll("{{DXC_CLI_INVOCATION}}", invocation);
|
|
27649
|
+
if (rendered.includes("{{DXC_CLI_INVOCATION}}") || rendered.includes("{{VERSION}}")) {
|
|
27650
|
+
throw new SkillInstallerError(
|
|
27651
|
+
"DXC_SKILL_TEMPLATE_INVALID",
|
|
27652
|
+
"Bundled Skill invocation template contains an unresolved placeholder"
|
|
27653
|
+
);
|
|
27654
|
+
}
|
|
27655
|
+
await writeFile(skillFile, rendered, { mode: 384 });
|
|
27656
|
+
}
|
|
27503
27657
|
function defaultTargetDirectory(homeDirectory, target) {
|
|
27504
27658
|
return path4.join(homeDirectory, target === "codex" ? ".codex" : ".workbuddy", "skills");
|
|
27505
27659
|
}
|
|
@@ -27542,10 +27696,11 @@ var SkillInstaller = class {
|
|
|
27542
27696
|
errorOnExist: true,
|
|
27543
27697
|
recursive: true
|
|
27544
27698
|
});
|
|
27699
|
+
await renderCliInvocation(sourceRoot, stagedSkill);
|
|
27545
27700
|
if (destinationExists) {
|
|
27546
|
-
await
|
|
27701
|
+
await rename(destination, backup);
|
|
27547
27702
|
}
|
|
27548
|
-
await
|
|
27703
|
+
await rename(stagedSkill, destination);
|
|
27549
27704
|
installed.push(skill);
|
|
27550
27705
|
if (destinationExists) {
|
|
27551
27706
|
try {
|
|
@@ -27556,7 +27711,7 @@ var SkillInstaller = class {
|
|
|
27556
27711
|
}
|
|
27557
27712
|
} catch (error) {
|
|
27558
27713
|
if (!await isDirectory(destination) && await isDirectory(backup)) {
|
|
27559
|
-
await
|
|
27714
|
+
await rename(backup, destination);
|
|
27560
27715
|
}
|
|
27561
27716
|
throw error;
|
|
27562
27717
|
} finally {
|
|
@@ -27587,7 +27742,7 @@ import {
|
|
|
27587
27742
|
randomUUID as randomUUID4
|
|
27588
27743
|
} from "node:crypto";
|
|
27589
27744
|
import { constants as fileConstants3 } from "node:fs";
|
|
27590
|
-
import { chmod, lstat as
|
|
27745
|
+
import { chmod, lstat as lstat5, mkdir as mkdir5, open as open3, rename as rename3, rm as rm2, writeFile as writeFile3 } from "node:fs/promises";
|
|
27591
27746
|
import os2 from "node:os";
|
|
27592
27747
|
import path7 from "node:path";
|
|
27593
27748
|
|
|
@@ -27735,10 +27890,10 @@ var LOG_REDACTION_PATHS = Object.freeze([
|
|
|
27735
27890
|
]);
|
|
27736
27891
|
|
|
27737
27892
|
// apps/cli/src/publishing-assets.ts
|
|
27738
|
-
import { createHash as
|
|
27739
|
-
import { constants as
|
|
27740
|
-
import { lstat as lstat4, open, readdir as readdir2, realpath } from "node:fs/promises";
|
|
27741
|
-
import
|
|
27893
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
27894
|
+
import { constants as fileConstants2 } from "node:fs";
|
|
27895
|
+
import { lstat as lstat4, mkdir as mkdir4, open as open2, readdir as readdir2, readFile as readFile3, realpath as realpath2 } from "node:fs/promises";
|
|
27896
|
+
import path6 from "node:path";
|
|
27742
27897
|
|
|
27743
27898
|
// packages/renderer-wechat/src/article.ts
|
|
27744
27899
|
import { createHash as createHash2 } from "node:crypto";
|
|
@@ -29860,7 +30015,24 @@ function rewriteWechatAssetSources(html, replacements) {
|
|
|
29860
30015
|
}
|
|
29861
30016
|
|
|
29862
30017
|
// apps/cli/src/publishing-assets.ts
|
|
30018
|
+
var import_yaml3 = __toESM(require_dist(), 1);
|
|
30019
|
+
import sharp2 from "sharp";
|
|
30020
|
+
|
|
30021
|
+
// apps/cli/src/publishing-image-optimization.ts
|
|
29863
30022
|
var import_yaml2 = __toESM(require_dist(), 1);
|
|
30023
|
+
import { createHash as createHash4, randomUUID as randomUUID3 } from "node:crypto";
|
|
30024
|
+
import { constants as fileConstants } from "node:fs";
|
|
30025
|
+
import {
|
|
30026
|
+
lstat as lstat3,
|
|
30027
|
+
mkdir as mkdir3,
|
|
30028
|
+
open,
|
|
30029
|
+
readFile as readFile2,
|
|
30030
|
+
realpath,
|
|
30031
|
+
rename as rename2,
|
|
30032
|
+
unlink as unlink2,
|
|
30033
|
+
writeFile as writeFile2
|
|
30034
|
+
} from "node:fs/promises";
|
|
30035
|
+
import path5 from "node:path";
|
|
29864
30036
|
import sharp from "sharp";
|
|
29865
30037
|
|
|
29866
30038
|
// apps/cli/src/wechat-error.ts
|
|
@@ -29879,46 +30051,402 @@ var WechatCliError = class extends Error {
|
|
|
29879
30051
|
fields;
|
|
29880
30052
|
};
|
|
29881
30053
|
|
|
30054
|
+
// apps/cli/src/publishing-image-optimization.ts
|
|
30055
|
+
var MAXIMUM_INPUT_BYTES = 32 * 1024 * 1024;
|
|
30056
|
+
var INLINE_IMAGE_LIMIT = 1024 * 1024 - 1;
|
|
30057
|
+
var INLINE_IMAGE_TARGET = 950 * 1024;
|
|
30058
|
+
var COVER_IMAGE_LIMIT = 5 * 1024 * 1024;
|
|
30059
|
+
var COVER_IMAGE_TARGET = 4500 * 1024;
|
|
30060
|
+
var VISUAL_PLAN_MAXIMUM_BYTES = 128 * 1024;
|
|
30061
|
+
var VISUAL_PLAN_FRONTMATTER = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)([\s\S]*)$/u;
|
|
30062
|
+
function sha256(value) {
|
|
30063
|
+
return createHash4("sha256").update(value).digest("hex");
|
|
30064
|
+
}
|
|
30065
|
+
function safeDerivativeBase(value) {
|
|
30066
|
+
return value.normalize("NFKC").replaceAll(/[^A-Za-z0-9._-]+/gu, "-").replaceAll(/^-+|-+$/gu, "").slice(0, 80) || "image";
|
|
30067
|
+
}
|
|
30068
|
+
function recordValue(value) {
|
|
30069
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
30070
|
+
}
|
|
30071
|
+
function portablePath(value, label) {
|
|
30072
|
+
if (typeof value !== "string" || value.trim().length === 0 || path5.isAbsolute(value) || value.includes("\\") || value.split("/").some((segment) => segment === "" || segment === "." || segment === "..")) {
|
|
30073
|
+
throw new WechatCliError(
|
|
30074
|
+
"DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
|
|
30075
|
+
`${label} \u5FC5\u987B\u662F\u9879\u76EE\u5185\u4F7F\u7528 / \u5206\u9694\u7684\u5B89\u5168\u76F8\u5BF9\u8DEF\u5F84\u3002`
|
|
30076
|
+
);
|
|
30077
|
+
}
|
|
30078
|
+
return value;
|
|
30079
|
+
}
|
|
30080
|
+
function isWithin(target, directory) {
|
|
30081
|
+
const relative = path5.relative(directory, target);
|
|
30082
|
+
return relative === "" || !relative.startsWith(`..${path5.sep}`) && relative !== "..";
|
|
30083
|
+
}
|
|
30084
|
+
async function regularImage(target) {
|
|
30085
|
+
let handle;
|
|
30086
|
+
try {
|
|
30087
|
+
handle = await open(target, fileConstants.O_RDONLY | fileConstants.O_NOFOLLOW);
|
|
30088
|
+
const metadata = await handle.stat();
|
|
30089
|
+
if (!metadata.isFile() || metadata.size <= 0 || metadata.size > MAXIMUM_INPUT_BYTES) {
|
|
30090
|
+
throw new Error("invalid image");
|
|
30091
|
+
}
|
|
30092
|
+
return await handle.readFile();
|
|
30093
|
+
} catch {
|
|
30094
|
+
throw new WechatCliError(
|
|
30095
|
+
"DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
|
|
30096
|
+
`\u65E0\u6CD5\u5B89\u5168\u8BFB\u53D6\u56FE\u7247 ${path5.basename(target)}\uFF1B\u6587\u4EF6\u5FC5\u987B\u662F\u5C0F\u4E8E ${MAXIMUM_INPUT_BYTES} bytes \u7684\u666E\u901A\u6587\u4EF6\u3002`
|
|
30097
|
+
);
|
|
30098
|
+
} finally {
|
|
30099
|
+
await handle?.close();
|
|
30100
|
+
}
|
|
30101
|
+
}
|
|
30102
|
+
async function requirePreservedAlpha(bytes) {
|
|
30103
|
+
const metadata = await sharp(bytes, {
|
|
30104
|
+
failOn: "error",
|
|
30105
|
+
limitInputPixels: 8e7
|
|
30106
|
+
}).metadata();
|
|
30107
|
+
if (metadata.format !== "png" || metadata.hasAlpha !== true) {
|
|
30108
|
+
throw new WechatCliError(
|
|
30109
|
+
"DXC_PUBLISHING_IMAGE_ALPHA_LOST",
|
|
30110
|
+
"\u900F\u660E\u56FE\u7247\u4F18\u5316\u540E\u4E22\u5931\u900F\u660E\u901A\u9053\uFF1B\u5DF2\u963B\u65AD\u4E14\u4E0D\u4F1A\u8986\u76D6\u539F\u56FE\u3002"
|
|
30111
|
+
);
|
|
30112
|
+
}
|
|
30113
|
+
}
|
|
30114
|
+
async function decodedImageMetadata(source, sourcePath) {
|
|
30115
|
+
let metadata;
|
|
30116
|
+
try {
|
|
30117
|
+
metadata = await sharp(source, { failOn: "error", limitInputPixels: 8e7 }).metadata();
|
|
30118
|
+
} catch {
|
|
30119
|
+
throw new WechatCliError(
|
|
30120
|
+
"DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
|
|
30121
|
+
"\u56FE\u7247\u65E0\u6CD5\u88AB\u5B89\u5168\u89E3\u7801\uFF1B\u4EC5\u652F\u6301\u6709\u6548 PNG/JPEG\u3002"
|
|
30122
|
+
);
|
|
30123
|
+
}
|
|
30124
|
+
const extension = path5.extname(sourcePath).toLowerCase();
|
|
30125
|
+
const expectedFormat = extension === ".png" ? "png" : extension === ".jpg" || extension === ".jpeg" ? "jpeg" : void 0;
|
|
30126
|
+
if (expectedFormat === void 0 || metadata.format !== expectedFormat || metadata.width === void 0 || metadata.height === void 0) {
|
|
30127
|
+
throw new WechatCliError(
|
|
30128
|
+
"DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
|
|
30129
|
+
"\u56FE\u7247\u6269\u5C55\u540D\u3001\u771F\u5B9E\u683C\u5F0F\u6216\u5C3A\u5BF8\u65E0\u6548\uFF1B\u4EC5\u652F\u6301\u6269\u5C55\u540D\u4E0E\u5185\u5BB9\u4E00\u81F4\u7684 PNG/JPEG\u3002"
|
|
30130
|
+
);
|
|
30131
|
+
}
|
|
30132
|
+
return {
|
|
30133
|
+
format: expectedFormat,
|
|
30134
|
+
hasAlpha: metadata.hasAlpha === true,
|
|
30135
|
+
height: metadata.height,
|
|
30136
|
+
width: metadata.width
|
|
30137
|
+
};
|
|
30138
|
+
}
|
|
30139
|
+
async function writeExclusiveOrVerify(target, bytes) {
|
|
30140
|
+
await mkdir3(path5.dirname(target), { recursive: true, mode: 448 });
|
|
30141
|
+
try {
|
|
30142
|
+
await writeFile2(target, bytes, { flag: "wx", mode: 384 });
|
|
30143
|
+
return true;
|
|
30144
|
+
} catch (error) {
|
|
30145
|
+
if (error.code !== "EEXIST") {
|
|
30146
|
+
throw error;
|
|
30147
|
+
}
|
|
30148
|
+
const existing = await regularImage(target);
|
|
30149
|
+
if (sha256(existing) !== sha256(bytes)) {
|
|
30150
|
+
throw new WechatCliError(
|
|
30151
|
+
"DXC_PUBLISHING_IMAGE_OPTIMIZATION_CONFLICT",
|
|
30152
|
+
`\u4F18\u5316\u76EE\u6807 ${path5.basename(target)} \u5DF2\u5B58\u5728\u4F46\u5185\u5BB9\u4E0D\u540C\uFF1B\u672A\u8986\u76D6\u4EFB\u4F55\u6587\u4EF6\u3002`
|
|
30153
|
+
);
|
|
30154
|
+
}
|
|
30155
|
+
return false;
|
|
30156
|
+
}
|
|
30157
|
+
}
|
|
30158
|
+
async function safeRealPathWithin(target, directory, label) {
|
|
30159
|
+
const resolved = await realpath(target).catch(() => void 0);
|
|
30160
|
+
if (resolved === void 0 || !isWithin(resolved, directory)) {
|
|
30161
|
+
throw new WechatCliError(
|
|
30162
|
+
"DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
|
|
30163
|
+
`${label} \u7684\u771F\u5B9E\u8DEF\u5F84\u4E0D\u5728\u5141\u8BB8\u7684\u9879\u76EE\u76EE\u5F55\u5185\u3002`
|
|
30164
|
+
);
|
|
30165
|
+
}
|
|
30166
|
+
return resolved;
|
|
30167
|
+
}
|
|
30168
|
+
async function ensureSafeOptimizedDirectory(assetsDirectory, realAssetsDirectory) {
|
|
30169
|
+
const optimizedDirectory = path5.join(assetsDirectory, "optimized");
|
|
30170
|
+
await mkdir3(optimizedDirectory, { recursive: true, mode: 448 });
|
|
30171
|
+
const metadata = await lstat3(optimizedDirectory).catch(() => void 0);
|
|
30172
|
+
if (metadata === void 0 || !metadata.isDirectory() || metadata.isSymbolicLink()) {
|
|
30173
|
+
throw new WechatCliError(
|
|
30174
|
+
"DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
|
|
30175
|
+
"\u4F18\u5316\u76EE\u5F55\u5FC5\u987B\u662F\u7D20\u6750\u76EE\u5F55\u5185\u7684\u666E\u901A\u76EE\u5F55\uFF0C\u4E0D\u80FD\u662F\u7B26\u53F7\u94FE\u63A5\u3002"
|
|
30176
|
+
);
|
|
30177
|
+
}
|
|
30178
|
+
await safeRealPathWithin(optimizedDirectory, realAssetsDirectory, "\u4F18\u5316\u76EE\u5F55");
|
|
30179
|
+
return optimizedDirectory;
|
|
30180
|
+
}
|
|
30181
|
+
async function writePlanAtomically(target, expectedSource, source) {
|
|
30182
|
+
const temporary = `${target}.${randomUUID3()}.tmp`;
|
|
30183
|
+
try {
|
|
30184
|
+
await writeFile2(temporary, source, { encoding: "utf8", flag: "wx", mode: 384 });
|
|
30185
|
+
if (await readFile2(target, "utf8") !== expectedSource) {
|
|
30186
|
+
throw new WechatCliError(
|
|
30187
|
+
"DXC_PUBLISHING_IMAGE_OPTIMIZATION_CONFLICT",
|
|
30188
|
+
"\u89C6\u89C9\u8BA1\u5212\u5728\u56FE\u7247\u4F18\u5316\u671F\u95F4\u5DF2\u88AB\u5176\u4ED6\u64CD\u4F5C\u4FEE\u6539\uFF1B\u672A\u8986\u76D6\u65B0\u5185\u5BB9\uFF0C\u8BF7\u91CD\u65B0\u8BFB\u53D6\u540E\u518D\u8BD5\u3002"
|
|
30189
|
+
);
|
|
30190
|
+
}
|
|
30191
|
+
await rename2(temporary, target);
|
|
30192
|
+
} finally {
|
|
30193
|
+
await unlink2(temporary).catch(() => void 0);
|
|
30194
|
+
}
|
|
30195
|
+
}
|
|
30196
|
+
function candidateWidths(width) {
|
|
30197
|
+
return [.../* @__PURE__ */ new Set([width, 2400, 2e3, 1600, 1280, 1080, 900, 720])].filter((candidate) => candidate > 0 && candidate <= width).sort((left, right) => right - left);
|
|
30198
|
+
}
|
|
30199
|
+
async function optimizedImage(source, targetBytes, metadata) {
|
|
30200
|
+
const hasAlpha = metadata.hasAlpha;
|
|
30201
|
+
for (const width of candidateWidths(metadata.width)) {
|
|
30202
|
+
if (hasAlpha) {
|
|
30203
|
+
const lossless = await sharp(source, { failOn: "error", limitInputPixels: 8e7 }).rotate().resize({ fit: "inside", width, withoutEnlargement: true }).png({ compressionLevel: 9, effort: 10 }).toBuffer();
|
|
30204
|
+
if (lossless.byteLength <= targetBytes) {
|
|
30205
|
+
await requirePreservedAlpha(lossless);
|
|
30206
|
+
return { alphaPreserved: true, bytes: lossless, extension: ".png" };
|
|
30207
|
+
}
|
|
30208
|
+
for (const colours of [256, 192, 128, 96, 64]) {
|
|
30209
|
+
const quantized = await sharp(source, {
|
|
30210
|
+
failOn: "error",
|
|
30211
|
+
limitInputPixels: 8e7
|
|
30212
|
+
}).rotate().resize({ fit: "inside", width, withoutEnlargement: true }).png({ colours, compressionLevel: 9, effort: 10, palette: true }).toBuffer();
|
|
30213
|
+
if (quantized.byteLength <= targetBytes) {
|
|
30214
|
+
await requirePreservedAlpha(quantized);
|
|
30215
|
+
return { alphaPreserved: true, bytes: quantized, extension: ".png" };
|
|
30216
|
+
}
|
|
30217
|
+
}
|
|
30218
|
+
continue;
|
|
30219
|
+
}
|
|
30220
|
+
for (const quality of [88, 82, 76, 70, 64, 58]) {
|
|
30221
|
+
const jpeg = await sharp(source, { failOn: "error", limitInputPixels: 8e7 }).rotate().resize({ fit: "inside", width, withoutEnlargement: true }).jpeg({ chromaSubsampling: "4:4:4", mozjpeg: true, progressive: true, quality }).toBuffer();
|
|
30222
|
+
if (jpeg.byteLength <= targetBytes) {
|
|
30223
|
+
return { alphaPreserved: true, bytes: jpeg, extension: ".jpg" };
|
|
30224
|
+
}
|
|
30225
|
+
}
|
|
30226
|
+
}
|
|
30227
|
+
throw new WechatCliError(
|
|
30228
|
+
"DXC_PUBLISHING_IMAGE_OPTIMIZATION_LIMIT_UNREACHABLE",
|
|
30229
|
+
`\u65E0\u6CD5\u5728\u4E0D\u4E22\u5931\u900F\u660E\u901A\u9053\u6216\u4F4E\u4E8E\u6700\u5C0F\u5C3A\u5BF8\u7B56\u7565\u7684\u524D\u63D0\u4E0B\u538B\u5230 ${targetBytes} bytes\uFF1B\u8BF7\u66F4\u6362\u6216\u88C1\u526A\u56FE\u7247\u3002`
|
|
30230
|
+
);
|
|
30231
|
+
}
|
|
30232
|
+
async function optimizePublishingImages(input) {
|
|
30233
|
+
const projectDirectory = path5.resolve(input.projectDirectory);
|
|
30234
|
+
const visualPlanPath = path5.resolve(input.visualPlanFile);
|
|
30235
|
+
if (!isWithin(visualPlanPath, projectDirectory)) {
|
|
30236
|
+
throw new WechatCliError(
|
|
30237
|
+
"DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
|
|
30238
|
+
"\u89C6\u89C9\u8BA1\u5212\u5FC5\u987B\u4F4D\u4E8E\u5F53\u524D\u5185\u5BB9\u9879\u76EE\u5185\u3002"
|
|
30239
|
+
);
|
|
30240
|
+
}
|
|
30241
|
+
const projectMetadata = await lstat3(projectDirectory).catch(() => void 0);
|
|
30242
|
+
const visualPlanMetadata = await lstat3(visualPlanPath).catch(() => void 0);
|
|
30243
|
+
if (projectMetadata === void 0 || !projectMetadata.isDirectory() || projectMetadata.isSymbolicLink() || visualPlanMetadata === void 0 || !visualPlanMetadata.isFile() || visualPlanMetadata.isSymbolicLink() || visualPlanMetadata.size > VISUAL_PLAN_MAXIMUM_BYTES) {
|
|
30244
|
+
throw new WechatCliError(
|
|
30245
|
+
"DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
|
|
30246
|
+
"\u5185\u5BB9\u9879\u76EE\u548C\u89C6\u89C9\u8BA1\u5212\u5FC5\u987B\u662F\u975E\u7B26\u53F7\u94FE\u63A5\u7684\u666E\u901A\u76EE\u5F55\u4E0E\u6587\u4EF6\u3002"
|
|
30247
|
+
);
|
|
30248
|
+
}
|
|
30249
|
+
const realProjectDirectory = await realpath(projectDirectory);
|
|
30250
|
+
await safeRealPathWithin(visualPlanPath, realProjectDirectory, "\u89C6\u89C9\u8BA1\u5212");
|
|
30251
|
+
const source = await readFile2(visualPlanPath, "utf8").catch(() => "");
|
|
30252
|
+
if (Buffer.byteLength(source, "utf8") > VISUAL_PLAN_MAXIMUM_BYTES) {
|
|
30253
|
+
throw new WechatCliError("DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID");
|
|
30254
|
+
}
|
|
30255
|
+
const match = VISUAL_PLAN_FRONTMATTER.exec(source);
|
|
30256
|
+
if (match?.[1] === void 0 || match[2] === void 0) {
|
|
30257
|
+
throw new WechatCliError("DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID");
|
|
30258
|
+
}
|
|
30259
|
+
let frontmatter2;
|
|
30260
|
+
try {
|
|
30261
|
+
frontmatter2 = recordValue((0, import_yaml2.parse)(match[1], { maxAliasCount: 10, uniqueKeys: true }));
|
|
30262
|
+
} catch {
|
|
30263
|
+
throw new WechatCliError("DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID");
|
|
30264
|
+
}
|
|
30265
|
+
if (frontmatter2 === void 0) {
|
|
30266
|
+
throw new WechatCliError(
|
|
30267
|
+
"DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
|
|
30268
|
+
"\u89C6\u89C9\u8BA1\u5212\u7684 YAML \u5934\u65E0\u6CD5\u8BFB\u53D6\u3002"
|
|
30269
|
+
);
|
|
30270
|
+
}
|
|
30271
|
+
const assetsRelative = frontmatter2["assetsDirectory"] === void 0 ? "assets" : portablePath(frontmatter2["assetsDirectory"], "assetsDirectory");
|
|
30272
|
+
frontmatter2["assetsDirectory"] = assetsRelative;
|
|
30273
|
+
frontmatter2["inlineImagesSupported"] = true;
|
|
30274
|
+
const assetsDirectory = path5.resolve(projectDirectory, assetsRelative);
|
|
30275
|
+
if (!isWithin(assetsDirectory, projectDirectory)) {
|
|
30276
|
+
throw new WechatCliError("DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID");
|
|
30277
|
+
}
|
|
30278
|
+
const assetsMetadata = await lstat3(assetsDirectory).catch(() => void 0);
|
|
30279
|
+
if (assetsMetadata === void 0 || !assetsMetadata.isDirectory() || assetsMetadata.isSymbolicLink()) {
|
|
30280
|
+
throw new WechatCliError("DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID");
|
|
30281
|
+
}
|
|
30282
|
+
const realAssetsDirectory = await safeRealPathWithin(
|
|
30283
|
+
assetsDirectory,
|
|
30284
|
+
realProjectDirectory,
|
|
30285
|
+
"\u7D20\u6750\u76EE\u5F55"
|
|
30286
|
+
);
|
|
30287
|
+
const inlineAssets = Array.isArray(frontmatter2["inlineAssets"]) ? frontmatter2["inlineAssets"] : [];
|
|
30288
|
+
const entries = [
|
|
30289
|
+
{
|
|
30290
|
+
assetId: "cover",
|
|
30291
|
+
limit: COVER_IMAGE_LIMIT,
|
|
30292
|
+
record: { path: frontmatter2["coverAsset"] },
|
|
30293
|
+
role: "cover",
|
|
30294
|
+
target: COVER_IMAGE_TARGET
|
|
30295
|
+
},
|
|
30296
|
+
...inlineAssets.map((asset, index) => ({
|
|
30297
|
+
assetId: `inline-${String(index + 1).padStart(2, "0")}`,
|
|
30298
|
+
limit: INLINE_IMAGE_LIMIT,
|
|
30299
|
+
record: recordValue(asset),
|
|
30300
|
+
role: "inline",
|
|
30301
|
+
target: INLINE_IMAGE_TARGET
|
|
30302
|
+
}))
|
|
30303
|
+
];
|
|
30304
|
+
const createdFiles = [];
|
|
30305
|
+
const mutations = [];
|
|
30306
|
+
let unchangedCount = 0;
|
|
30307
|
+
let optimizedDirectory;
|
|
30308
|
+
try {
|
|
30309
|
+
for (const entry of entries) {
|
|
30310
|
+
const assetPath = portablePath(entry.record?.["path"], `${entry.role} \u56FE\u7247\u8DEF\u5F84`);
|
|
30311
|
+
const absolutePath = path5.resolve(projectDirectory, assetPath);
|
|
30312
|
+
if (!isWithin(absolutePath, assetsDirectory)) {
|
|
30313
|
+
throw new WechatCliError(
|
|
30314
|
+
"DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
|
|
30315
|
+
`${assetPath} \u4E0D\u5728\u89C6\u89C9\u8BA1\u5212\u58F0\u660E\u7684\u7D20\u6750\u76EE\u5F55\u5185\u3002`
|
|
30316
|
+
);
|
|
30317
|
+
}
|
|
30318
|
+
const assetMetadata = await lstat3(absolutePath).catch((error) => {
|
|
30319
|
+
if (error.code === "ENOENT") {
|
|
30320
|
+
return void 0;
|
|
30321
|
+
}
|
|
30322
|
+
throw error;
|
|
30323
|
+
});
|
|
30324
|
+
if (assetMetadata === void 0) {
|
|
30325
|
+
throw new WechatCliError(
|
|
30326
|
+
"DXC_PUBLISHING_VISUAL_ASSET_MISSING",
|
|
30327
|
+
`\u89C6\u89C9\u7D20\u6750 ${entry.assetId} \u7F3A\u5931\uFF1B\u8BF7\u5C06\u771F\u5B9E\u56FE\u7247\u5199\u5165 CLI \u5206\u914D\u7684\u4F4D\u7F6E\u540E\u91CD\u8BD5\u3002`,
|
|
30328
|
+
false,
|
|
30329
|
+
{ assetId: entry.assetId, role: entry.role }
|
|
30330
|
+
);
|
|
30331
|
+
}
|
|
30332
|
+
await safeRealPathWithin(absolutePath, realAssetsDirectory, `${assetPath} \u56FE\u7247`);
|
|
30333
|
+
const bytes = await regularImage(absolutePath);
|
|
30334
|
+
const metadata = await decodedImageMetadata(bytes, assetPath);
|
|
30335
|
+
const beforeSha256 = sha256(bytes);
|
|
30336
|
+
let finalPath = assetPath;
|
|
30337
|
+
let finalBytes = bytes;
|
|
30338
|
+
let alphaPreserved = true;
|
|
30339
|
+
if (bytes.byteLength > entry.limit) {
|
|
30340
|
+
const optimized = await optimizedImage(bytes, entry.target, metadata);
|
|
30341
|
+
optimizedDirectory ??= await ensureSafeOptimizedDirectory(
|
|
30342
|
+
assetsDirectory,
|
|
30343
|
+
realAssetsDirectory
|
|
30344
|
+
);
|
|
30345
|
+
const baseName = safeDerivativeBase(path5.basename(assetPath, path5.extname(assetPath)));
|
|
30346
|
+
const optimizedSha256 = sha256(optimized.bytes);
|
|
30347
|
+
const optimizedName = `${baseName}-${entry.role}-${beforeSha256.slice(0, 12)}-${optimizedSha256.slice(0, 12)}${optimized.extension}`;
|
|
30348
|
+
const optimizedAbsolute = path5.join(optimizedDirectory, optimizedName);
|
|
30349
|
+
const created = await writeExclusiveOrVerify(optimizedAbsolute, optimized.bytes);
|
|
30350
|
+
if (created) {
|
|
30351
|
+
createdFiles.push(optimizedAbsolute);
|
|
30352
|
+
}
|
|
30353
|
+
finalPath = path5.relative(projectDirectory, optimizedAbsolute).split(path5.sep).join("/");
|
|
30354
|
+
finalBytes = optimized.bytes;
|
|
30355
|
+
alphaPreserved = optimized.alphaPreserved;
|
|
30356
|
+
mutations.push({
|
|
30357
|
+
alphaPreserved,
|
|
30358
|
+
afterBytes: finalBytes.byteLength,
|
|
30359
|
+
afterSha256: sha256(finalBytes),
|
|
30360
|
+
beforeBytes: bytes.byteLength,
|
|
30361
|
+
beforeSha256,
|
|
30362
|
+
from: assetPath,
|
|
30363
|
+
role: entry.role,
|
|
30364
|
+
to: finalPath
|
|
30365
|
+
});
|
|
30366
|
+
} else {
|
|
30367
|
+
unchangedCount += 1;
|
|
30368
|
+
}
|
|
30369
|
+
if (entry.role === "cover") {
|
|
30370
|
+
frontmatter2["coverAsset"] = finalPath;
|
|
30371
|
+
frontmatter2["coverSha256"] = sha256(finalBytes);
|
|
30372
|
+
} else if (entry.record !== void 0) {
|
|
30373
|
+
if (finalPath !== assetPath && entry.record["sourcePath"] === void 0) {
|
|
30374
|
+
entry.record["sourcePath"] = assetPath;
|
|
30375
|
+
}
|
|
30376
|
+
entry.record["path"] = finalPath;
|
|
30377
|
+
entry.record["sha256"] = sha256(finalBytes);
|
|
30378
|
+
}
|
|
30379
|
+
}
|
|
30380
|
+
frontmatter2["inlineAssets"] = inlineAssets;
|
|
30381
|
+
const normalizedSource = `---
|
|
30382
|
+
${(0, import_yaml2.stringify)(frontmatter2, { lineWidth: 0 }).trimEnd()}
|
|
30383
|
+
---
|
|
30384
|
+
${match[2]}`;
|
|
30385
|
+
await writePlanAtomically(visualPlanPath, source, normalizedSource);
|
|
30386
|
+
} catch (error) {
|
|
30387
|
+
await Promise.all(createdFiles.map((target) => unlink2(target).catch(() => void 0)));
|
|
30388
|
+
if (error instanceof WechatCliError) {
|
|
30389
|
+
throw error;
|
|
30390
|
+
}
|
|
30391
|
+
throw new WechatCliError(
|
|
30392
|
+
"DXC_PUBLISHING_IMAGE_OPTIMIZATION_FAILED",
|
|
30393
|
+
"\u56FE\u7247\u4F18\u5316\u672A\u5B8C\u6210\uFF1B\u539F\u56FE\u548C\u89C6\u89C9\u8BA1\u5212\u5747\u672A\u88AB\u8986\u76D6\u3002"
|
|
30394
|
+
);
|
|
30395
|
+
}
|
|
30396
|
+
return {
|
|
30397
|
+
command: "wechat.draft.optimize-images",
|
|
30398
|
+
data: { mutations, unchangedCount, visualPlanPath },
|
|
30399
|
+
ok: true
|
|
30400
|
+
};
|
|
30401
|
+
}
|
|
30402
|
+
|
|
29882
30403
|
// apps/cli/src/publishing-assets.ts
|
|
29883
30404
|
var MAXIMUM_ARTICLE_BYTES = 512 * 1024;
|
|
29884
|
-
var
|
|
29885
|
-
var
|
|
29886
|
-
var
|
|
30405
|
+
var PUBLISHING_COVER_MAXIMUM_BYTES = 5 * 1024 * 1024;
|
|
30406
|
+
var PUBLISHING_INLINE_IMAGE_MAXIMUM_BYTES = 1024 * 1024 - 1;
|
|
30407
|
+
var PUBLISHING_OPTIMIZABLE_IMAGE_MAXIMUM_BYTES = 32 * 1024 * 1024;
|
|
30408
|
+
var PUBLISHING_INLINE_IMAGE_MAXIMUM_COUNT = 20;
|
|
30409
|
+
var MAXIMUM_IMAGE_BYTES = PUBLISHING_COVER_MAXIMUM_BYTES;
|
|
30410
|
+
var MAXIMUM_INLINE_IMAGE_BYTES = PUBLISHING_INLINE_IMAGE_MAXIMUM_BYTES;
|
|
30411
|
+
var MAXIMUM_INLINE_IMAGES = PUBLISHING_INLINE_IMAGE_MAXIMUM_COUNT;
|
|
29887
30412
|
var SUPPORTED_IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([".jpeg", ".jpg", ".png"]);
|
|
29888
|
-
var
|
|
30413
|
+
var VISUAL_PLAN_MAXIMUM_BYTES2 = 128 * 1024;
|
|
29889
30414
|
var ARTICLE_FRONTMATTER = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)([\s\S]*)$/u;
|
|
29890
|
-
var
|
|
30415
|
+
var VISUAL_PLAN_FRONTMATTER2 = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/u;
|
|
29891
30416
|
var LOCAL_WORKFLOW_FRONTMATTER_KEYS = ["dxc", "goldenLinesPath", "goldenLinesSha256"];
|
|
29892
|
-
|
|
30417
|
+
var WORKFLOW_VISUAL_SIDECAR_FILE = ".dxc/visual-assets.json";
|
|
30418
|
+
var WORKFLOW_PUBLISHING_VISUAL_PLAN_FILE = ".dxc/publishing-visual-plan.md";
|
|
30419
|
+
var WORKFLOW_LOCAL_PREVIEW_FILE = ".dxc/previews/current.html";
|
|
30420
|
+
function recordValue2(value) {
|
|
29893
30421
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
29894
30422
|
}
|
|
29895
30423
|
async function validatePublishingImage(bytes, target) {
|
|
29896
30424
|
let metadata;
|
|
29897
30425
|
try {
|
|
29898
|
-
metadata = await
|
|
30426
|
+
metadata = await sharp2(bytes, { failOn: "error", limitInputPixels: 8e7 }).metadata();
|
|
29899
30427
|
} catch {
|
|
29900
30428
|
throw new WechatCliError(
|
|
29901
30429
|
"DXC_PUBLISHING_INPUT_INVALID",
|
|
29902
|
-
`\u56FE\u7247 ${
|
|
30430
|
+
`\u56FE\u7247 ${path6.basename(target)} \u65E0\u6CD5\u88AB\u5B89\u5168\u89E3\u7801\uFF1B\u4EC5\u652F\u6301\u6709\u6548 PNG/JPEG\u3002`
|
|
29903
30431
|
);
|
|
29904
30432
|
}
|
|
29905
|
-
const extension =
|
|
30433
|
+
const extension = path6.extname(target).toLowerCase();
|
|
29906
30434
|
const expectedFormat = extension === ".png" ? "png" : extension === ".jpg" || extension === ".jpeg" ? "jpeg" : void 0;
|
|
29907
30435
|
if (expectedFormat === void 0 || metadata.format !== expectedFormat || metadata.width === void 0 || metadata.height === void 0) {
|
|
29908
30436
|
throw new WechatCliError(
|
|
29909
30437
|
"DXC_PUBLISHING_INPUT_INVALID",
|
|
29910
|
-
`\u56FE\u7247 ${
|
|
30438
|
+
`\u56FE\u7247 ${path6.basename(target)} \u7684\u6269\u5C55\u540D\u4E0E\u771F\u5B9E PNG/JPEG \u683C\u5F0F\u4E0D\u4E00\u81F4\u3002`
|
|
29911
30439
|
);
|
|
29912
30440
|
}
|
|
29913
30441
|
}
|
|
29914
30442
|
async function readPublishingInput(inputPath, maximumBytes, role = "article") {
|
|
29915
|
-
const target =
|
|
30443
|
+
const target = path6.resolve(inputPath);
|
|
29916
30444
|
let handle;
|
|
29917
30445
|
try {
|
|
29918
|
-
handle = await
|
|
30446
|
+
handle = await open2(target, fileConstants2.O_RDONLY | fileConstants2.O_NOFOLLOW);
|
|
29919
30447
|
const metadata = await handle.stat();
|
|
29920
30448
|
if (metadata.isFile() && metadata.size > maximumBytes) {
|
|
29921
|
-
const fileName =
|
|
30449
|
+
const fileName = path6.basename(target);
|
|
29922
30450
|
if (role === "inline-image") {
|
|
29923
30451
|
throw new WechatCliError(
|
|
29924
30452
|
"DXC_PUBLISHING_INLINE_IMAGE_TOO_LARGE",
|
|
@@ -29939,7 +30467,7 @@ async function readPublishingInput(inputPath, maximumBytes, role = "article") {
|
|
|
29939
30467
|
if (!metadata.isFile() || metadata.size <= 0) {
|
|
29940
30468
|
throw new WechatCliError(
|
|
29941
30469
|
"DXC_PUBLISHING_INPUT_INVALID",
|
|
29942
|
-
`\u6587\u4EF6 ${
|
|
30470
|
+
`\u6587\u4EF6 ${path6.basename(target)} \u4E0D\u662F\u53EF\u8BFB\u53D6\u7684\u975E\u7A7A\u666E\u901A\u6587\u4EF6\u3002`
|
|
29943
30471
|
);
|
|
29944
30472
|
}
|
|
29945
30473
|
const bytes = await handle.readFile();
|
|
@@ -29953,7 +30481,7 @@ async function readPublishingInput(inputPath, maximumBytes, role = "article") {
|
|
|
29953
30481
|
}
|
|
29954
30482
|
throw new WechatCliError(
|
|
29955
30483
|
"DXC_PUBLISHING_INPUT_INVALID",
|
|
29956
|
-
`\u65E0\u6CD5\u8BFB\u53D6\u6587\u4EF6 ${
|
|
30484
|
+
`\u65E0\u6CD5\u8BFB\u53D6\u6587\u4EF6 ${path6.basename(target)}\uFF1B\u8BF7\u786E\u8BA4\u8DEF\u5F84\u3001\u6743\u9650\u4E14\u6587\u4EF6\u4E0D\u662F\u7B26\u53F7\u94FE\u63A5\u3002`
|
|
29957
30485
|
);
|
|
29958
30486
|
} finally {
|
|
29959
30487
|
await handle?.close();
|
|
@@ -29962,16 +30490,16 @@ async function readPublishingInput(inputPath, maximumBytes, role = "article") {
|
|
|
29962
30490
|
async function readContainedPublishingInput(inputPath, maximumBytes, allowedDirectories, role) {
|
|
29963
30491
|
try {
|
|
29964
30492
|
const [target, ...directories] = await Promise.all([
|
|
29965
|
-
|
|
29966
|
-
...allowedDirectories.map((directory) =>
|
|
30493
|
+
realpath2(path6.resolve(inputPath)),
|
|
30494
|
+
...allowedDirectories.map((directory) => realpath2(path6.resolve(directory)))
|
|
29967
30495
|
]);
|
|
29968
30496
|
const contained = directories.some(
|
|
29969
|
-
(directory) => target !== directory && target.startsWith(`${directory}${
|
|
30497
|
+
(directory) => target !== directory && target.startsWith(`${directory}${path6.sep}`)
|
|
29970
30498
|
);
|
|
29971
30499
|
if (!contained) {
|
|
29972
30500
|
throw new WechatCliError(
|
|
29973
30501
|
"DXC_PUBLISHING_INPUT_INVALID",
|
|
29974
|
-
`\u81EA\u52A8\u89E3\u6790\u7684\u7D20\u6750 ${
|
|
30502
|
+
`\u81EA\u52A8\u89E3\u6790\u7684\u7D20\u6750 ${path6.basename(inputPath)} \u4E0D\u5728\u6587\u7AE0\u76EE\u5F55\u6216\u663E\u5F0F\u7D20\u6750\u76EE\u5F55\u4E2D\u3002`
|
|
29975
30503
|
);
|
|
29976
30504
|
}
|
|
29977
30505
|
} catch (error) {
|
|
@@ -29980,13 +30508,13 @@ async function readContainedPublishingInput(inputPath, maximumBytes, allowedDire
|
|
|
29980
30508
|
}
|
|
29981
30509
|
throw new WechatCliError(
|
|
29982
30510
|
"DXC_PUBLISHING_INPUT_INVALID",
|
|
29983
|
-
`\u65E0\u6CD5\u5B89\u5168\u89E3\u6790\u7D20\u6750 ${
|
|
30511
|
+
`\u65E0\u6CD5\u5B89\u5168\u89E3\u6790\u7D20\u6750 ${path6.basename(inputPath)}\u3002`
|
|
29984
30512
|
);
|
|
29985
30513
|
}
|
|
29986
30514
|
return readPublishingInput(inputPath, maximumBytes, role);
|
|
29987
30515
|
}
|
|
29988
30516
|
function publishingImageMediaType(inputPath) {
|
|
29989
|
-
const extension =
|
|
30517
|
+
const extension = path6.extname(inputPath).toLowerCase();
|
|
29990
30518
|
if (extension === ".png") {
|
|
29991
30519
|
return "image/png";
|
|
29992
30520
|
}
|
|
@@ -29999,13 +30527,13 @@ function safeFileName(value) {
|
|
|
29999
30527
|
return value.normalize("NFKC").replaceAll(/[^A-Za-z0-9._-]+/gu, "-").replaceAll(/^-+|-+$/gu, "").slice(0, 80);
|
|
30000
30528
|
}
|
|
30001
30529
|
function isWithinDirectory(target, directory) {
|
|
30002
|
-
const relative =
|
|
30003
|
-
return relative === "" || !relative.startsWith(`..${
|
|
30530
|
+
const relative = path6.relative(directory, target);
|
|
30531
|
+
return relative === "" || !relative.startsWith(`..${path6.sep}`) && relative !== "..";
|
|
30004
30532
|
}
|
|
30005
30533
|
function commonDirectory(left, right) {
|
|
30006
|
-
let directory =
|
|
30534
|
+
let directory = path6.resolve(left);
|
|
30007
30535
|
while (!isWithinDirectory(right, directory)) {
|
|
30008
|
-
const parent =
|
|
30536
|
+
const parent = path6.dirname(directory);
|
|
30009
30537
|
if (parent === directory) {
|
|
30010
30538
|
return directory;
|
|
30011
30539
|
}
|
|
@@ -30017,7 +30545,7 @@ async function collectedImages(directoryInput, articleDirectory) {
|
|
|
30017
30545
|
if (directoryInput === void 0) {
|
|
30018
30546
|
return [];
|
|
30019
30547
|
}
|
|
30020
|
-
const directory =
|
|
30548
|
+
const directory = path6.resolve(directoryInput);
|
|
30021
30549
|
let entries;
|
|
30022
30550
|
try {
|
|
30023
30551
|
const metadata = await lstat4(directory);
|
|
@@ -30029,12 +30557,12 @@ async function collectedImages(directoryInput, articleDirectory) {
|
|
|
30029
30557
|
}
|
|
30030
30558
|
const sharedDirectory = commonDirectory(articleDirectory, directory);
|
|
30031
30559
|
const [resolvedDirectory, resolvedSharedDirectory] = await Promise.all([
|
|
30032
|
-
|
|
30033
|
-
|
|
30560
|
+
realpath2(directory),
|
|
30561
|
+
realpath2(sharedDirectory)
|
|
30034
30562
|
]);
|
|
30035
|
-
const expectedDirectory =
|
|
30563
|
+
const expectedDirectory = path6.resolve(
|
|
30036
30564
|
resolvedSharedDirectory,
|
|
30037
|
-
|
|
30565
|
+
path6.relative(sharedDirectory, directory)
|
|
30038
30566
|
);
|
|
30039
30567
|
if (resolvedDirectory !== expectedDirectory) {
|
|
30040
30568
|
throw new WechatCliError(
|
|
@@ -30050,8 +30578,8 @@ async function collectedImages(directoryInput, articleDirectory) {
|
|
|
30050
30578
|
throw new WechatCliError("DXC_PUBLISHING_ASSETS_DIRECTORY_INVALID");
|
|
30051
30579
|
}
|
|
30052
30580
|
return entries.filter(
|
|
30053
|
-
(entry) => entry.isFile() && SUPPORTED_IMAGE_EXTENSIONS.has(
|
|
30054
|
-
).map((entry) =>
|
|
30581
|
+
(entry) => entry.isFile() && SUPPORTED_IMAGE_EXTENSIONS.has(path6.extname(entry.name).toLowerCase())
|
|
30582
|
+
).map((entry) => path6.join(directory, entry.name)).sort((left, right) => left.localeCompare(right, "zh-CN"));
|
|
30055
30583
|
}
|
|
30056
30584
|
function injectCollectedImages(source, images) {
|
|
30057
30585
|
const diagnosticText = (value, maximum = 120) => {
|
|
@@ -30081,8 +30609,14 @@ function injectCollectedImages(source, images) {
|
|
|
30081
30609
|
}
|
|
30082
30610
|
const insertions = /* @__PURE__ */ new Map();
|
|
30083
30611
|
for (const [index, image] of images.entries()) {
|
|
30084
|
-
let headingLine = headingLines[index];
|
|
30085
|
-
if (image.
|
|
30612
|
+
let headingLine = image.headingIndex === void 0 ? headingLines[index] : headingLines[image.headingIndex];
|
|
30613
|
+
if (image.headingIndex !== void 0 && headingLine === void 0) {
|
|
30614
|
+
throw new WechatCliError(
|
|
30615
|
+
"DXC_PUBLISHING_VISUAL_ANCHOR_INVALID",
|
|
30616
|
+
`\u89C6\u89C9\u8BA1\u5212\u7AE0\u8282\u5E8F\u53F7 ${image.headingIndex + 1} \u4E0D\u5B58\u5728\u3002`
|
|
30617
|
+
);
|
|
30618
|
+
}
|
|
30619
|
+
if (image.headingIndex === void 0 && image.placementAnchor !== void 0) {
|
|
30086
30620
|
const match = /^after-heading:(.+)$/u.exec(image.placementAnchor);
|
|
30087
30621
|
const requestedHeading = match?.[1]?.trim().replace(/^##\s+/u, "").replace(/\s+#+\s*$/u, "").trim();
|
|
30088
30622
|
const matches = requestedHeading === void 0 ? void 0 : headingLineByText.get(requestedHeading);
|
|
@@ -30112,12 +30646,12 @@ function injectCollectedImages(source, images) {
|
|
|
30112
30646
|
return output.join("\n");
|
|
30113
30647
|
}
|
|
30114
30648
|
function parsedVisualPlan(source) {
|
|
30115
|
-
const yamlSource =
|
|
30649
|
+
const yamlSource = VISUAL_PLAN_FRONTMATTER2.exec(source)?.[1];
|
|
30116
30650
|
if (yamlSource === void 0) {
|
|
30117
30651
|
throw new WechatCliError("DXC_PUBLISHING_VISUAL_PLAN_INVALID");
|
|
30118
30652
|
}
|
|
30119
30653
|
try {
|
|
30120
|
-
const plan =
|
|
30654
|
+
const plan = recordValue2((0, import_yaml3.parse)(yamlSource, { maxAliasCount: 10, uniqueKeys: true }));
|
|
30121
30655
|
if (plan === void 0) {
|
|
30122
30656
|
throw new WechatCliError("DXC_PUBLISHING_VISUAL_PLAN_INVALID");
|
|
30123
30657
|
}
|
|
@@ -30129,29 +30663,299 @@ function parsedVisualPlan(source) {
|
|
|
30129
30663
|
throw new WechatCliError("DXC_PUBLISHING_VISUAL_PLAN_INVALID");
|
|
30130
30664
|
}
|
|
30131
30665
|
}
|
|
30132
|
-
function
|
|
30133
|
-
const
|
|
30134
|
-
const
|
|
30135
|
-
|
|
30136
|
-
|
|
30137
|
-
|
|
30666
|
+
function parsedWorkflowVisualAssetsSidecar(value) {
|
|
30667
|
+
const sidecar = recordValue2(value);
|
|
30668
|
+
const assets = sidecar?.["assets"];
|
|
30669
|
+
if (sidecar?.["version"] !== 1 || typeof sidecar["articleSha256"] !== "string" || !/^[a-f0-9]{64}$/u.test(sidecar["articleSha256"]) || typeof sidecar["visualPlanSha256"] !== "string" || !/^[a-f0-9]{64}$/u.test(sidecar["visualPlanSha256"]) || typeof sidecar["localPreviewPath"] !== "string" || typeof sidecar["publishingVisualPlanPath"] !== "string" || !Array.isArray(assets) || assets.length < 1 || assets.length > MAXIMUM_INLINE_IMAGES + 1) {
|
|
30670
|
+
throw new WechatCliError(
|
|
30671
|
+
"DXC_PUBLISHING_VISUAL_PLAN_INVALID",
|
|
30672
|
+
"\u89C6\u89C9\u7D20\u6750 sidecar\uFF08\u65C1\u8F66\u5143\u6570\u636E\uFF09\u65E0\u6548\u3002"
|
|
30673
|
+
);
|
|
30674
|
+
}
|
|
30675
|
+
const parsedAssets = assets.map((entry, index) => {
|
|
30676
|
+
const asset = recordValue2(entry);
|
|
30677
|
+
const expectedAssetId = index === 0 ? "cover" : `inline-${String(index).padStart(2, "0")}`;
|
|
30678
|
+
const relativePath = asset?.["relativePath"];
|
|
30679
|
+
const sectionId = asset?.["sectionId"];
|
|
30680
|
+
if (asset?.["assetId"] !== expectedAssetId || asset["role"] !== (index === 0 ? "cover" : "inline") || typeof relativePath !== "string" || relativePath.includes("\\") || path6.posix.isAbsolute(relativePath) || relativePath.split("/").some((segment) => segment === "" || segment === "." || segment === "..") || typeof asset["sha256"] !== "string" || !/^[a-f0-9]{64}$/u.test(asset["sha256"]) || index > 0 && (typeof sectionId !== "string" || !/^sec_[0-9]{2}_[a-f0-9]{8}$/u.test(sectionId)) || index === 0 && sectionId !== void 0) {
|
|
30138
30681
|
throw new WechatCliError(
|
|
30139
30682
|
"DXC_PUBLISHING_VISUAL_PLAN_INVALID",
|
|
30140
|
-
|
|
30683
|
+
`\u89C6\u89C9\u7D20\u6750 ${expectedAssetId} \u7684 sidecar\uFF08\u65C1\u8F66\u5143\u6570\u636E\uFF09\u65E0\u6548\u3002`
|
|
30141
30684
|
);
|
|
30142
30685
|
}
|
|
30686
|
+
const parsedSectionId = typeof sectionId === "string" ? sectionId : void 0;
|
|
30143
30687
|
return {
|
|
30144
|
-
|
|
30145
|
-
|
|
30146
|
-
|
|
30688
|
+
assetId: expectedAssetId,
|
|
30689
|
+
relativePath,
|
|
30690
|
+
role: index === 0 ? "cover" : "inline",
|
|
30691
|
+
...parsedSectionId === void 0 ? {} : { sectionId: parsedSectionId },
|
|
30692
|
+
sha256: asset["sha256"]
|
|
30147
30693
|
};
|
|
30148
30694
|
});
|
|
30149
|
-
|
|
30695
|
+
return {
|
|
30696
|
+
articleSha256: sidecar["articleSha256"],
|
|
30697
|
+
assets: parsedAssets,
|
|
30698
|
+
localPreviewPath: sidecar["localPreviewPath"],
|
|
30699
|
+
publishingVisualPlanPath: sidecar["publishingVisualPlanPath"],
|
|
30700
|
+
version: 1,
|
|
30701
|
+
visualPlanSha256: sidecar["visualPlanSha256"]
|
|
30702
|
+
};
|
|
30703
|
+
}
|
|
30704
|
+
function workflowSha256(value) {
|
|
30705
|
+
return createHash5("sha256").update(value).digest("hex");
|
|
30150
30706
|
}
|
|
30151
|
-
|
|
30707
|
+
function semanticVisualPlan(source, sections) {
|
|
30708
|
+
const plan = parsedVisualPlan(source);
|
|
30709
|
+
const cover = recordValue2(plan["cover"]);
|
|
30710
|
+
const inline = Array.isArray(plan["inline"]) ? plan["inline"] : [];
|
|
30711
|
+
if (typeof cover?.["purpose"] !== "string" || cover["purpose"].trim().length === 0) {
|
|
30712
|
+
throw new WechatCliError(
|
|
30713
|
+
"DXC_PUBLISHING_VISUAL_PLAN_INVALID",
|
|
30714
|
+
"\u89C6\u89C9\u8BA1\u5212\u9700\u8981\u8BF4\u660E\u5C01\u9762\u7684\u5185\u5BB9\u76EE\u7684\u3002"
|
|
30715
|
+
);
|
|
30716
|
+
}
|
|
30717
|
+
const sectionIds = new Set(sections.map((section) => section.sectionId));
|
|
30718
|
+
if (inline.length > MAXIMUM_INLINE_IMAGES) {
|
|
30719
|
+
throw new WechatCliError("DXC_PUBLISHING_TOO_MANY_INLINE_IMAGES");
|
|
30720
|
+
}
|
|
30721
|
+
const seenSections = /* @__PURE__ */ new Set();
|
|
30722
|
+
const parsedInline = inline.map((entry) => {
|
|
30723
|
+
const item = recordValue2(entry);
|
|
30724
|
+
if (typeof item?.["sectionId"] !== "string" || !sectionIds.has(item["sectionId"]) || typeof item["purpose"] !== "string" || item["purpose"].trim().length === 0 || seenSections.has(item["sectionId"])) {
|
|
30725
|
+
throw new WechatCliError(
|
|
30726
|
+
"DXC_PUBLISHING_VISUAL_PLAN_INVALID",
|
|
30727
|
+
"\u6B63\u6587\u89C6\u89C9\u8BA1\u5212\u5FC5\u987B\u4E3A\u6709\u6548\u4E14\u552F\u4E00\u7684 sectionId \u586B\u5199\u56FE\u7247\u76EE\u7684\u3002"
|
|
30728
|
+
);
|
|
30729
|
+
}
|
|
30730
|
+
seenSections.add(item["sectionId"]);
|
|
30731
|
+
return { purpose: item["purpose"].trim(), sectionId: item["sectionId"] };
|
|
30732
|
+
});
|
|
30733
|
+
return { cover: { purpose: cover["purpose"].trim() }, inline: parsedInline };
|
|
30734
|
+
}
|
|
30735
|
+
function parseWorkflowArticleSections(articleSource) {
|
|
30736
|
+
const sourceHash = workflowSha256(articleSource);
|
|
30737
|
+
const lines = articleSource.split(/\r?\n/u);
|
|
30738
|
+
const sections = [];
|
|
30739
|
+
let inFence = false;
|
|
30740
|
+
for (const line of lines) {
|
|
30741
|
+
if (/^\s*```/u.test(line)) {
|
|
30742
|
+
inFence = !inFence;
|
|
30743
|
+
continue;
|
|
30744
|
+
}
|
|
30745
|
+
if (inFence || !/^##\s+\S/u.test(line)) {
|
|
30746
|
+
continue;
|
|
30747
|
+
}
|
|
30748
|
+
const heading = line.replace(/^##\s+/u, "").replace(/\s+#+\s*$/u, "").trim();
|
|
30749
|
+
const ordinal = sections.length + 1;
|
|
30750
|
+
const identity = workflowSha256(`${sourceHash}:${ordinal}:${heading}`).slice(0, 8);
|
|
30751
|
+
sections.push({
|
|
30752
|
+
heading,
|
|
30753
|
+
sectionId: `sec_${String(ordinal).padStart(2, "0")}_${identity}`
|
|
30754
|
+
});
|
|
30755
|
+
}
|
|
30756
|
+
return sections;
|
|
30757
|
+
}
|
|
30758
|
+
function validateWorkflowSemanticVisualPlan(input) {
|
|
30759
|
+
return semanticVisualPlan(input.source, input.sections);
|
|
30760
|
+
}
|
|
30761
|
+
function workflowVisualAssetAssignments(input) {
|
|
30762
|
+
const plan = semanticVisualPlan(input.visualPlanSource, input.sections);
|
|
30763
|
+
const directory = path6.join(
|
|
30764
|
+
input.assetsDirectory ?? path6.join(input.projectDirectory, "assets"),
|
|
30765
|
+
"visuals"
|
|
30766
|
+
);
|
|
30767
|
+
return [
|
|
30768
|
+
{ assetId: "cover", path: path6.join(directory, "cover.png"), role: "cover" },
|
|
30769
|
+
...plan.inline.map((item, index) => ({
|
|
30770
|
+
assetId: `inline-${String(index + 1).padStart(2, "0")}`,
|
|
30771
|
+
path: path6.join(directory, `inline-${String(index + 1).padStart(2, "0")}.png`),
|
|
30772
|
+
role: "inline",
|
|
30773
|
+
sectionId: item.sectionId
|
|
30774
|
+
}))
|
|
30775
|
+
];
|
|
30776
|
+
}
|
|
30777
|
+
function localWorkflowPreviewHtml(prepared) {
|
|
30778
|
+
const imageSources = new Map(
|
|
30779
|
+
prepared.inlineAssets.map((asset) => [
|
|
30780
|
+
asset.logicalPath,
|
|
30781
|
+
`data:${asset.mediaType};base64,${asset.bytes.toString("base64")}`
|
|
30782
|
+
])
|
|
30783
|
+
);
|
|
30784
|
+
const article = rewriteWechatAssetSources(prepared.localRender.html, imageSources);
|
|
30785
|
+
const coverMediaType = publishingImageMediaType(prepared.cover.path);
|
|
30786
|
+
return `<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="referrer" content="no-referrer"><meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src data:; style-src 'unsafe-inline'"><title>\u672C\u5730\u5E26\u56FE\u9884\u89C8</title></head><body><main><p>\u672C\u5730\u5185\u5BB9\u4E0E\u914D\u56FE\u9884\u89C8\uFF1B\u6700\u7EC8\u4EA4\u4ED8\u4EE5\u4E91\u7AEF\u4E0D\u53EF\u53D8\u9884\u89C8\u4E3A\u51C6\u3002</p><img alt="\u5C01\u9762" style="max-width:100%" src="data:${coverMediaType};base64,${prepared.cover.bytes.toString("base64")}"><article>${article}</article></main></body></html>`;
|
|
30787
|
+
}
|
|
30788
|
+
async function finalizeWorkflowVisualAssets(input) {
|
|
30789
|
+
const plan = semanticVisualPlan(input.visualPlanSource, input.sections);
|
|
30790
|
+
const expected = workflowVisualAssetAssignments(input);
|
|
30791
|
+
if (expected.length !== input.assignments.length || expected.some(
|
|
30792
|
+
(asset, index) => asset.assetId !== input.assignments[index]?.assetId || path6.resolve(asset.path) !== path6.resolve(input.assignments[index]?.path)
|
|
30793
|
+
)) {
|
|
30794
|
+
throw new WechatCliError(
|
|
30795
|
+
"DXC_PUBLISHING_VISUAL_PLAN_INVALID",
|
|
30796
|
+
"\u89C6\u89C9\u7D20\u6750\u5206\u914D\u4E0E\u5F53\u524D\u5DE5\u4F5C\u9879\u4E0D\u4E00\u81F4\u3002"
|
|
30797
|
+
);
|
|
30798
|
+
}
|
|
30799
|
+
await mkdir4(path6.join(input.assetsDirectory, "visuals"), { recursive: true });
|
|
30800
|
+
const sectionIndex = new Map(input.sections.map((section, index) => [section.sectionId, index]));
|
|
30801
|
+
const publishingPlanPath = path6.join(
|
|
30802
|
+
input.projectDirectory,
|
|
30803
|
+
WORKFLOW_PUBLISHING_VISUAL_PLAN_FILE
|
|
30804
|
+
);
|
|
30805
|
+
const relative = (target) => path6.relative(input.projectDirectory, target).split(path6.sep).join("/");
|
|
30806
|
+
const publishingPlan = {
|
|
30807
|
+
assetsDirectory: relative(input.assetsDirectory),
|
|
30808
|
+
coverAsset: relative(expected[0].path),
|
|
30809
|
+
inlineAssets: expected.slice(1).map((asset, index) => ({
|
|
30810
|
+
assetId: asset.assetId,
|
|
30811
|
+
path: relative(asset.path),
|
|
30812
|
+
placementHeadingIndex: sectionIndex.get(asset.sectionId ?? ""),
|
|
30813
|
+
purpose: plan.inline[index]?.purpose,
|
|
30814
|
+
source: "agent-generated"
|
|
30815
|
+
}))
|
|
30816
|
+
};
|
|
30817
|
+
await writePrivateBuffer(
|
|
30818
|
+
publishingPlanPath,
|
|
30819
|
+
Buffer.from(`---
|
|
30820
|
+
${(0, import_yaml3.stringify)(publishingPlan, { lineWidth: 0 }).trimEnd()}
|
|
30821
|
+
---
|
|
30822
|
+
`, "utf8")
|
|
30823
|
+
);
|
|
30824
|
+
await optimizePublishingImages({
|
|
30825
|
+
projectDirectory: input.projectDirectory,
|
|
30826
|
+
visualPlanFile: publishingPlanPath
|
|
30827
|
+
});
|
|
30828
|
+
const prepared = await preparePublishingDraft({
|
|
30829
|
+
articleFile: input.articleFile,
|
|
30830
|
+
assetsDirectory: input.assetsDirectory,
|
|
30831
|
+
coverFile: "auto",
|
|
30832
|
+
visualPlanFile: publishingPlanPath
|
|
30833
|
+
});
|
|
30834
|
+
const localPreviewPath = path6.join(input.projectDirectory, WORKFLOW_LOCAL_PREVIEW_FILE);
|
|
30835
|
+
await writePrivateBuffer(
|
|
30836
|
+
localPreviewPath,
|
|
30837
|
+
Buffer.from(localWorkflowPreviewHtml(prepared), "utf8")
|
|
30838
|
+
);
|
|
30839
|
+
const materializedPlan = parsedVisualPlan(await readFile3(publishingPlanPath, "utf8"));
|
|
30840
|
+
const materializedInline = Array.isArray(materializedPlan["inlineAssets"]) ? materializedPlan["inlineAssets"] : [];
|
|
30841
|
+
const materializedCover = String(materializedPlan["coverAsset"]);
|
|
30842
|
+
const materialized = [
|
|
30843
|
+
{ assetId: "cover", path: materializedCover, role: "cover" },
|
|
30844
|
+
...materializedInline.map((entry, index) => {
|
|
30845
|
+
const item = recordValue2(entry);
|
|
30846
|
+
const sectionId = expected[index + 1]?.sectionId;
|
|
30847
|
+
return {
|
|
30848
|
+
assetId: expected[index + 1]?.assetId ?? `inline-${index + 1}`,
|
|
30849
|
+
path: String(item?.["path"]),
|
|
30850
|
+
role: "inline",
|
|
30851
|
+
...sectionId === void 0 ? {} : { sectionId }
|
|
30852
|
+
};
|
|
30853
|
+
})
|
|
30854
|
+
];
|
|
30855
|
+
const sidecar = {
|
|
30856
|
+
articleSha256: workflowSha256(input.articleSource),
|
|
30857
|
+
assets: await Promise.all(
|
|
30858
|
+
materialized.map(async (asset) => {
|
|
30859
|
+
const bytes = await readFile3(path6.join(input.projectDirectory, asset.path));
|
|
30860
|
+
return {
|
|
30861
|
+
assetId: asset.assetId,
|
|
30862
|
+
relativePath: asset.path,
|
|
30863
|
+
role: asset.role,
|
|
30864
|
+
...asset.sectionId === void 0 ? {} : { sectionId: asset.sectionId },
|
|
30865
|
+
sha256: workflowSha256(bytes)
|
|
30866
|
+
};
|
|
30867
|
+
})
|
|
30868
|
+
),
|
|
30869
|
+
localPreviewPath,
|
|
30870
|
+
publishingVisualPlanPath: publishingPlanPath,
|
|
30871
|
+
version: 1,
|
|
30872
|
+
visualPlanSha256: workflowSha256(input.visualPlanSource)
|
|
30873
|
+
};
|
|
30874
|
+
await writePrivateJson(path6.join(input.projectDirectory, WORKFLOW_VISUAL_SIDECAR_FILE), sidecar);
|
|
30875
|
+
return sidecar;
|
|
30876
|
+
}
|
|
30877
|
+
async function readWorkflowVisualAssetsSidecar(projectDirectory) {
|
|
30878
|
+
const input = await readPublishingInput(
|
|
30879
|
+
path6.join(projectDirectory, WORKFLOW_VISUAL_SIDECAR_FILE),
|
|
30880
|
+
VISUAL_PLAN_MAXIMUM_BYTES2
|
|
30881
|
+
);
|
|
30882
|
+
try {
|
|
30883
|
+
return parsedWorkflowVisualAssetsSidecar(JSON.parse(input.bytes.toString("utf8")));
|
|
30884
|
+
} catch (error) {
|
|
30885
|
+
if (error instanceof WechatCliError) {
|
|
30886
|
+
throw error;
|
|
30887
|
+
}
|
|
30888
|
+
throw new WechatCliError(
|
|
30889
|
+
"DXC_PUBLISHING_VISUAL_PLAN_INVALID",
|
|
30890
|
+
"\u89C6\u89C9\u7D20\u6750 sidecar\uFF08\u65C1\u8F66\u5143\u6570\u636E\uFF09\u65E0\u6CD5\u89E3\u6790\u3002"
|
|
30891
|
+
);
|
|
30892
|
+
}
|
|
30893
|
+
}
|
|
30894
|
+
async function workflowVisualAssetsFingerprint(projectDirectory) {
|
|
30895
|
+
try {
|
|
30896
|
+
const sidecar = await readWorkflowVisualAssetsSidecar(projectDirectory);
|
|
30897
|
+
const assets = await Promise.all(
|
|
30898
|
+
sidecar.assets.map(async (asset) => {
|
|
30899
|
+
const target = path6.resolve(projectDirectory, asset.relativePath);
|
|
30900
|
+
if (!isWithinDirectory(target, projectDirectory)) {
|
|
30901
|
+
return { assetId: asset.assetId, state: "invalid" };
|
|
30902
|
+
}
|
|
30903
|
+
try {
|
|
30904
|
+
const input = await readPublishingInput(
|
|
30905
|
+
target,
|
|
30906
|
+
asset.role === "cover" ? MAXIMUM_IMAGE_BYTES : MAXIMUM_INLINE_IMAGE_BYTES,
|
|
30907
|
+
asset.role === "cover" ? "cover" : "inline-image"
|
|
30908
|
+
);
|
|
30909
|
+
return { assetId: asset.assetId, sha256: workflowSha256(input.bytes) };
|
|
30910
|
+
} catch {
|
|
30911
|
+
return { assetId: asset.assetId, state: "invalid" };
|
|
30912
|
+
}
|
|
30913
|
+
})
|
|
30914
|
+
);
|
|
30915
|
+
return workflowSha256(JSON.stringify({ assets, sidecar }));
|
|
30916
|
+
} catch {
|
|
30917
|
+
return workflowSha256("visual-assets:missing-or-invalid");
|
|
30918
|
+
}
|
|
30919
|
+
}
|
|
30920
|
+
async function validateWorkflowVisualAssets(input) {
|
|
30921
|
+
const sidecar = await readWorkflowVisualAssetsSidecar(input.projectDirectory);
|
|
30922
|
+
if (sidecar.articleSha256 !== workflowSha256(input.articleSource) || sidecar.visualPlanSha256 !== workflowSha256(input.visualPlanSource) || path6.resolve(sidecar.localPreviewPath) !== path6.resolve(input.projectDirectory, WORKFLOW_LOCAL_PREVIEW_FILE) || path6.resolve(sidecar.publishingVisualPlanPath) !== path6.resolve(input.projectDirectory, WORKFLOW_PUBLISHING_VISUAL_PLAN_FILE)) {
|
|
30923
|
+
throw new WechatCliError(
|
|
30924
|
+
"DXC_PUBLISHING_VISUAL_PLAN_INVALID",
|
|
30925
|
+
"\u6587\u7AE0\u3001\u89C6\u89C9\u8BA1\u5212\u6216\u672C\u5730\u9884\u89C8\u4E0E\u89C6\u89C9\u7D20\u6750 sidecar\uFF08\u65C1\u8F66\u5143\u6570\u636E\uFF09\u4E0D\u4E00\u81F4\u3002"
|
|
30926
|
+
);
|
|
30927
|
+
}
|
|
30928
|
+
for (const asset of sidecar.assets) {
|
|
30929
|
+
const target = path6.resolve(input.projectDirectory, asset.relativePath);
|
|
30930
|
+
if (!isWithinDirectory(target, path6.resolve(input.assetsDirectory))) {
|
|
30931
|
+
throw new WechatCliError(
|
|
30932
|
+
"DXC_PUBLISHING_VISUAL_PLAN_INVALID",
|
|
30933
|
+
`\u89C6\u89C9\u7D20\u6750 ${asset.assetId} \u4E0D\u5728\u9879\u76EE\u7D20\u6750\u76EE\u5F55\u4E2D\u3002`
|
|
30934
|
+
);
|
|
30935
|
+
}
|
|
30936
|
+
const materialized = await readPublishingInput(
|
|
30937
|
+
target,
|
|
30938
|
+
asset.role === "cover" ? MAXIMUM_IMAGE_BYTES : MAXIMUM_INLINE_IMAGE_BYTES,
|
|
30939
|
+
asset.role === "cover" ? "cover" : "inline-image"
|
|
30940
|
+
);
|
|
30941
|
+
if (workflowSha256(materialized.bytes) !== asset.sha256) {
|
|
30942
|
+
throw new WechatCliError(
|
|
30943
|
+
"DXC_PUBLISHING_VISUAL_PLAN_INVALID",
|
|
30944
|
+
`\u89C6\u89C9\u7D20\u6750 ${asset.assetId} \u5DF2\u53D8\u5316\uFF0C\u8BF7\u91CD\u65B0\u5B8C\u6210 visual-plan \u9636\u6BB5\u3002`
|
|
30945
|
+
);
|
|
30946
|
+
}
|
|
30947
|
+
}
|
|
30948
|
+
await readPublishingInput(
|
|
30949
|
+
sidecar.publishingVisualPlanPath,
|
|
30950
|
+
VISUAL_PLAN_MAXIMUM_BYTES2,
|
|
30951
|
+
"visual-plan"
|
|
30952
|
+
);
|
|
30953
|
+
return sidecar;
|
|
30954
|
+
}
|
|
30955
|
+
async function plannedVisualAssets(visualPlanFile, assetsDirectoryInput, maximumCoverBytes = MAXIMUM_IMAGE_BYTES, maximumInlineBytes = MAXIMUM_INLINE_IMAGE_BYTES) {
|
|
30152
30956
|
let source;
|
|
30153
30957
|
try {
|
|
30154
|
-
source = (await readPublishingInput(visualPlanFile,
|
|
30958
|
+
source = (await readPublishingInput(visualPlanFile, VISUAL_PLAN_MAXIMUM_BYTES2, "visual-plan")).bytes.toString("utf8");
|
|
30155
30959
|
} catch {
|
|
30156
30960
|
throw new WechatCliError("DXC_PUBLISHING_VISUAL_PLAN_INVALID");
|
|
30157
30961
|
}
|
|
@@ -30167,12 +30971,12 @@ async function plannedVisualAssets(visualPlanFile, assetsDirectoryInput) {
|
|
|
30167
30971
|
"\u4F7F\u7528\u89C6\u89C9\u8BA1\u5212\u65F6\u5FC5\u987B\u663E\u5F0F\u63D0\u4F9B\u5176\u58F0\u660E\u7684\u7D20\u6750\u76EE\u5F55\u3002"
|
|
30168
30972
|
);
|
|
30169
30973
|
}
|
|
30170
|
-
const assetsDirectory =
|
|
30974
|
+
const assetsDirectory = path6.resolve(assetsDirectoryInput);
|
|
30171
30975
|
const projectDirectory = commonDirectory(
|
|
30172
|
-
|
|
30976
|
+
path6.dirname(path6.resolve(visualPlanFile)),
|
|
30173
30977
|
assetsDirectory
|
|
30174
30978
|
);
|
|
30175
|
-
const declaredAssetsDirectory = typeof plan["assetsDirectory"] === "string" ?
|
|
30979
|
+
const declaredAssetsDirectory = typeof plan["assetsDirectory"] === "string" ? path6.resolve(projectDirectory, plan["assetsDirectory"]) : assetsDirectory;
|
|
30176
30980
|
if (!isWithinDirectory(assetsDirectory, declaredAssetsDirectory)) {
|
|
30177
30981
|
throw new WechatCliError(
|
|
30178
30982
|
"DXC_PUBLISHING_VISUAL_PLAN_INVALID",
|
|
@@ -30180,7 +30984,7 @@ async function plannedVisualAssets(visualPlanFile, assetsDirectoryInput) {
|
|
|
30180
30984
|
);
|
|
30181
30985
|
}
|
|
30182
30986
|
const resolvePlannedAsset = (assetPath) => {
|
|
30183
|
-
const target =
|
|
30987
|
+
const target = path6.resolve(projectDirectory, assetPath);
|
|
30184
30988
|
if (!isWithinDirectory(target, declaredAssetsDirectory) || !isWithinDirectory(target, assetsDirectory)) {
|
|
30185
30989
|
throw new WechatCliError("DXC_PUBLISHING_VISUAL_PLAN_INVALID");
|
|
30186
30990
|
}
|
|
@@ -30189,7 +30993,7 @@ async function plannedVisualAssets(visualPlanFile, assetsDirectoryInput) {
|
|
|
30189
30993
|
const coverAbsolutePath = resolvePlannedAsset(coverAsset);
|
|
30190
30994
|
await readContainedPublishingInput(
|
|
30191
30995
|
coverAbsolutePath,
|
|
30192
|
-
|
|
30996
|
+
maximumCoverBytes,
|
|
30193
30997
|
[assetsDirectory],
|
|
30194
30998
|
"cover"
|
|
30195
30999
|
);
|
|
@@ -30197,23 +31001,24 @@ async function plannedVisualAssets(visualPlanFile, assetsDirectoryInput) {
|
|
|
30197
31001
|
coverAbsolutePath,
|
|
30198
31002
|
inline: await Promise.all(
|
|
30199
31003
|
inlineAssets.map(async (rawAsset) => {
|
|
30200
|
-
const asset =
|
|
30201
|
-
|
|
31004
|
+
const asset = recordValue2(rawAsset);
|
|
31005
|
+
const headingIndex = asset?.["placementHeadingIndex"];
|
|
31006
|
+
if (typeof asset?.["path"] !== "string" || typeof asset["placementAnchor"] !== "string" && (!Number.isInteger(headingIndex) || Number(headingIndex) < 0)) {
|
|
30202
31007
|
throw new WechatCliError(
|
|
30203
31008
|
"DXC_PUBLISHING_VISUAL_PLAN_INVALID",
|
|
30204
|
-
"\u6B63\u6587\u914D\u56FE\u9700\u8981
|
|
31009
|
+
"\u6B63\u6587\u914D\u56FE\u9700\u8981\u5B89\u5168\u8DEF\u5F84\u548C\u6709\u6548\u7AE0\u8282\u5F15\u7528\u3002"
|
|
30205
31010
|
);
|
|
30206
31011
|
}
|
|
30207
31012
|
const absolutePath = resolvePlannedAsset(asset["path"]);
|
|
30208
31013
|
if (!isWithinDirectory(absolutePath, assetsDirectory)) {
|
|
30209
31014
|
throw new WechatCliError(
|
|
30210
31015
|
"DXC_PUBLISHING_VISUAL_PLAN_INVALID",
|
|
30211
|
-
`\u89C6\u89C9\u8BA1\u5212\u58F0\u660E\u7684\u7D20\u6750 ${
|
|
31016
|
+
`\u89C6\u89C9\u8BA1\u5212\u58F0\u660E\u7684\u7D20\u6750 ${path6.posix.basename(asset["path"])} \u4E0D\u5728\u6307\u5B9A\u7D20\u6750\u76EE\u5F55\u4E2D\u3002`
|
|
30212
31017
|
);
|
|
30213
31018
|
}
|
|
30214
31019
|
await readContainedPublishingInput(
|
|
30215
31020
|
absolutePath,
|
|
30216
|
-
|
|
31021
|
+
maximumInlineBytes,
|
|
30217
31022
|
[assetsDirectory],
|
|
30218
31023
|
"inline-image"
|
|
30219
31024
|
);
|
|
@@ -30224,13 +31029,14 @@ async function plannedVisualAssets(visualPlanFile, assetsDirectoryInput) {
|
|
|
30224
31029
|
"\u6B63\u6587\u914D\u56FE\u7684\u539F\u59CB\u8DEF\u5F84\u5FC5\u987B\u662F\u9879\u76EE\u5185\u5B89\u5168\u76F8\u5BF9\u8DEF\u5F84\u3002"
|
|
30225
31030
|
);
|
|
30226
31031
|
}
|
|
30227
|
-
const digest =
|
|
30228
|
-
const fileName = safeFileName(
|
|
31032
|
+
const digest = createHash5("sha256").update(absolutePath).digest("hex").slice(0, 12);
|
|
31033
|
+
const fileName = safeFileName(path6.basename(absolutePath)) || `visual-${digest}.png`;
|
|
30229
31034
|
return {
|
|
30230
31035
|
absolutePath,
|
|
30231
|
-
alt: typeof asset["purpose"] === "string" ? asset["purpose"] :
|
|
31036
|
+
alt: typeof asset["purpose"] === "string" ? asset["purpose"] : path6.basename(absolutePath, path6.extname(absolutePath)),
|
|
30232
31037
|
logicalPath: `assets/dxc-visuals/${digest}-${fileName}`,
|
|
30233
|
-
|
|
31038
|
+
...typeof headingIndex === "number" ? { headingIndex } : {},
|
|
31039
|
+
...typeof asset["placementAnchor"] === "string" ? { placementAnchor: asset["placementAnchor"] } : {},
|
|
30234
31040
|
plannedPath: asset["path"],
|
|
30235
31041
|
...sourceLogicalPath === void 0 ? {} : { sourceLogicalPath }
|
|
30236
31042
|
};
|
|
@@ -30248,7 +31054,7 @@ function publishingArticleSource(source, digestOverride) {
|
|
|
30248
31054
|
if (yamlSource === void 0 || body === void 0) {
|
|
30249
31055
|
throw new WechatCliError("DXC_PUBLISHING_ARTICLE_INVALID");
|
|
30250
31056
|
}
|
|
30251
|
-
const document = (0,
|
|
31057
|
+
const document = (0, import_yaml3.parseDocument)(yamlSource, { uniqueKeys: true });
|
|
30252
31058
|
if (document.errors.length > 0) {
|
|
30253
31059
|
throw new WechatCliError("DXC_PUBLISHING_ARTICLE_INVALID");
|
|
30254
31060
|
}
|
|
@@ -30273,21 +31079,21 @@ async function preparePublishingDraft(input) {
|
|
|
30273
31079
|
} catch {
|
|
30274
31080
|
throw new WechatCliError("DXC_PUBLISHING_ARTICLE_INVALID");
|
|
30275
31081
|
}
|
|
30276
|
-
const articleDirectory =
|
|
31082
|
+
const articleDirectory = path6.dirname(articleInput.path);
|
|
30277
31083
|
const availableImages = await collectedImages(input.assetsDirectory, articleDirectory);
|
|
30278
31084
|
const availableByFileName = new Map(
|
|
30279
|
-
availableImages.map((candidate) => [
|
|
31085
|
+
availableImages.map((candidate) => [path6.basename(candidate), candidate])
|
|
30280
31086
|
);
|
|
30281
|
-
const projectDirectory = input.assetsDirectory === void 0 ? articleDirectory : commonDirectory(articleDirectory,
|
|
30282
|
-
const resolveDeclaredAsset = (logicalPath) => availableByFileName.get(
|
|
31087
|
+
const projectDirectory = input.assetsDirectory === void 0 ? articleDirectory : commonDirectory(articleDirectory, path6.resolve(input.assetsDirectory));
|
|
31088
|
+
const resolveDeclaredAsset = (logicalPath) => availableByFileName.get(path6.posix.basename(logicalPath)) ?? path6.resolve(projectDirectory, logicalPath);
|
|
30283
31089
|
const referenced = new Set(logicalInlinePaths(originalBundle));
|
|
30284
31090
|
const automaticAssetDirectories = [
|
|
30285
31091
|
articleDirectory,
|
|
30286
|
-
...input.assetsDirectory === void 0 ? [] : [
|
|
31092
|
+
...input.assetsDirectory === void 0 ? [] : [path6.resolve(input.assetsDirectory)]
|
|
30287
31093
|
];
|
|
30288
31094
|
const articleCoverCandidate = originalBundle.coverImage !== void 0 && isSafeLogicalAssetPath(originalBundle.coverImage) ? resolveDeclaredAsset(originalBundle.coverImage) : void 0;
|
|
30289
31095
|
const namedCoverCandidate = availableImages.find(
|
|
30290
|
-
(candidate) => /^cover(?:[._-]|$)/iu.test(
|
|
31096
|
+
(candidate) => /^cover(?:[._-]|$)/iu.test(path6.basename(candidate))
|
|
30291
31097
|
);
|
|
30292
31098
|
const explicitCover = input.coverFile !== void 0 && input.coverFile !== "auto" ? input.coverFile : void 0;
|
|
30293
31099
|
const planned = input.visualPlanFile === void 0 ? void 0 : await plannedVisualAssets(input.visualPlanFile, input.assetsDirectory);
|
|
@@ -30313,16 +31119,16 @@ async function preparePublishingDraft(input) {
|
|
|
30313
31119
|
const coverCandidate = explicitCover ?? planned?.coverAbsolutePath ?? articleCoverCandidate ?? namedCoverCandidate;
|
|
30314
31120
|
const coverMode = explicitCover !== void 0 ? "explicit-file" : planned?.coverAbsolutePath !== void 0 ? "visual-plan" : articleCoverCandidate !== void 0 ? "article-frontmatter" : namedCoverCandidate !== void 0 ? "assets-directory" : void 0;
|
|
30315
31121
|
const pickupCandidates = availableImages.filter(
|
|
30316
|
-
(candidate) => candidate !== namedCoverCandidate && candidate !== articleCoverCandidate && !referencedFiles.has(
|
|
31122
|
+
(candidate) => candidate !== namedCoverCandidate && candidate !== articleCoverCandidate && !referencedFiles.has(path6.resolve(candidate)) && input.visualPlanFile === void 0
|
|
30317
31123
|
);
|
|
30318
31124
|
const injected = [
|
|
30319
31125
|
...plannedInlineForInjection,
|
|
30320
31126
|
...pickupCandidates.slice(0, Math.max(0, MAXIMUM_INLINE_IMAGES - referenced.size)).map((candidate) => {
|
|
30321
|
-
const digest =
|
|
30322
|
-
const fileName = safeFileName(
|
|
31127
|
+
const digest = createHash5("sha256").update(candidate).digest("hex").slice(0, 12);
|
|
31128
|
+
const fileName = safeFileName(path6.basename(candidate)) || `visual-${digest}.png`;
|
|
30323
31129
|
return {
|
|
30324
31130
|
absolutePath: candidate,
|
|
30325
|
-
alt:
|
|
31131
|
+
alt: path6.basename(candidate, path6.extname(candidate)),
|
|
30326
31132
|
logicalPath: `assets/dxc-visuals/${digest}-${fileName}`
|
|
30327
31133
|
};
|
|
30328
31134
|
}).filter((asset) => !referenced.has(asset.logicalPath))
|
|
@@ -30366,7 +31172,7 @@ async function preparePublishingDraft(input) {
|
|
|
30366
31172
|
);
|
|
30367
31173
|
const inlineAssets = await Promise.all(
|
|
30368
31174
|
logicalInlinePaths(bundle).map(async (logicalPath) => {
|
|
30369
|
-
const target = injectedByLogicalPath.get(logicalPath) ?? referencedFilesByLogicalPath.get(logicalPath) ??
|
|
31175
|
+
const target = injectedByLogicalPath.get(logicalPath) ?? referencedFilesByLogicalPath.get(logicalPath) ?? path6.resolve(articleDirectory, logicalPath);
|
|
30370
31176
|
const asset = await readContainedPublishingInput(
|
|
30371
31177
|
target,
|
|
30372
31178
|
MAXIMUM_INLINE_IMAGE_BYTES,
|
|
@@ -30407,354 +31213,6 @@ async function preparePublishingDraft(input) {
|
|
|
30407
31213
|
};
|
|
30408
31214
|
}
|
|
30409
31215
|
|
|
30410
|
-
// apps/cli/src/publishing-image-optimization.ts
|
|
30411
|
-
var import_yaml3 = __toESM(require_dist(), 1);
|
|
30412
|
-
import { createHash as createHash5, randomUUID as randomUUID3 } from "node:crypto";
|
|
30413
|
-
import { constants as fileConstants2 } from "node:fs";
|
|
30414
|
-
import {
|
|
30415
|
-
lstat as lstat5,
|
|
30416
|
-
mkdir as mkdir3,
|
|
30417
|
-
open as open2,
|
|
30418
|
-
readFile as readFile2,
|
|
30419
|
-
realpath as realpath2,
|
|
30420
|
-
rename as rename3,
|
|
30421
|
-
unlink,
|
|
30422
|
-
writeFile
|
|
30423
|
-
} from "node:fs/promises";
|
|
30424
|
-
import path6 from "node:path";
|
|
30425
|
-
import sharp2 from "sharp";
|
|
30426
|
-
var MAXIMUM_INPUT_BYTES = 32 * 1024 * 1024;
|
|
30427
|
-
var INLINE_IMAGE_LIMIT = 1024 * 1024 - 1;
|
|
30428
|
-
var INLINE_IMAGE_TARGET = 950 * 1024;
|
|
30429
|
-
var COVER_IMAGE_LIMIT = 5 * 1024 * 1024;
|
|
30430
|
-
var COVER_IMAGE_TARGET = 4500 * 1024;
|
|
30431
|
-
var VISUAL_PLAN_MAXIMUM_BYTES2 = 128 * 1024;
|
|
30432
|
-
var VISUAL_PLAN_FRONTMATTER2 = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)([\s\S]*)$/u;
|
|
30433
|
-
function sha256(value) {
|
|
30434
|
-
return createHash5("sha256").update(value).digest("hex");
|
|
30435
|
-
}
|
|
30436
|
-
function safeDerivativeBase(value) {
|
|
30437
|
-
return value.normalize("NFKC").replaceAll(/[^A-Za-z0-9._-]+/gu, "-").replaceAll(/^-+|-+$/gu, "").slice(0, 80) || "image";
|
|
30438
|
-
}
|
|
30439
|
-
function recordValue2(value) {
|
|
30440
|
-
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
30441
|
-
}
|
|
30442
|
-
function portablePath(value, label) {
|
|
30443
|
-
if (typeof value !== "string" || value.trim().length === 0 || path6.isAbsolute(value) || value.includes("\\") || value.split("/").some((segment) => segment === "" || segment === "." || segment === "..")) {
|
|
30444
|
-
throw new WechatCliError(
|
|
30445
|
-
"DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
|
|
30446
|
-
`${label} \u5FC5\u987B\u662F\u9879\u76EE\u5185\u4F7F\u7528 / \u5206\u9694\u7684\u5B89\u5168\u76F8\u5BF9\u8DEF\u5F84\u3002`
|
|
30447
|
-
);
|
|
30448
|
-
}
|
|
30449
|
-
return value;
|
|
30450
|
-
}
|
|
30451
|
-
function isWithin(target, directory) {
|
|
30452
|
-
const relative = path6.relative(directory, target);
|
|
30453
|
-
return relative === "" || !relative.startsWith(`..${path6.sep}`) && relative !== "..";
|
|
30454
|
-
}
|
|
30455
|
-
async function regularImage(target) {
|
|
30456
|
-
let handle;
|
|
30457
|
-
try {
|
|
30458
|
-
handle = await open2(target, fileConstants2.O_RDONLY | fileConstants2.O_NOFOLLOW);
|
|
30459
|
-
const metadata = await handle.stat();
|
|
30460
|
-
if (!metadata.isFile() || metadata.size <= 0 || metadata.size > MAXIMUM_INPUT_BYTES) {
|
|
30461
|
-
throw new Error("invalid image");
|
|
30462
|
-
}
|
|
30463
|
-
return await handle.readFile();
|
|
30464
|
-
} catch {
|
|
30465
|
-
throw new WechatCliError(
|
|
30466
|
-
"DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
|
|
30467
|
-
`\u65E0\u6CD5\u5B89\u5168\u8BFB\u53D6\u56FE\u7247 ${path6.basename(target)}\uFF1B\u6587\u4EF6\u5FC5\u987B\u662F\u5C0F\u4E8E ${MAXIMUM_INPUT_BYTES} bytes \u7684\u666E\u901A\u6587\u4EF6\u3002`
|
|
30468
|
-
);
|
|
30469
|
-
} finally {
|
|
30470
|
-
await handle?.close();
|
|
30471
|
-
}
|
|
30472
|
-
}
|
|
30473
|
-
async function requirePreservedAlpha(bytes) {
|
|
30474
|
-
const metadata = await sharp2(bytes, {
|
|
30475
|
-
failOn: "error",
|
|
30476
|
-
limitInputPixels: 8e7
|
|
30477
|
-
}).metadata();
|
|
30478
|
-
if (metadata.format !== "png" || metadata.hasAlpha !== true) {
|
|
30479
|
-
throw new WechatCliError(
|
|
30480
|
-
"DXC_PUBLISHING_IMAGE_ALPHA_LOST",
|
|
30481
|
-
"\u900F\u660E\u56FE\u7247\u4F18\u5316\u540E\u4E22\u5931\u900F\u660E\u901A\u9053\uFF1B\u5DF2\u963B\u65AD\u4E14\u4E0D\u4F1A\u8986\u76D6\u539F\u56FE\u3002"
|
|
30482
|
-
);
|
|
30483
|
-
}
|
|
30484
|
-
}
|
|
30485
|
-
async function decodedImageMetadata(source, sourcePath) {
|
|
30486
|
-
let metadata;
|
|
30487
|
-
try {
|
|
30488
|
-
metadata = await sharp2(source, { failOn: "error", limitInputPixels: 8e7 }).metadata();
|
|
30489
|
-
} catch {
|
|
30490
|
-
throw new WechatCliError(
|
|
30491
|
-
"DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
|
|
30492
|
-
"\u56FE\u7247\u65E0\u6CD5\u88AB\u5B89\u5168\u89E3\u7801\uFF1B\u4EC5\u652F\u6301\u6709\u6548 PNG/JPEG\u3002"
|
|
30493
|
-
);
|
|
30494
|
-
}
|
|
30495
|
-
const extension = path6.extname(sourcePath).toLowerCase();
|
|
30496
|
-
const expectedFormat = extension === ".png" ? "png" : extension === ".jpg" || extension === ".jpeg" ? "jpeg" : void 0;
|
|
30497
|
-
if (expectedFormat === void 0 || metadata.format !== expectedFormat || metadata.width === void 0 || metadata.height === void 0) {
|
|
30498
|
-
throw new WechatCliError(
|
|
30499
|
-
"DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
|
|
30500
|
-
"\u56FE\u7247\u6269\u5C55\u540D\u3001\u771F\u5B9E\u683C\u5F0F\u6216\u5C3A\u5BF8\u65E0\u6548\uFF1B\u4EC5\u652F\u6301\u6269\u5C55\u540D\u4E0E\u5185\u5BB9\u4E00\u81F4\u7684 PNG/JPEG\u3002"
|
|
30501
|
-
);
|
|
30502
|
-
}
|
|
30503
|
-
return {
|
|
30504
|
-
format: expectedFormat,
|
|
30505
|
-
hasAlpha: metadata.hasAlpha === true,
|
|
30506
|
-
height: metadata.height,
|
|
30507
|
-
width: metadata.width
|
|
30508
|
-
};
|
|
30509
|
-
}
|
|
30510
|
-
async function writeExclusiveOrVerify(target, bytes) {
|
|
30511
|
-
await mkdir3(path6.dirname(target), { recursive: true, mode: 448 });
|
|
30512
|
-
try {
|
|
30513
|
-
await writeFile(target, bytes, { flag: "wx", mode: 384 });
|
|
30514
|
-
return true;
|
|
30515
|
-
} catch (error) {
|
|
30516
|
-
if (error.code !== "EEXIST") {
|
|
30517
|
-
throw error;
|
|
30518
|
-
}
|
|
30519
|
-
const existing = await regularImage(target);
|
|
30520
|
-
if (sha256(existing) !== sha256(bytes)) {
|
|
30521
|
-
throw new WechatCliError(
|
|
30522
|
-
"DXC_PUBLISHING_IMAGE_OPTIMIZATION_CONFLICT",
|
|
30523
|
-
`\u4F18\u5316\u76EE\u6807 ${path6.basename(target)} \u5DF2\u5B58\u5728\u4F46\u5185\u5BB9\u4E0D\u540C\uFF1B\u672A\u8986\u76D6\u4EFB\u4F55\u6587\u4EF6\u3002`
|
|
30524
|
-
);
|
|
30525
|
-
}
|
|
30526
|
-
return false;
|
|
30527
|
-
}
|
|
30528
|
-
}
|
|
30529
|
-
async function safeRealPathWithin(target, directory, label) {
|
|
30530
|
-
const resolved = await realpath2(target).catch(() => void 0);
|
|
30531
|
-
if (resolved === void 0 || !isWithin(resolved, directory)) {
|
|
30532
|
-
throw new WechatCliError(
|
|
30533
|
-
"DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
|
|
30534
|
-
`${label} \u7684\u771F\u5B9E\u8DEF\u5F84\u4E0D\u5728\u5141\u8BB8\u7684\u9879\u76EE\u76EE\u5F55\u5185\u3002`
|
|
30535
|
-
);
|
|
30536
|
-
}
|
|
30537
|
-
return resolved;
|
|
30538
|
-
}
|
|
30539
|
-
async function ensureSafeOptimizedDirectory(assetsDirectory, realAssetsDirectory) {
|
|
30540
|
-
const optimizedDirectory = path6.join(assetsDirectory, "optimized");
|
|
30541
|
-
await mkdir3(optimizedDirectory, { recursive: true, mode: 448 });
|
|
30542
|
-
const metadata = await lstat5(optimizedDirectory).catch(() => void 0);
|
|
30543
|
-
if (metadata === void 0 || !metadata.isDirectory() || metadata.isSymbolicLink()) {
|
|
30544
|
-
throw new WechatCliError(
|
|
30545
|
-
"DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
|
|
30546
|
-
"\u4F18\u5316\u76EE\u5F55\u5FC5\u987B\u662F\u7D20\u6750\u76EE\u5F55\u5185\u7684\u666E\u901A\u76EE\u5F55\uFF0C\u4E0D\u80FD\u662F\u7B26\u53F7\u94FE\u63A5\u3002"
|
|
30547
|
-
);
|
|
30548
|
-
}
|
|
30549
|
-
await safeRealPathWithin(optimizedDirectory, realAssetsDirectory, "\u4F18\u5316\u76EE\u5F55");
|
|
30550
|
-
return optimizedDirectory;
|
|
30551
|
-
}
|
|
30552
|
-
async function writePlanAtomically(target, expectedSource, source) {
|
|
30553
|
-
const temporary = `${target}.${randomUUID3()}.tmp`;
|
|
30554
|
-
try {
|
|
30555
|
-
await writeFile(temporary, source, { encoding: "utf8", flag: "wx", mode: 384 });
|
|
30556
|
-
if (await readFile2(target, "utf8") !== expectedSource) {
|
|
30557
|
-
throw new WechatCliError(
|
|
30558
|
-
"DXC_PUBLISHING_IMAGE_OPTIMIZATION_CONFLICT",
|
|
30559
|
-
"\u89C6\u89C9\u8BA1\u5212\u5728\u56FE\u7247\u4F18\u5316\u671F\u95F4\u5DF2\u88AB\u5176\u4ED6\u64CD\u4F5C\u4FEE\u6539\uFF1B\u672A\u8986\u76D6\u65B0\u5185\u5BB9\uFF0C\u8BF7\u91CD\u65B0\u8BFB\u53D6\u540E\u518D\u8BD5\u3002"
|
|
30560
|
-
);
|
|
30561
|
-
}
|
|
30562
|
-
await rename3(temporary, target);
|
|
30563
|
-
} finally {
|
|
30564
|
-
await unlink(temporary).catch(() => void 0);
|
|
30565
|
-
}
|
|
30566
|
-
}
|
|
30567
|
-
function candidateWidths(width) {
|
|
30568
|
-
return [.../* @__PURE__ */ new Set([width, 2400, 2e3, 1600, 1280, 1080, 900, 720])].filter((candidate) => candidate > 0 && candidate <= width).sort((left, right) => right - left);
|
|
30569
|
-
}
|
|
30570
|
-
async function optimizedImage(source, targetBytes, metadata) {
|
|
30571
|
-
const hasAlpha = metadata.hasAlpha;
|
|
30572
|
-
for (const width of candidateWidths(metadata.width)) {
|
|
30573
|
-
if (hasAlpha) {
|
|
30574
|
-
const lossless = await sharp2(source, { failOn: "error", limitInputPixels: 8e7 }).rotate().resize({ fit: "inside", width, withoutEnlargement: true }).png({ compressionLevel: 9, effort: 10 }).toBuffer();
|
|
30575
|
-
if (lossless.byteLength <= targetBytes) {
|
|
30576
|
-
await requirePreservedAlpha(lossless);
|
|
30577
|
-
return { alphaPreserved: true, bytes: lossless, extension: ".png" };
|
|
30578
|
-
}
|
|
30579
|
-
for (const colours of [256, 192, 128, 96, 64]) {
|
|
30580
|
-
const quantized = await sharp2(source, {
|
|
30581
|
-
failOn: "error",
|
|
30582
|
-
limitInputPixels: 8e7
|
|
30583
|
-
}).rotate().resize({ fit: "inside", width, withoutEnlargement: true }).png({ colours, compressionLevel: 9, effort: 10, palette: true }).toBuffer();
|
|
30584
|
-
if (quantized.byteLength <= targetBytes) {
|
|
30585
|
-
await requirePreservedAlpha(quantized);
|
|
30586
|
-
return { alphaPreserved: true, bytes: quantized, extension: ".png" };
|
|
30587
|
-
}
|
|
30588
|
-
}
|
|
30589
|
-
continue;
|
|
30590
|
-
}
|
|
30591
|
-
for (const quality of [88, 82, 76, 70, 64, 58]) {
|
|
30592
|
-
const jpeg = await sharp2(source, { failOn: "error", limitInputPixels: 8e7 }).rotate().resize({ fit: "inside", width, withoutEnlargement: true }).jpeg({ chromaSubsampling: "4:4:4", mozjpeg: true, progressive: true, quality }).toBuffer();
|
|
30593
|
-
if (jpeg.byteLength <= targetBytes) {
|
|
30594
|
-
return { alphaPreserved: true, bytes: jpeg, extension: ".jpg" };
|
|
30595
|
-
}
|
|
30596
|
-
}
|
|
30597
|
-
}
|
|
30598
|
-
throw new WechatCliError(
|
|
30599
|
-
"DXC_PUBLISHING_IMAGE_OPTIMIZATION_LIMIT_UNREACHABLE",
|
|
30600
|
-
`\u65E0\u6CD5\u5728\u4E0D\u4E22\u5931\u900F\u660E\u901A\u9053\u6216\u4F4E\u4E8E\u6700\u5C0F\u5C3A\u5BF8\u7B56\u7565\u7684\u524D\u63D0\u4E0B\u538B\u5230 ${targetBytes} bytes\uFF1B\u8BF7\u66F4\u6362\u6216\u88C1\u526A\u56FE\u7247\u3002`
|
|
30601
|
-
);
|
|
30602
|
-
}
|
|
30603
|
-
async function optimizePublishingImages(input) {
|
|
30604
|
-
const projectDirectory = path6.resolve(input.projectDirectory);
|
|
30605
|
-
const visualPlanPath = path6.resolve(input.visualPlanFile);
|
|
30606
|
-
if (!isWithin(visualPlanPath, projectDirectory)) {
|
|
30607
|
-
throw new WechatCliError(
|
|
30608
|
-
"DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
|
|
30609
|
-
"\u89C6\u89C9\u8BA1\u5212\u5FC5\u987B\u4F4D\u4E8E\u5F53\u524D\u5185\u5BB9\u9879\u76EE\u5185\u3002"
|
|
30610
|
-
);
|
|
30611
|
-
}
|
|
30612
|
-
const projectMetadata = await lstat5(projectDirectory).catch(() => void 0);
|
|
30613
|
-
const visualPlanMetadata = await lstat5(visualPlanPath).catch(() => void 0);
|
|
30614
|
-
if (projectMetadata === void 0 || !projectMetadata.isDirectory() || projectMetadata.isSymbolicLink() || visualPlanMetadata === void 0 || !visualPlanMetadata.isFile() || visualPlanMetadata.isSymbolicLink() || visualPlanMetadata.size > VISUAL_PLAN_MAXIMUM_BYTES2) {
|
|
30615
|
-
throw new WechatCliError(
|
|
30616
|
-
"DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
|
|
30617
|
-
"\u5185\u5BB9\u9879\u76EE\u548C\u89C6\u89C9\u8BA1\u5212\u5FC5\u987B\u662F\u975E\u7B26\u53F7\u94FE\u63A5\u7684\u666E\u901A\u76EE\u5F55\u4E0E\u6587\u4EF6\u3002"
|
|
30618
|
-
);
|
|
30619
|
-
}
|
|
30620
|
-
const realProjectDirectory = await realpath2(projectDirectory);
|
|
30621
|
-
await safeRealPathWithin(visualPlanPath, realProjectDirectory, "\u89C6\u89C9\u8BA1\u5212");
|
|
30622
|
-
const source = await readFile2(visualPlanPath, "utf8").catch(() => "");
|
|
30623
|
-
if (Buffer.byteLength(source, "utf8") > VISUAL_PLAN_MAXIMUM_BYTES2) {
|
|
30624
|
-
throw new WechatCliError("DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID");
|
|
30625
|
-
}
|
|
30626
|
-
const match = VISUAL_PLAN_FRONTMATTER2.exec(source);
|
|
30627
|
-
if (match?.[1] === void 0 || match[2] === void 0) {
|
|
30628
|
-
throw new WechatCliError("DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID");
|
|
30629
|
-
}
|
|
30630
|
-
let frontmatter2;
|
|
30631
|
-
try {
|
|
30632
|
-
frontmatter2 = recordValue2((0, import_yaml3.parse)(match[1], { maxAliasCount: 10, uniqueKeys: true }));
|
|
30633
|
-
} catch {
|
|
30634
|
-
throw new WechatCliError("DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID");
|
|
30635
|
-
}
|
|
30636
|
-
if (frontmatter2 === void 0) {
|
|
30637
|
-
throw new WechatCliError(
|
|
30638
|
-
"DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
|
|
30639
|
-
"\u89C6\u89C9\u8BA1\u5212\u7684 YAML \u5934\u65E0\u6CD5\u8BFB\u53D6\u3002"
|
|
30640
|
-
);
|
|
30641
|
-
}
|
|
30642
|
-
const assetsRelative = frontmatter2["assetsDirectory"] === void 0 ? "assets" : portablePath(frontmatter2["assetsDirectory"], "assetsDirectory");
|
|
30643
|
-
frontmatter2["assetsDirectory"] = assetsRelative;
|
|
30644
|
-
frontmatter2["inlineImagesSupported"] = true;
|
|
30645
|
-
const assetsDirectory = path6.resolve(projectDirectory, assetsRelative);
|
|
30646
|
-
if (!isWithin(assetsDirectory, projectDirectory)) {
|
|
30647
|
-
throw new WechatCliError("DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID");
|
|
30648
|
-
}
|
|
30649
|
-
const assetsMetadata = await lstat5(assetsDirectory).catch(() => void 0);
|
|
30650
|
-
if (assetsMetadata === void 0 || !assetsMetadata.isDirectory() || assetsMetadata.isSymbolicLink()) {
|
|
30651
|
-
throw new WechatCliError("DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID");
|
|
30652
|
-
}
|
|
30653
|
-
const realAssetsDirectory = await safeRealPathWithin(
|
|
30654
|
-
assetsDirectory,
|
|
30655
|
-
realProjectDirectory,
|
|
30656
|
-
"\u7D20\u6750\u76EE\u5F55"
|
|
30657
|
-
);
|
|
30658
|
-
const inlineAssets = Array.isArray(frontmatter2["inlineAssets"]) ? frontmatter2["inlineAssets"] : [];
|
|
30659
|
-
const entries = [
|
|
30660
|
-
{
|
|
30661
|
-
limit: COVER_IMAGE_LIMIT,
|
|
30662
|
-
record: { path: frontmatter2["coverAsset"] },
|
|
30663
|
-
role: "cover",
|
|
30664
|
-
target: COVER_IMAGE_TARGET
|
|
30665
|
-
},
|
|
30666
|
-
...inlineAssets.map((asset) => ({
|
|
30667
|
-
limit: INLINE_IMAGE_LIMIT,
|
|
30668
|
-
record: recordValue2(asset),
|
|
30669
|
-
role: "inline",
|
|
30670
|
-
target: INLINE_IMAGE_TARGET
|
|
30671
|
-
}))
|
|
30672
|
-
];
|
|
30673
|
-
const createdFiles = [];
|
|
30674
|
-
const mutations = [];
|
|
30675
|
-
let unchangedCount = 0;
|
|
30676
|
-
let optimizedDirectory;
|
|
30677
|
-
try {
|
|
30678
|
-
for (const entry of entries) {
|
|
30679
|
-
const assetPath = portablePath(entry.record?.["path"], `${entry.role} \u56FE\u7247\u8DEF\u5F84`);
|
|
30680
|
-
const absolutePath = path6.resolve(projectDirectory, assetPath);
|
|
30681
|
-
if (!isWithin(absolutePath, assetsDirectory)) {
|
|
30682
|
-
throw new WechatCliError(
|
|
30683
|
-
"DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
|
|
30684
|
-
`${assetPath} \u4E0D\u5728\u89C6\u89C9\u8BA1\u5212\u58F0\u660E\u7684\u7D20\u6750\u76EE\u5F55\u5185\u3002`
|
|
30685
|
-
);
|
|
30686
|
-
}
|
|
30687
|
-
await safeRealPathWithin(absolutePath, realAssetsDirectory, `${assetPath} \u56FE\u7247`);
|
|
30688
|
-
const bytes = await regularImage(absolutePath);
|
|
30689
|
-
const metadata = await decodedImageMetadata(bytes, assetPath);
|
|
30690
|
-
const beforeSha256 = sha256(bytes);
|
|
30691
|
-
let finalPath = assetPath;
|
|
30692
|
-
let finalBytes = bytes;
|
|
30693
|
-
let alphaPreserved = true;
|
|
30694
|
-
if (bytes.byteLength > entry.limit) {
|
|
30695
|
-
const optimized = await optimizedImage(bytes, entry.target, metadata);
|
|
30696
|
-
optimizedDirectory ??= await ensureSafeOptimizedDirectory(
|
|
30697
|
-
assetsDirectory,
|
|
30698
|
-
realAssetsDirectory
|
|
30699
|
-
);
|
|
30700
|
-
const baseName = safeDerivativeBase(path6.basename(assetPath, path6.extname(assetPath)));
|
|
30701
|
-
const optimizedSha256 = sha256(optimized.bytes);
|
|
30702
|
-
const optimizedName = `${baseName}-${entry.role}-${beforeSha256.slice(0, 12)}-${optimizedSha256.slice(0, 12)}${optimized.extension}`;
|
|
30703
|
-
const optimizedAbsolute = path6.join(optimizedDirectory, optimizedName);
|
|
30704
|
-
const created = await writeExclusiveOrVerify(optimizedAbsolute, optimized.bytes);
|
|
30705
|
-
if (created) {
|
|
30706
|
-
createdFiles.push(optimizedAbsolute);
|
|
30707
|
-
}
|
|
30708
|
-
finalPath = path6.relative(projectDirectory, optimizedAbsolute).split(path6.sep).join("/");
|
|
30709
|
-
finalBytes = optimized.bytes;
|
|
30710
|
-
alphaPreserved = optimized.alphaPreserved;
|
|
30711
|
-
mutations.push({
|
|
30712
|
-
alphaPreserved,
|
|
30713
|
-
afterBytes: finalBytes.byteLength,
|
|
30714
|
-
afterSha256: sha256(finalBytes),
|
|
30715
|
-
beforeBytes: bytes.byteLength,
|
|
30716
|
-
beforeSha256,
|
|
30717
|
-
from: assetPath,
|
|
30718
|
-
role: entry.role,
|
|
30719
|
-
to: finalPath
|
|
30720
|
-
});
|
|
30721
|
-
} else {
|
|
30722
|
-
unchangedCount += 1;
|
|
30723
|
-
}
|
|
30724
|
-
if (entry.role === "cover") {
|
|
30725
|
-
frontmatter2["coverAsset"] = finalPath;
|
|
30726
|
-
frontmatter2["coverSha256"] = sha256(finalBytes);
|
|
30727
|
-
} else if (entry.record !== void 0) {
|
|
30728
|
-
if (finalPath !== assetPath && entry.record["sourcePath"] === void 0) {
|
|
30729
|
-
entry.record["sourcePath"] = assetPath;
|
|
30730
|
-
}
|
|
30731
|
-
entry.record["path"] = finalPath;
|
|
30732
|
-
entry.record["sha256"] = sha256(finalBytes);
|
|
30733
|
-
}
|
|
30734
|
-
}
|
|
30735
|
-
frontmatter2["inlineAssets"] = inlineAssets;
|
|
30736
|
-
const normalizedSource = `---
|
|
30737
|
-
${(0, import_yaml3.stringify)(frontmatter2, { lineWidth: 0 }).trimEnd()}
|
|
30738
|
-
---
|
|
30739
|
-
${match[2]}`;
|
|
30740
|
-
await writePlanAtomically(visualPlanPath, source, normalizedSource);
|
|
30741
|
-
} catch (error) {
|
|
30742
|
-
await Promise.all(createdFiles.map((target) => unlink(target).catch(() => void 0)));
|
|
30743
|
-
if (error instanceof WechatCliError) {
|
|
30744
|
-
throw error;
|
|
30745
|
-
}
|
|
30746
|
-
throw new WechatCliError(
|
|
30747
|
-
"DXC_PUBLISHING_IMAGE_OPTIMIZATION_FAILED",
|
|
30748
|
-
"\u56FE\u7247\u4F18\u5316\u672A\u5B8C\u6210\uFF1B\u539F\u56FE\u548C\u89C6\u89C9\u8BA1\u5212\u5747\u672A\u88AB\u8986\u76D6\u3002"
|
|
30749
|
-
);
|
|
30750
|
-
}
|
|
30751
|
-
return {
|
|
30752
|
-
command: "wechat.draft.optimize-images",
|
|
30753
|
-
data: { mutations, unchangedCount, visualPlanPath },
|
|
30754
|
-
ok: true
|
|
30755
|
-
};
|
|
30756
|
-
}
|
|
30757
|
-
|
|
30758
31216
|
// apps/cli/src/wechat.ts
|
|
30759
31217
|
var DEFAULT_API_BASE_URL = "https://content.deployxai.com";
|
|
30760
31218
|
var DEFAULT_POLL_INTERVAL_MS = 2e3;
|
|
@@ -30868,19 +31326,19 @@ function localPreviewOutputConflict() {
|
|
|
30868
31326
|
async function ensureLocalPreviewDirectory(directory) {
|
|
30869
31327
|
let metadata;
|
|
30870
31328
|
try {
|
|
30871
|
-
metadata = await
|
|
31329
|
+
metadata = await lstat5(directory);
|
|
30872
31330
|
} catch (error) {
|
|
30873
31331
|
if (fileSystemErrorCode(error) !== "ENOENT") {
|
|
30874
31332
|
throw error;
|
|
30875
31333
|
}
|
|
30876
31334
|
try {
|
|
30877
|
-
await
|
|
31335
|
+
await mkdir5(directory, { mode: 448 });
|
|
30878
31336
|
} catch (mkdirError) {
|
|
30879
31337
|
if (fileSystemErrorCode(mkdirError) !== "EEXIST") {
|
|
30880
31338
|
throw mkdirError;
|
|
30881
31339
|
}
|
|
30882
31340
|
}
|
|
30883
|
-
metadata = await
|
|
31341
|
+
metadata = await lstat5(directory);
|
|
30884
31342
|
}
|
|
30885
31343
|
if (!metadata.isDirectory() || metadata.isSymbolicLink()) {
|
|
30886
31344
|
throw localPreviewOutputConflict();
|
|
@@ -30895,7 +31353,7 @@ async function safeLocalPreviewOutput(options) {
|
|
|
30895
31353
|
throw localPreviewOutputConflict();
|
|
30896
31354
|
}
|
|
30897
31355
|
try {
|
|
30898
|
-
const projectMetadata = await
|
|
31356
|
+
const projectMetadata = await lstat5(projectDirectory);
|
|
30899
31357
|
if (!projectMetadata.isDirectory() || projectMetadata.isSymbolicLink()) {
|
|
30900
31358
|
throw localPreviewOutputConflict();
|
|
30901
31359
|
}
|
|
@@ -30906,7 +31364,7 @@ async function safeLocalPreviewOutput(options) {
|
|
|
30906
31364
|
await ensureLocalPreviewDirectory(directory);
|
|
30907
31365
|
}
|
|
30908
31366
|
try {
|
|
30909
|
-
const outputMetadata = await
|
|
31367
|
+
const outputMetadata = await lstat5(outputFile);
|
|
30910
31368
|
if (!outputMetadata.isFile() || outputMetadata.isSymbolicLink()) {
|
|
30911
31369
|
throw localPreviewOutputConflict();
|
|
30912
31370
|
}
|
|
@@ -31047,17 +31505,17 @@ async function readProtectedStateFile(target, invalidCode) {
|
|
|
31047
31505
|
}
|
|
31048
31506
|
}
|
|
31049
31507
|
async function saveSession(stateDirectory, session) {
|
|
31050
|
-
await
|
|
31508
|
+
await mkdir5(stateDirectory, { mode: 448, recursive: true });
|
|
31051
31509
|
await chmod(stateDirectory, 448);
|
|
31052
31510
|
const target = sessionPath(stateDirectory);
|
|
31053
31511
|
const temporary = `${target}.${process.pid}.tmp`;
|
|
31054
|
-
await
|
|
31512
|
+
await writeFile3(temporary, `${JSON.stringify(session)}
|
|
31055
31513
|
`, {
|
|
31056
31514
|
encoding: "utf8",
|
|
31057
31515
|
mode: 384
|
|
31058
31516
|
});
|
|
31059
31517
|
await chmod(temporary, 384);
|
|
31060
|
-
await
|
|
31518
|
+
await rename3(temporary, target);
|
|
31061
31519
|
await chmod(target, 384);
|
|
31062
31520
|
}
|
|
31063
31521
|
async function readSessionValue(stateDirectory) {
|
|
@@ -31180,17 +31638,17 @@ async function loadOrCreateDeviceIdentity(stateDirectory) {
|
|
|
31180
31638
|
publicKeyFingerprint: keyPair.publicKeyFingerprint,
|
|
31181
31639
|
publicKeyPem: keyPair.publicKeyPem
|
|
31182
31640
|
};
|
|
31183
|
-
await
|
|
31641
|
+
await mkdir5(stateDirectory, { mode: 448, recursive: true });
|
|
31184
31642
|
await chmod(stateDirectory, 448);
|
|
31185
31643
|
const target = deviceIdentityPath(stateDirectory);
|
|
31186
31644
|
const temporary = `${target}.${process.pid}.tmp`;
|
|
31187
|
-
await
|
|
31645
|
+
await writeFile3(temporary, `${JSON.stringify(identity)}
|
|
31188
31646
|
`, {
|
|
31189
31647
|
encoding: "utf8",
|
|
31190
31648
|
mode: 384
|
|
31191
31649
|
});
|
|
31192
31650
|
await chmod(temporary, 384);
|
|
31193
|
-
await
|
|
31651
|
+
await rename3(temporary, target);
|
|
31194
31652
|
await chmod(target, 384);
|
|
31195
31653
|
return { created: true, identity };
|
|
31196
31654
|
}
|
|
@@ -31811,6 +32269,17 @@ var WechatCli = class {
|
|
|
31811
32269
|
);
|
|
31812
32270
|
return result;
|
|
31813
32271
|
}
|
|
32272
|
+
async publishingDraftDiagnostics(intentId, output) {
|
|
32273
|
+
const session = await loadSession(this.#stateDirectory);
|
|
32274
|
+
const { response } = await this.#authenticatedFetch(
|
|
32275
|
+
session,
|
|
32276
|
+
`${session.apiBaseUrl}/api/v1/draft-intents/${encodeURIComponent(intentId)}/diagnostics`
|
|
32277
|
+
);
|
|
32278
|
+
const result = publishingDraftAttentionDiagnosticsSchema.parse(await checkedJson(response));
|
|
32279
|
+
output.writeStdout(`${JSON.stringify({ diagnostics: result })}
|
|
32280
|
+
`);
|
|
32281
|
+
return result;
|
|
32282
|
+
}
|
|
31814
32283
|
async reverifyDraft(intentId, output) {
|
|
31815
32284
|
const session = await loadSession(this.#stateDirectory);
|
|
31816
32285
|
const { response } = await this.#authenticatedFetch(
|
|
@@ -32255,28 +32724,36 @@ ${session.authorizationUrl}
|
|
|
32255
32724
|
};
|
|
32256
32725
|
|
|
32257
32726
|
// apps/cli/src/workflow-delivery.ts
|
|
32258
|
-
import { createHash as
|
|
32727
|
+
import { createHash as createHash8 } from "node:crypto";
|
|
32259
32728
|
import path9 from "node:path";
|
|
32260
32729
|
|
|
32261
32730
|
// apps/cli/src/workflow.ts
|
|
32262
|
-
import {
|
|
32731
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
32732
|
+
import { lstat as lstat6, readFile as readFile4 } from "node:fs/promises";
|
|
32263
32733
|
import path8 from "node:path";
|
|
32264
32734
|
var import_yaml4 = __toESM(require_dist(), 1);
|
|
32265
32735
|
var WORKFLOW_STATE_FILE = ".dxc/workflow.json";
|
|
32266
32736
|
var WORKFLOW_STATE_MAXIMUM_BYTES = 16 * 1024;
|
|
32267
32737
|
var ARTIFACT_MAXIMUM_BYTES = 5 * 1024 * 1024;
|
|
32268
32738
|
var FRONTMATTER = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/u;
|
|
32739
|
+
var WORK_ITEM_PATTERN = /^wi1_([A-Za-z0-9_-]+)\.([a-f0-9]{32})$/u;
|
|
32740
|
+
var SCAFFOLD_MARKER = "dxcScaffold: true";
|
|
32269
32741
|
var WorkflowCliError = class extends Error {
|
|
32270
|
-
constructor(code, message) {
|
|
32742
|
+
constructor(code, message, details) {
|
|
32271
32743
|
super(message);
|
|
32272
32744
|
this.code = code;
|
|
32745
|
+
this.details = details;
|
|
32273
32746
|
this.name = "WorkflowCliError";
|
|
32274
32747
|
}
|
|
32275
32748
|
code;
|
|
32749
|
+
details;
|
|
32276
32750
|
};
|
|
32277
32751
|
function isRecord(value) {
|
|
32278
32752
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
32279
32753
|
}
|
|
32754
|
+
function sha2562(value) {
|
|
32755
|
+
return createHash7("sha256").update(value).digest("hex");
|
|
32756
|
+
}
|
|
32280
32757
|
function workflowState(value, projectId) {
|
|
32281
32758
|
if (!isRecord(value) || value["version"] !== 1 || value["projectId"] !== projectId) {
|
|
32282
32759
|
return void 0;
|
|
@@ -32297,11 +32774,7 @@ function statePath(directory) {
|
|
|
32297
32774
|
return path8.join(directory, WORKFLOW_STATE_FILE);
|
|
32298
32775
|
}
|
|
32299
32776
|
function projectSummary(location) {
|
|
32300
|
-
return {
|
|
32301
|
-
directory: location.directory,
|
|
32302
|
-
projectId: location.manifest.projectId,
|
|
32303
|
-
title: location.manifest.title
|
|
32304
|
-
};
|
|
32777
|
+
return { projectId: location.manifest.projectId, title: location.manifest.title };
|
|
32305
32778
|
}
|
|
32306
32779
|
function nextStep(lastCompletedStep) {
|
|
32307
32780
|
const nextIndex = lastCompletedStep === null ? 0 : CONTENT_ARTIFACT_KINDS.indexOf(lastCompletedStep) + 1;
|
|
@@ -32312,23 +32785,16 @@ function previousStep(step) {
|
|
|
32312
32785
|
return index <= 0 ? null : CONTENT_ARTIFACT_KINDS[index - 1] ?? null;
|
|
32313
32786
|
}
|
|
32314
32787
|
function requestedStep(value) {
|
|
32315
|
-
|
|
32316
|
-
if (!CONTENT_ARTIFACT_KINDS.includes(step)) {
|
|
32788
|
+
if (!CONTENT_ARTIFACT_KINDS.includes(value)) {
|
|
32317
32789
|
throw new WorkflowCliError(
|
|
32318
32790
|
"DXC_WORKFLOW_STEP_INVALID",
|
|
32319
|
-
`\u672A\u77E5\u9636\u6BB5 ${
|
|
32791
|
+
`\u672A\u77E5\u9636\u6BB5 ${value}\u3002\u8BF7\u4F7F\u7528 ${CONTENT_ARTIFACT_KINDS.join("\u3001")}\u3002`
|
|
32320
32792
|
);
|
|
32321
32793
|
}
|
|
32322
|
-
return
|
|
32323
|
-
}
|
|
32324
|
-
function inputPaths(directory, manifest, step) {
|
|
32325
|
-
const inputs = CONTENT_STAGE_INPUTS[step];
|
|
32326
|
-
return [...inputs.required, ...inputs.optional].map(
|
|
32327
|
-
(kind) => path8.join(directory, manifest.artifacts[kind])
|
|
32328
|
-
);
|
|
32794
|
+
return value;
|
|
32329
32795
|
}
|
|
32330
32796
|
function requiresStageConfirmation(policy, step) {
|
|
32331
|
-
if (step ===
|
|
32797
|
+
if (step === "delivery" || policy === "auto-until-delivery") {
|
|
32332
32798
|
return false;
|
|
32333
32799
|
}
|
|
32334
32800
|
if (policy === "review-every-stage") {
|
|
@@ -32348,71 +32814,264 @@ function stageLabel(step) {
|
|
|
32348
32814
|
"visual-plan": "\u56FE\u7247\u548C\u89C6\u89C9\u7ED3\u679C"
|
|
32349
32815
|
}[step];
|
|
32350
32816
|
}
|
|
32351
|
-
function
|
|
32352
|
-
const
|
|
32353
|
-
|
|
32354
|
-
|
|
32355
|
-
|
|
32356
|
-
|
|
32357
|
-
|
|
32358
|
-
|
|
32359
|
-
|
|
32360
|
-
|
|
32361
|
-
}
|
|
32817
|
+
function frontmatter(source) {
|
|
32818
|
+
const yaml = FRONTMATTER.exec(source)?.[1];
|
|
32819
|
+
if (yaml === void 0) {
|
|
32820
|
+
return {};
|
|
32821
|
+
}
|
|
32822
|
+
try {
|
|
32823
|
+
const value = (0, import_yaml4.parse)(yaml, { maxAliasCount: 10, uniqueKeys: true });
|
|
32824
|
+
return isRecord(value) ? value : {};
|
|
32825
|
+
} catch {
|
|
32826
|
+
return {};
|
|
32827
|
+
}
|
|
32362
32828
|
}
|
|
32363
|
-
|
|
32364
|
-
const
|
|
32365
|
-
|
|
32829
|
+
function selectedTitle(value) {
|
|
32830
|
+
const title = value["selectedTitle"];
|
|
32831
|
+
return typeof title === "string" && title.trim().length > 0 ? title.trim() : void 0;
|
|
32832
|
+
}
|
|
32833
|
+
function artifactPath(location, kind) {
|
|
32834
|
+
return path8.join(location.directory, location.manifest.artifacts[kind]);
|
|
32835
|
+
}
|
|
32836
|
+
async function readArtifact(location, kind) {
|
|
32837
|
+
const target = path8.resolve(location.directory, location.manifest.artifacts[kind]);
|
|
32838
|
+
const relative = path8.relative(location.directory, target);
|
|
32366
32839
|
if (relative.startsWith("..") || path8.isAbsolute(relative)) {
|
|
32367
|
-
throw new WorkflowCliError(
|
|
32840
|
+
throw new WorkflowCliError(
|
|
32841
|
+
"DXC_WORKFLOW_ARTIFACT_INVALID",
|
|
32842
|
+
`${kind} \u4EA7\u7269\u8DEF\u5F84\u4E0D\u5728\u9879\u76EE\u76EE\u5F55\u4E2D\u3002`,
|
|
32843
|
+
{ path: target, stage: kind }
|
|
32844
|
+
);
|
|
32368
32845
|
}
|
|
32369
32846
|
try {
|
|
32370
|
-
const metadata = await
|
|
32847
|
+
const metadata = await lstat6(target);
|
|
32371
32848
|
if (!metadata.isFile() || metadata.isSymbolicLink() || metadata.size === 0 || metadata.size > ARTIFACT_MAXIMUM_BYTES) {
|
|
32372
32849
|
throw new WorkflowCliError(
|
|
32373
32850
|
"DXC_WORKFLOW_ARTIFACT_INVALID",
|
|
32374
|
-
|
|
32851
|
+
`${kind} \u4EA7\u7269\u4E3A\u7A7A\u3001\u8FC7\u5927\u6216\u4E0D\u662F\u666E\u901A\u6587\u4EF6\u3002`,
|
|
32852
|
+
{ path: target, stage: kind }
|
|
32375
32853
|
);
|
|
32376
32854
|
}
|
|
32377
|
-
return await
|
|
32855
|
+
return await readFile4(target, "utf8");
|
|
32378
32856
|
} catch (error) {
|
|
32379
32857
|
if (error instanceof WorkflowCliError) {
|
|
32380
32858
|
throw error;
|
|
32381
32859
|
}
|
|
32382
|
-
throw new WorkflowCliError(
|
|
32383
|
-
|
|
32384
|
-
|
|
32385
|
-
);
|
|
32860
|
+
throw new WorkflowCliError("DXC_WORKFLOW_ARTIFACT_MISSING", `\u7F3A\u5C11\u547D\u540D\u8F93\u5165\u6216\u4EA7\u7269 ${kind}\u3002`, {
|
|
32861
|
+
path: target,
|
|
32862
|
+
stage: kind
|
|
32863
|
+
});
|
|
32386
32864
|
}
|
|
32387
32865
|
}
|
|
32388
|
-
function
|
|
32389
|
-
const
|
|
32390
|
-
|
|
32391
|
-
|
|
32866
|
+
async function artifactAvailability(location, kind) {
|
|
32867
|
+
const target = artifactPath(location, kind);
|
|
32868
|
+
try {
|
|
32869
|
+
const metadata = await lstat6(target);
|
|
32870
|
+
if (!metadata.isFile() || metadata.isSymbolicLink() || metadata.size <= 0) {
|
|
32871
|
+
return { availability: "missing" };
|
|
32872
|
+
}
|
|
32873
|
+
const source = await readFile4(target);
|
|
32874
|
+
return { availability: "present", hash: sha2562(source), path: target };
|
|
32875
|
+
} catch (error) {
|
|
32876
|
+
if (typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT") {
|
|
32877
|
+
return { availability: "missing" };
|
|
32878
|
+
}
|
|
32879
|
+
throw new WorkflowCliError("DXC_WORKFLOW_ARTIFACT_INVALID", `\u65E0\u6CD5\u5B89\u5168\u8BFB\u53D6\u547D\u540D\u8F93\u5165 ${kind}\u3002`, {
|
|
32880
|
+
path: target,
|
|
32881
|
+
stage: kind
|
|
32882
|
+
});
|
|
32883
|
+
}
|
|
32884
|
+
}
|
|
32885
|
+
function stageScaffold(stage, title) {
|
|
32886
|
+
switch (stage) {
|
|
32887
|
+
case "article":
|
|
32888
|
+
return `---
|
|
32889
|
+
title: ""
|
|
32890
|
+
author: ""
|
|
32891
|
+
digest: ""
|
|
32892
|
+
tags: []
|
|
32893
|
+
${SCAFFOLD_MARKER}
|
|
32894
|
+
---
|
|
32895
|
+
|
|
32896
|
+
# ${title}
|
|
32897
|
+
`;
|
|
32898
|
+
case "titles":
|
|
32899
|
+
return `---
|
|
32900
|
+
selectedTitle: ""
|
|
32901
|
+
${SCAFFOLD_MARKER}
|
|
32902
|
+
---
|
|
32903
|
+
|
|
32904
|
+
# \u6807\u9898\u5019\u9009
|
|
32905
|
+
`;
|
|
32906
|
+
case "visual-plan":
|
|
32907
|
+
return `---
|
|
32908
|
+
cover:
|
|
32909
|
+
purpose: ""
|
|
32910
|
+
inline: []
|
|
32911
|
+
${SCAFFOLD_MARKER}
|
|
32912
|
+
---
|
|
32913
|
+
|
|
32914
|
+
# \u89C6\u89C9\u8BA1\u5212
|
|
32915
|
+
`;
|
|
32916
|
+
case "quality-review":
|
|
32917
|
+
return `---
|
|
32918
|
+
verdict: block
|
|
32919
|
+
${SCAFFOLD_MARKER}
|
|
32920
|
+
---
|
|
32921
|
+
|
|
32922
|
+
# \u5BA1\u6821\u7ED3\u679C
|
|
32923
|
+
`;
|
|
32924
|
+
case "delivery":
|
|
32925
|
+
return "# \u5FAE\u4FE1\u8349\u7A3F\u4EA4\u4ED8\n";
|
|
32926
|
+
default:
|
|
32927
|
+
return `---
|
|
32928
|
+
${SCAFFOLD_MARKER}
|
|
32929
|
+
---
|
|
32930
|
+
|
|
32931
|
+
# ${stageLabel(stage)}
|
|
32932
|
+
`;
|
|
32392
32933
|
}
|
|
32934
|
+
}
|
|
32935
|
+
async function ensureStageScaffold(location, stage) {
|
|
32936
|
+
if (stage === "delivery") {
|
|
32937
|
+
return "not-applicable";
|
|
32938
|
+
}
|
|
32939
|
+
const target = artifactPath(location, stage);
|
|
32393
32940
|
try {
|
|
32394
|
-
const
|
|
32395
|
-
|
|
32396
|
-
|
|
32397
|
-
|
|
32941
|
+
const metadata = await lstat6(target);
|
|
32942
|
+
if (!metadata.isFile() || metadata.isSymbolicLink()) {
|
|
32943
|
+
throw new WorkflowCliError(
|
|
32944
|
+
"DXC_WORKFLOW_ARTIFACT_INVALID",
|
|
32945
|
+
`${stage} \u8F93\u51FA\u4F4D\u7F6E\u4E0D\u662F\u666E\u901A\u6587\u4EF6\u3002`,
|
|
32946
|
+
{ path: target, stage }
|
|
32947
|
+
);
|
|
32948
|
+
}
|
|
32949
|
+
if (metadata.size > 0) {
|
|
32950
|
+
return "existing";
|
|
32951
|
+
}
|
|
32952
|
+
} catch (error) {
|
|
32953
|
+
if (error instanceof WorkflowCliError || !(typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT")) {
|
|
32954
|
+
throw error;
|
|
32955
|
+
}
|
|
32398
32956
|
}
|
|
32957
|
+
await writePrivateBuffer(target, Buffer.from(stageScaffold(stage, location.manifest.title)));
|
|
32958
|
+
return "created";
|
|
32399
32959
|
}
|
|
32400
|
-
function
|
|
32401
|
-
|
|
32402
|
-
|
|
32960
|
+
async function workflowSections(location, stage) {
|
|
32961
|
+
if (stage !== "visual-plan") {
|
|
32962
|
+
return void 0;
|
|
32963
|
+
}
|
|
32964
|
+
const article = await artifactAvailability(location, "article");
|
|
32965
|
+
if (article.availability === "missing") {
|
|
32966
|
+
return [];
|
|
32967
|
+
}
|
|
32968
|
+
return parseWorkflowArticleSections(await readFile4(article.path, "utf8"));
|
|
32969
|
+
}
|
|
32970
|
+
function workflowConstraints(stage) {
|
|
32971
|
+
if (stage === "article" || stage === "titles") {
|
|
32972
|
+
return {
|
|
32973
|
+
authorMaxCharacters: WECHAT_AUTHOR_CHARACTER_LIMIT,
|
|
32974
|
+
digestMaxCharacters: WECHAT_DIGEST_CHARACTER_LIMIT,
|
|
32975
|
+
titleMaxCharacters: WECHAT_TITLE_CHARACTER_LIMIT
|
|
32976
|
+
};
|
|
32977
|
+
}
|
|
32978
|
+
if (stage === "visual-plan" || stage === "delivery") {
|
|
32979
|
+
return {
|
|
32980
|
+
coverMaxBytes: PUBLISHING_COVER_MAXIMUM_BYTES,
|
|
32981
|
+
inlineImageMaxBytes: PUBLISHING_INLINE_IMAGE_MAXIMUM_BYTES,
|
|
32982
|
+
inlineImageMaxCount: PUBLISHING_INLINE_IMAGE_MAXIMUM_COUNT,
|
|
32983
|
+
supportedImageTypes: ["image/jpeg", "image/png"]
|
|
32984
|
+
};
|
|
32985
|
+
}
|
|
32986
|
+
return {};
|
|
32987
|
+
}
|
|
32988
|
+
async function namedResources(location, stage, scaffold) {
|
|
32989
|
+
const definition = CONTENT_STAGE_DEFINITIONS[stage];
|
|
32990
|
+
const inputs = {};
|
|
32991
|
+
for (const kind of [...definition.inputs.required, ...definition.inputs.optional]) {
|
|
32992
|
+
const availability = await artifactAvailability(location, kind);
|
|
32993
|
+
inputs[kind] = availability.availability === "missing" ? { availability: "missing" } : { availability: "present", path: availability.path };
|
|
32994
|
+
}
|
|
32995
|
+
return {
|
|
32996
|
+
inputs,
|
|
32997
|
+
output: { path: artifactPath(location, definition.output), scaffold }
|
|
32998
|
+
};
|
|
32999
|
+
}
|
|
33000
|
+
async function inputFingerprint(location, stage) {
|
|
33001
|
+
const definition = CONTENT_STAGE_DEFINITIONS[stage];
|
|
33002
|
+
const inputs = {};
|
|
33003
|
+
for (const kind of [...definition.inputs.required, ...definition.inputs.optional]) {
|
|
33004
|
+
const availability = await artifactAvailability(location, kind);
|
|
33005
|
+
inputs[kind] = availability.availability === "missing" ? { availability: "missing" } : { availability: "present", hash: availability.hash };
|
|
33006
|
+
}
|
|
33007
|
+
if (stage === "delivery") {
|
|
33008
|
+
inputs["visual-assets"] = await workflowVisualAssetsFingerprint(location.directory);
|
|
33009
|
+
}
|
|
33010
|
+
return sha2562(JSON.stringify(inputs));
|
|
32403
33011
|
}
|
|
32404
|
-
|
|
32405
|
-
|
|
32406
|
-
|
|
33012
|
+
function cursorFingerprint(state) {
|
|
33013
|
+
return sha2562(JSON.stringify(state));
|
|
33014
|
+
}
|
|
33015
|
+
function encodeWorkItem(payload) {
|
|
33016
|
+
const encoded = Buffer.from(JSON.stringify(payload), "utf8").toString("base64url");
|
|
33017
|
+
return `wi1_${encoded}.${sha2562(encoded).slice(0, 32)}`;
|
|
33018
|
+
}
|
|
33019
|
+
function decodeWorkItem(workItemId) {
|
|
33020
|
+
const match = WORK_ITEM_PATTERN.exec(workItemId);
|
|
33021
|
+
if (match === null || match[1] === void 0 || match[2] === void 0) {
|
|
33022
|
+
throw new WorkflowCliError("DXC_WORK_ITEM_INVALID", "\u5DE5\u4F5C\u9879 ID \u683C\u5F0F\u65E0\u6548\u3002");
|
|
33023
|
+
}
|
|
33024
|
+
if (sha2562(match[1]).slice(0, 32) !== match[2]) {
|
|
33025
|
+
throw new WorkflowCliError("DXC_WORK_ITEM_INVALID", "\u5DE5\u4F5C\u9879 ID \u5B8C\u6574\u6027\u6821\u9A8C\u5931\u8D25\u3002");
|
|
32407
33026
|
}
|
|
32408
|
-
|
|
33027
|
+
try {
|
|
33028
|
+
const value = JSON.parse(Buffer.from(match[1], "base64url").toString("utf8"));
|
|
33029
|
+
if (!isRecord(value) || value["version"] !== 1 || typeof value["projectId"] !== "string" || typeof value["stage"] !== "string" || !CONTENT_ARTIFACT_KINDS.includes(value["stage"]) || typeof value["action"] !== "string" || ![
|
|
33030
|
+
"completed",
|
|
33031
|
+
"delivery-confirm",
|
|
33032
|
+
"delivery-preview",
|
|
33033
|
+
"stage",
|
|
33034
|
+
"stage-confirm",
|
|
33035
|
+
"visual-assets"
|
|
33036
|
+
].includes(value["action"]) || typeof value["cursorFingerprint"] !== "string" || typeof value["inputFingerprint"] !== "string" || value["outputFingerprint"] !== void 0 && typeof value["outputFingerprint"] !== "string" || value["bindingFingerprint"] !== void 0 && typeof value["bindingFingerprint"] !== "string") {
|
|
33037
|
+
throw new TypeError("invalid work item payload");
|
|
33038
|
+
}
|
|
33039
|
+
return value;
|
|
33040
|
+
} catch (error) {
|
|
33041
|
+
if (error instanceof WorkflowCliError) {
|
|
33042
|
+
throw error;
|
|
33043
|
+
}
|
|
33044
|
+
throw new WorkflowCliError("DXC_WORK_ITEM_INVALID", "\u5DE5\u4F5C\u9879 ID \u8F7D\u8377\u65E0\u6548\u3002");
|
|
33045
|
+
}
|
|
33046
|
+
}
|
|
33047
|
+
async function validateRequiredInputs(location, stage) {
|
|
33048
|
+
for (const kind of CONTENT_STAGE_DEFINITIONS[stage].inputs.required) {
|
|
33049
|
+
if ((await artifactAvailability(location, kind)).availability === "missing") {
|
|
33050
|
+
throw new WorkflowCliError(
|
|
33051
|
+
"DXC_WORKFLOW_INPUT_MISSING",
|
|
33052
|
+
`\u5F53\u524D ${stage} \u9636\u6BB5\u7F3A\u5C11\u547D\u540D\u8F93\u5165 ${kind}\u3002`,
|
|
33053
|
+
{ input: kind, stage }
|
|
33054
|
+
);
|
|
33055
|
+
}
|
|
33056
|
+
}
|
|
33057
|
+
}
|
|
33058
|
+
async function validateStageResult(stage, source, location) {
|
|
33059
|
+
if (source.trim().length === 0 || source.includes(SCAFFOLD_MARKER)) {
|
|
33060
|
+
throw new WorkflowCliError(
|
|
33061
|
+
"DXC_WORKFLOW_ARTIFACT_INVALID",
|
|
33062
|
+
`${stage} \u9636\u6BB5\u4ECD\u662F\u672A\u586B\u5199\u7684 scaffold\uFF08\u811A\u624B\u67B6\uFF09\u3002`,
|
|
33063
|
+
{ path: artifactPath(location, stage), stage }
|
|
33064
|
+
);
|
|
33065
|
+
}
|
|
33066
|
+
if (stage === "article") {
|
|
32409
33067
|
let article;
|
|
32410
33068
|
try {
|
|
32411
33069
|
article = parseArticleDocument(source);
|
|
32412
33070
|
} catch {
|
|
32413
33071
|
throw new WorkflowCliError(
|
|
32414
33072
|
"DXC_WORKFLOW_ARTIFACT_INVALID",
|
|
32415
|
-
"\u6B63\u6587\u9700\u8981\u5305\u542B\u53EF\u53D1\u5E03\u7684\u6807\u9898\u3001\u4F5C\u8005\u548C Markdown \u6B63\u6587\u3002"
|
|
33073
|
+
"\u6B63\u6587\u9700\u8981\u5305\u542B\u53EF\u53D1\u5E03\u7684\u6807\u9898\u3001\u4F5C\u8005\u548C Markdown \u6B63\u6587\u3002",
|
|
33074
|
+
{ path: artifactPath(location, stage), stage }
|
|
32416
33075
|
);
|
|
32417
33076
|
}
|
|
32418
33077
|
const lengths = {
|
|
@@ -32424,56 +33083,41 @@ async function validateStageResult(step, source, location) {
|
|
|
32424
33083
|
if (invalid !== void 0) {
|
|
32425
33084
|
throw new WorkflowCliError(
|
|
32426
33085
|
"DXC_WORKFLOW_ARTICLE_FIELD_INVALID",
|
|
32427
|
-
`${invalid} \u4E2A Unicode \u5B57\u7B26\uFF1B\u8BF7\u5728\u6B63\u6587\u9636\u6BB5\u4FEE\u6B63\u540E\u518D\u7EE7\u7EED\u3002
|
|
33086
|
+
`${invalid} \u4E2A Unicode \u5B57\u7B26\uFF1B\u8BF7\u5728\u6B63\u6587\u9636\u6BB5\u4FEE\u6B63\u540E\u518D\u7EE7\u7EED\u3002`,
|
|
33087
|
+
{ path: artifactPath(location, stage), stage }
|
|
32428
33088
|
);
|
|
32429
33089
|
}
|
|
32430
33090
|
}
|
|
32431
|
-
if (
|
|
33091
|
+
if (stage === "titles") {
|
|
32432
33092
|
const title = selectedTitle(frontmatter(source));
|
|
32433
|
-
if (title === void 0 || [...title].length >
|
|
33093
|
+
if (title === void 0 || [...title].length > WECHAT_TITLE_CHARACTER_LIMIT) {
|
|
32434
33094
|
throw new WorkflowCliError(
|
|
32435
33095
|
"DXC_WORKFLOW_ARTIFACT_INVALID",
|
|
32436
|
-
|
|
33096
|
+
`\u6807\u9898\u6B65\u9AA4\u9700\u8981\u5728 selectedTitle \u4E2D\u4FDD\u5B58\u4E00\u4E2A\u4E0D\u8D85\u8FC7 ${WECHAT_TITLE_CHARACTER_LIMIT} \u5B57\u7684\u6700\u7EC8\u6807\u9898\u3002`,
|
|
33097
|
+
{ path: artifactPath(location, stage), stage }
|
|
32437
33098
|
);
|
|
32438
33099
|
}
|
|
32439
33100
|
}
|
|
32440
|
-
if (
|
|
32441
|
-
const
|
|
32442
|
-
|
|
32443
|
-
|
|
32444
|
-
|
|
32445
|
-
|
|
32446
|
-
);
|
|
32447
|
-
}
|
|
32448
|
-
const articleSource = await readArtifact(
|
|
32449
|
-
location.directory,
|
|
32450
|
-
location.manifest.artifacts.article
|
|
32451
|
-
);
|
|
32452
|
-
try {
|
|
32453
|
-
validateVisualPlanPlacementAnchors(articleSource, source);
|
|
32454
|
-
} catch (error) {
|
|
32455
|
-
if (error instanceof WechatCliError) {
|
|
32456
|
-
throw new WorkflowCliError(error.code, error.guidance ?? error.message);
|
|
32457
|
-
}
|
|
32458
|
-
throw error;
|
|
32459
|
-
}
|
|
33101
|
+
if (stage === "visual-plan") {
|
|
33102
|
+
const articleSource = await readArtifact(location, "article");
|
|
33103
|
+
validateWorkflowSemanticVisualPlan({
|
|
33104
|
+
sections: parseWorkflowArticleSections(articleSource),
|
|
33105
|
+
source
|
|
33106
|
+
});
|
|
32460
33107
|
}
|
|
32461
|
-
if (
|
|
33108
|
+
if (stage === "quality-review" && frontmatter(source)["verdict"] !== "pass") {
|
|
32462
33109
|
throw new WorkflowCliError(
|
|
32463
33110
|
"DXC_WORKFLOW_ARTIFACT_INVALID",
|
|
32464
|
-
"\u5BA1\u6821\u6B65\u9AA4\u53EA\u6709 verdict: pass \u65F6\u624D\u80FD\u7EE7\u7EED\u4EA4\u4ED8\u3002"
|
|
33111
|
+
"\u5BA1\u6821\u6B65\u9AA4\u53EA\u6709 verdict: pass \u65F6\u624D\u80FD\u7EE7\u7EED\u4EA4\u4ED8\u3002",
|
|
33112
|
+
{ path: artifactPath(location, stage), stage }
|
|
32465
33113
|
);
|
|
32466
33114
|
}
|
|
32467
33115
|
}
|
|
32468
33116
|
var WorkflowCli = class {
|
|
32469
|
-
#currentDirectory;
|
|
32470
|
-
#homeDirectory;
|
|
32471
33117
|
#now;
|
|
32472
33118
|
#profile;
|
|
32473
33119
|
#projects;
|
|
32474
33120
|
constructor(input) {
|
|
32475
|
-
this.#currentDirectory = input.currentDirectory;
|
|
32476
|
-
this.#homeDirectory = input.homeDirectory;
|
|
32477
33121
|
this.#now = input.now ?? (() => /* @__PURE__ */ new Date());
|
|
32478
33122
|
this.#profile = new ProfileCli({
|
|
32479
33123
|
currentDirectory: input.currentDirectory,
|
|
@@ -32490,15 +33134,6 @@ var WorkflowCli = class {
|
|
|
32490
33134
|
const status = await this.#profile.status();
|
|
32491
33135
|
return status.data.configured ? status.data.profile.user.confirmationPolicy : "guided";
|
|
32492
33136
|
}
|
|
32493
|
-
async #locate(directory, projectId) {
|
|
32494
|
-
if (directory !== void 0 && projectId !== void 0) {
|
|
32495
|
-
throw new WorkflowCliError(
|
|
32496
|
-
"DXC_WORKFLOW_PROJECT_REFERENCE_INVALID",
|
|
32497
|
-
"\u9879\u76EE\u76EE\u5F55\u548C\u9879\u76EE ID \u53EA\u80FD\u6307\u5B9A\u4E00\u4E2A\u3002"
|
|
32498
|
-
);
|
|
32499
|
-
}
|
|
32500
|
-
return projectId === void 0 ? this.#projects.locate(directory) : this.#projects.locateByProjectId(projectId);
|
|
32501
|
-
}
|
|
32502
33137
|
async #loadState(location, persistMigration = true, migrationUpdatedAt = this.#now().toISOString()) {
|
|
32503
33138
|
try {
|
|
32504
33139
|
const raw = await readPrivateFile(
|
|
@@ -32553,79 +33188,328 @@ var WorkflowCli = class {
|
|
|
32553
33188
|
}
|
|
32554
33189
|
return migrated;
|
|
32555
33190
|
}
|
|
33191
|
+
#nextTimestamp(previous) {
|
|
33192
|
+
const current = this.#now().getTime();
|
|
33193
|
+
const previousTime = previous === void 0 ? Number.NEGATIVE_INFINITY : Date.parse(previous);
|
|
33194
|
+
return new Date(Math.max(current, previousTime + 1)).toISOString();
|
|
33195
|
+
}
|
|
33196
|
+
async #basePayload(location, state, stage, action) {
|
|
33197
|
+
return {
|
|
33198
|
+
action,
|
|
33199
|
+
cursorFingerprint: cursorFingerprint(state),
|
|
33200
|
+
inputFingerprint: await inputFingerprint(location, stage),
|
|
33201
|
+
projectId: location.manifest.projectId,
|
|
33202
|
+
stage,
|
|
33203
|
+
version: 1
|
|
33204
|
+
};
|
|
33205
|
+
}
|
|
33206
|
+
async #stagePayload(location, state) {
|
|
33207
|
+
const stage = nextStep(state.lastCompletedStep);
|
|
33208
|
+
if (stage === null) {
|
|
33209
|
+
return this.#basePayload(location, state, "delivery", "completed");
|
|
33210
|
+
}
|
|
33211
|
+
return this.#basePayload(
|
|
33212
|
+
location,
|
|
33213
|
+
state,
|
|
33214
|
+
stage,
|
|
33215
|
+
stage === "delivery" ? "delivery-preview" : "stage"
|
|
33216
|
+
);
|
|
33217
|
+
}
|
|
33218
|
+
async #confirmationPayload(location, state, stage) {
|
|
33219
|
+
const source = await readArtifact(location, stage);
|
|
33220
|
+
await validateStageResult(stage, source, location);
|
|
33221
|
+
const base = await this.#basePayload(location, state, stage, "stage-confirm");
|
|
33222
|
+
let bindingFingerprint;
|
|
33223
|
+
if (stage === "visual-plan") {
|
|
33224
|
+
bindingFingerprint = await workflowVisualAssetsFingerprint(location.directory);
|
|
33225
|
+
}
|
|
33226
|
+
return {
|
|
33227
|
+
...base,
|
|
33228
|
+
...bindingFingerprint === void 0 ? {} : { bindingFingerprint },
|
|
33229
|
+
outputFingerprint: sha2562(source)
|
|
33230
|
+
};
|
|
33231
|
+
}
|
|
33232
|
+
async #visualAssetsPayload(location, state) {
|
|
33233
|
+
const source = await readArtifact(location, "visual-plan");
|
|
33234
|
+
await validateStageResult("visual-plan", source, location);
|
|
33235
|
+
return {
|
|
33236
|
+
...await this.#basePayload(location, state, "visual-plan", "visual-assets"),
|
|
33237
|
+
outputFingerprint: sha2562(source)
|
|
33238
|
+
};
|
|
33239
|
+
}
|
|
33240
|
+
async #currentWorkItemId(location, state) {
|
|
33241
|
+
return encodeWorkItem(await this.#stagePayload(location, state));
|
|
33242
|
+
}
|
|
33243
|
+
async #stale(location, state) {
|
|
33244
|
+
throw new WorkflowCliError(
|
|
33245
|
+
"DXC_WORK_ITEM_STALE",
|
|
33246
|
+
"\u5DE5\u4F5C\u9879\u5DF2\u8FC7\u671F\uFF1B\u8BF7\u4F7F\u7528\u5F53\u524D\u5DE5\u4F5C\u9879\u7EE7\u7EED\uFF0C\u4E0D\u4F1A\u66FF\u4F60\u9759\u9ED8\u5B8C\u6210\u65E7\u52A8\u4F5C\u3002",
|
|
33247
|
+
{ workItemId: await this.#currentWorkItemId(location, state) }
|
|
33248
|
+
);
|
|
33249
|
+
}
|
|
33250
|
+
async #resolve(workItemId) {
|
|
33251
|
+
const payload = decodeWorkItem(workItemId);
|
|
33252
|
+
let location;
|
|
33253
|
+
try {
|
|
33254
|
+
location = await this.#projects.locateByProjectId(payload.projectId);
|
|
33255
|
+
} catch {
|
|
33256
|
+
throw new WorkflowCliError("DXC_WORK_ITEM_INVALID", "\u5DE5\u4F5C\u9879\u6307\u5411\u7684\u9879\u76EE\u4E0D\u5B58\u5728\u6216\u65E0\u6548\u3002");
|
|
33257
|
+
}
|
|
33258
|
+
const state = await this.#loadState(location);
|
|
33259
|
+
const stage = nextStep(state.lastCompletedStep);
|
|
33260
|
+
if (stage === null) {
|
|
33261
|
+
const expected2 = encodeWorkItem(await this.#stagePayload(location, state));
|
|
33262
|
+
if (payload.action !== "completed" || expected2 !== workItemId) {
|
|
33263
|
+
return this.#stale(location, state);
|
|
33264
|
+
}
|
|
33265
|
+
return { location, payload, state };
|
|
33266
|
+
}
|
|
33267
|
+
if (payload.stage !== stage) {
|
|
33268
|
+
return this.#stale(location, state);
|
|
33269
|
+
}
|
|
33270
|
+
const currentBase = await this.#basePayload(location, state, stage, payload.action);
|
|
33271
|
+
if (payload.cursorFingerprint !== currentBase.cursorFingerprint || payload.inputFingerprint !== currentBase.inputFingerprint) {
|
|
33272
|
+
return this.#stale(location, state);
|
|
33273
|
+
}
|
|
33274
|
+
let expected;
|
|
33275
|
+
switch (payload.action) {
|
|
33276
|
+
case "stage":
|
|
33277
|
+
case "delivery-preview":
|
|
33278
|
+
expected = await this.#stagePayload(location, state);
|
|
33279
|
+
break;
|
|
33280
|
+
case "stage-confirm":
|
|
33281
|
+
expected = await this.#confirmationPayload(location, state, stage);
|
|
33282
|
+
break;
|
|
33283
|
+
case "visual-assets":
|
|
33284
|
+
if (stage !== "visual-plan") {
|
|
33285
|
+
return this.#stale(location, state);
|
|
33286
|
+
}
|
|
33287
|
+
expected = await this.#visualAssetsPayload(location, state);
|
|
33288
|
+
break;
|
|
33289
|
+
case "delivery-confirm": {
|
|
33290
|
+
if (stage !== "delivery") {
|
|
33291
|
+
return this.#stale(location, state);
|
|
33292
|
+
}
|
|
33293
|
+
expected = {
|
|
33294
|
+
...await this.#basePayload(location, state, stage, "delivery-confirm"),
|
|
33295
|
+
...payload.bindingFingerprint === void 0 ? {} : { bindingFingerprint: payload.bindingFingerprint }
|
|
33296
|
+
};
|
|
33297
|
+
break;
|
|
33298
|
+
}
|
|
33299
|
+
case "completed":
|
|
33300
|
+
return this.#stale(location, state);
|
|
33301
|
+
}
|
|
33302
|
+
if (encodeWorkItem(expected) !== workItemId) {
|
|
33303
|
+
return this.#stale(location, state);
|
|
33304
|
+
}
|
|
33305
|
+
return { location, payload, state };
|
|
33306
|
+
}
|
|
33307
|
+
async #workItem(resolved, rich, actionOverride) {
|
|
33308
|
+
const { location, payload } = resolved;
|
|
33309
|
+
const definition = CONTENT_STAGE_DEFINITIONS[payload.stage];
|
|
33310
|
+
const workItemId = encodeWorkItem(payload);
|
|
33311
|
+
let nextAction;
|
|
33312
|
+
switch (payload.action) {
|
|
33313
|
+
case "stage":
|
|
33314
|
+
nextAction = { type: "run-stage" };
|
|
33315
|
+
break;
|
|
33316
|
+
case "visual-assets": {
|
|
33317
|
+
const article = await readArtifact(location, "article");
|
|
33318
|
+
const visualPlan = await readArtifact(location, "visual-plan");
|
|
33319
|
+
const sections2 = parseWorkflowArticleSections(article);
|
|
33320
|
+
const assetsDirectory = path8.join(location.directory, location.manifest.assetsDirectory);
|
|
33321
|
+
await ensurePrivateDirectory(path8.join(assetsDirectory, "visuals"));
|
|
33322
|
+
nextAction = {
|
|
33323
|
+
assets: [
|
|
33324
|
+
...workflowVisualAssetAssignments({
|
|
33325
|
+
assetsDirectory,
|
|
33326
|
+
projectDirectory: location.directory,
|
|
33327
|
+
sections: sections2,
|
|
33328
|
+
visualPlanSource: visualPlan
|
|
33329
|
+
})
|
|
33330
|
+
],
|
|
33331
|
+
type: "generate-assets"
|
|
33332
|
+
};
|
|
33333
|
+
break;
|
|
33334
|
+
}
|
|
33335
|
+
case "stage-confirm":
|
|
33336
|
+
nextAction = {
|
|
33337
|
+
presentation: { path: artifactPath(location, payload.stage), type: "artifact" },
|
|
33338
|
+
type: "confirm-stage"
|
|
33339
|
+
};
|
|
33340
|
+
break;
|
|
33341
|
+
case "delivery-preview":
|
|
33342
|
+
nextAction = { type: "preview" };
|
|
33343
|
+
break;
|
|
33344
|
+
case "delivery-confirm":
|
|
33345
|
+
nextAction = actionOverride ?? {
|
|
33346
|
+
expiresAt: (/* @__PURE__ */ new Date(0)).toISOString(),
|
|
33347
|
+
type: "confirm-delivery"
|
|
33348
|
+
};
|
|
33349
|
+
break;
|
|
33350
|
+
case "completed":
|
|
33351
|
+
nextAction = { type: "completed" };
|
|
33352
|
+
break;
|
|
33353
|
+
}
|
|
33354
|
+
const base = {
|
|
33355
|
+
nextAction: actionOverride ?? nextAction,
|
|
33356
|
+
skill: definition.skill,
|
|
33357
|
+
stage: payload.stage,
|
|
33358
|
+
workItemId
|
|
33359
|
+
};
|
|
33360
|
+
if (!rich || payload.action === "completed") {
|
|
33361
|
+
return base;
|
|
33362
|
+
}
|
|
33363
|
+
const scaffold = payload.action === "stage" ? await ensureStageScaffold(location, payload.stage) : payload.stage === "delivery" ? "not-applicable" : "existing";
|
|
33364
|
+
const sections = await workflowSections(location, payload.stage);
|
|
33365
|
+
return {
|
|
33366
|
+
...base,
|
|
33367
|
+
constraints: workflowConstraints(payload.stage),
|
|
33368
|
+
resources: await namedResources(location, payload.stage, scaffold),
|
|
33369
|
+
...sections === void 0 ? {} : { sections: [...sections] }
|
|
33370
|
+
};
|
|
33371
|
+
}
|
|
33372
|
+
async #result(location, payload, rich = false, actionOverride) {
|
|
33373
|
+
return {
|
|
33374
|
+
command: "workflow.next",
|
|
33375
|
+
data: {
|
|
33376
|
+
project: projectSummary(location),
|
|
33377
|
+
workItem: await this.#workItem(
|
|
33378
|
+
{ location, payload, state: await this.#loadState(location) },
|
|
33379
|
+
rich,
|
|
33380
|
+
actionOverride
|
|
33381
|
+
)
|
|
33382
|
+
},
|
|
33383
|
+
ok: true
|
|
33384
|
+
};
|
|
33385
|
+
}
|
|
32556
33386
|
async start(options) {
|
|
32557
|
-
if (options.
|
|
33387
|
+
if (options.projectId !== void 0 && (options.directory !== void 0 || options.title !== void 0)) {
|
|
32558
33388
|
throw new WorkflowCliError(
|
|
32559
33389
|
"DXC_WORKFLOW_PROJECT_REFERENCE_INVALID",
|
|
32560
|
-
"\u9879\u76EE\
|
|
33390
|
+
"\u5DF2\u6709\u9879\u76EE\u53EA\u80FD\u4F7F\u7528 --project\uFF0C\u4E0D\u63A5\u53D7\u6807\u9898\u6216\u76EE\u5F55\u3002"
|
|
32561
33391
|
);
|
|
32562
33392
|
}
|
|
32563
|
-
const directory = options.directory === void 0 ? void 0 : resolveUserPath({
|
|
32564
|
-
currentDirectory: this.#currentDirectory,
|
|
32565
|
-
homeDirectory: this.#homeDirectory,
|
|
32566
|
-
input: options.directory
|
|
32567
|
-
});
|
|
32568
33393
|
const requested = options.from === void 0 ? void 0 : requestedStep(options.from);
|
|
32569
33394
|
let location;
|
|
33395
|
+
let existingState;
|
|
32570
33396
|
if (options.projectId !== void 0) {
|
|
32571
33397
|
location = await this.#projects.locateByProjectId(options.projectId);
|
|
32572
|
-
|
|
32573
|
-
|
|
32574
|
-
location
|
|
32575
|
-
} catch (error) {
|
|
32576
|
-
if (!(error instanceof ProjectCliError) || error.code !== "DXC_PROJECT_NOT_FOUND") {
|
|
32577
|
-
throw error;
|
|
32578
|
-
}
|
|
32579
|
-
if (options.title === void 0 || options.title.trim().length === 0) {
|
|
32580
|
-
throw new WorkflowCliError(
|
|
32581
|
-
"DXC_WORKFLOW_TITLE_REQUIRED",
|
|
32582
|
-
"\u521B\u5EFA\u65B0\u9879\u76EE\u65F6\u9700\u8981\u63D0\u4F9B\u6587\u7AE0\u4E3B\u9898\u3002"
|
|
32583
|
-
);
|
|
32584
|
-
}
|
|
32585
|
-
const initialized = await this.#projects.initialize(directory, options.title);
|
|
32586
|
-
location = { directory: initialized.data.directory, manifest: initialized.data.manifest };
|
|
33398
|
+
existingState = await this.#loadState(location);
|
|
33399
|
+
if (requested === void 0) {
|
|
33400
|
+
return this.#result(location, await this.#stagePayload(location, existingState));
|
|
32587
33401
|
}
|
|
32588
33402
|
} else {
|
|
32589
33403
|
if (options.title === void 0 || options.title.trim().length === 0) {
|
|
32590
33404
|
throw new WorkflowCliError("DXC_WORKFLOW_TITLE_REQUIRED", "\u521B\u5EFA\u65B0\u9879\u76EE\u65F6\u9700\u8981\u63D0\u4F9B\u6587\u7AE0\u4E3B\u9898\u3002");
|
|
32591
33405
|
}
|
|
32592
|
-
const initialized = await this.#projects.initialize(
|
|
33406
|
+
const initialized = await this.#projects.initialize(options.directory, options.title);
|
|
32593
33407
|
location = { directory: initialized.data.directory, manifest: initialized.data.manifest };
|
|
32594
33408
|
}
|
|
32595
|
-
|
|
32596
|
-
const state2 = await this.#loadState(location);
|
|
32597
|
-
const confirmationPolicy2 = await this.#confirmationPolicy();
|
|
32598
|
-
return {
|
|
32599
|
-
command: "workflow.next",
|
|
32600
|
-
data: { match: "ready", work: workItem(location, state2, confirmationPolicy2) },
|
|
32601
|
-
ok: true
|
|
32602
|
-
};
|
|
32603
|
-
}
|
|
32604
|
-
if (requested === void 0 && directory !== void 0) {
|
|
32605
|
-
const state2 = await this.#loadState(location);
|
|
32606
|
-
if (state2.lastCompletedStep !== null) {
|
|
32607
|
-
const confirmationPolicy2 = await this.#confirmationPolicy();
|
|
32608
|
-
return {
|
|
32609
|
-
command: "workflow.next",
|
|
32610
|
-
data: { match: "ready", work: workItem(location, state2, confirmationPolicy2) },
|
|
32611
|
-
ok: true
|
|
32612
|
-
};
|
|
32613
|
-
}
|
|
32614
|
-
}
|
|
32615
|
-
const step = requested ?? "research";
|
|
33409
|
+
const stage = requested ?? "research";
|
|
32616
33410
|
const state = {
|
|
32617
|
-
lastCompletedStep: previousStep(
|
|
33411
|
+
lastCompletedStep: previousStep(stage),
|
|
32618
33412
|
projectId: location.manifest.projectId,
|
|
32619
|
-
updatedAt: this.#
|
|
33413
|
+
updatedAt: this.#nextTimestamp(existingState?.updatedAt),
|
|
32620
33414
|
version: 1
|
|
32621
33415
|
};
|
|
32622
33416
|
await writePrivateJson(statePath(location.directory), state);
|
|
32623
|
-
|
|
32624
|
-
|
|
32625
|
-
|
|
32626
|
-
|
|
32627
|
-
|
|
33417
|
+
return this.#result(location, await this.#stagePayload(location, state));
|
|
33418
|
+
}
|
|
33419
|
+
async next(options) {
|
|
33420
|
+
if (options.projectId === void 0 === (options.workItemId === void 0)) {
|
|
33421
|
+
throw new WorkflowCliError(
|
|
33422
|
+
"DXC_WORKFLOW_PROJECT_REFERENCE_INVALID",
|
|
33423
|
+
"workflow next \u5FC5\u987B\u4E14\u53EA\u80FD\u6307\u5B9A --project \u6216 --work-item\u3002"
|
|
33424
|
+
);
|
|
33425
|
+
}
|
|
33426
|
+
if (options.workItemId !== void 0) {
|
|
33427
|
+
const resolved = await this.#resolve(options.workItemId);
|
|
33428
|
+
return this.#result(resolved.location, resolved.payload, true);
|
|
33429
|
+
}
|
|
33430
|
+
const location = await this.#projects.locateByProjectId(options.projectId);
|
|
33431
|
+
const state = await this.#loadState(location);
|
|
33432
|
+
return this.#result(location, await this.#stagePayload(location, state));
|
|
33433
|
+
}
|
|
33434
|
+
async complete(workItemId, confirmed = false) {
|
|
33435
|
+
const resolved = await this.#resolve(workItemId);
|
|
33436
|
+
const { location, payload, state } = resolved;
|
|
33437
|
+
if (payload.action === "completed") {
|
|
33438
|
+
return this.#result(location, payload);
|
|
33439
|
+
}
|
|
33440
|
+
if (payload.stage === "delivery" || payload.action.startsWith("delivery-")) {
|
|
33441
|
+
throw new WorkflowCliError(
|
|
33442
|
+
"DXC_WORKFLOW_DELIVERY_REQUIRED",
|
|
33443
|
+
"\u5185\u5BB9\u5DF2\u7ECF\u51C6\u5907\u5B8C\u6210\uFF1B\u8BF7\u751F\u6210\u5FAE\u4FE1\u9884\u89C8\u5E76\u786E\u8BA4\u4EA4\u4ED8\u3002"
|
|
33444
|
+
);
|
|
33445
|
+
}
|
|
33446
|
+
if (payload.action === "stage-confirm") {
|
|
33447
|
+
if (!confirmed) {
|
|
33448
|
+
throw new WorkflowCliError(
|
|
33449
|
+
"DXC_WORKFLOW_CONFIRMATION_REQUIRED",
|
|
33450
|
+
`\u8BF7\u660E\u786E\u786E\u8BA4\u91C7\u7528\u5F53\u524D${stageLabel(payload.stage)}\u3002`
|
|
33451
|
+
);
|
|
33452
|
+
}
|
|
33453
|
+
return this.#advance(location, state, payload.stage);
|
|
33454
|
+
}
|
|
33455
|
+
if (confirmed) {
|
|
33456
|
+
throw new WorkflowCliError(
|
|
33457
|
+
"DXC_WORKFLOW_CONFIRMATION_REQUIRED",
|
|
33458
|
+
"\u751F\u4EA7\u5DE5\u4F5C\u9879\u4E0D\u80FD\u76F4\u63A5\u786E\u8BA4\uFF1B\u8BF7\u5148\u5B8C\u6210\u6821\u9A8C\u5E76\u5C55\u793A CLI \u8FD4\u56DE\u7684\u786E\u8BA4\u5DE5\u4F5C\u9879\u3002"
|
|
33459
|
+
);
|
|
33460
|
+
}
|
|
33461
|
+
await validateRequiredInputs(location, payload.stage);
|
|
33462
|
+
const source = await readArtifact(location, payload.stage);
|
|
33463
|
+
await validateStageResult(payload.stage, source, location);
|
|
33464
|
+
if (payload.action === "stage" && payload.stage === "visual-plan") {
|
|
33465
|
+
const visualPayload = await this.#visualAssetsPayload(location, state);
|
|
33466
|
+
return this.#result(location, visualPayload, true);
|
|
33467
|
+
}
|
|
33468
|
+
if (payload.action === "visual-assets") {
|
|
33469
|
+
const articleSource = await readArtifact(location, "article");
|
|
33470
|
+
const sections = parseWorkflowArticleSections(articleSource);
|
|
33471
|
+
const assetsDirectory = path8.join(location.directory, location.manifest.assetsDirectory);
|
|
33472
|
+
const assignments = workflowVisualAssetAssignments({
|
|
33473
|
+
assetsDirectory,
|
|
33474
|
+
projectDirectory: location.directory,
|
|
33475
|
+
sections,
|
|
33476
|
+
visualPlanSource: source
|
|
33477
|
+
});
|
|
33478
|
+
try {
|
|
33479
|
+
await finalizeWorkflowVisualAssets({
|
|
33480
|
+
articleFile: artifactPath(location, "article"),
|
|
33481
|
+
articleSource,
|
|
33482
|
+
assetsDirectory,
|
|
33483
|
+
assignments,
|
|
33484
|
+
projectDirectory: location.directory,
|
|
33485
|
+
sections,
|
|
33486
|
+
visualPlanSource: source
|
|
33487
|
+
});
|
|
33488
|
+
} catch (error) {
|
|
33489
|
+
if (error instanceof WechatCliError) {
|
|
33490
|
+
throw new WorkflowCliError(error.code, error.guidance ?? error.message, {
|
|
33491
|
+
...error.fields,
|
|
33492
|
+
stage: payload.stage
|
|
33493
|
+
});
|
|
33494
|
+
}
|
|
33495
|
+
throw error;
|
|
33496
|
+
}
|
|
33497
|
+
}
|
|
33498
|
+
const policy = await this.#confirmationPolicy();
|
|
33499
|
+
if (requiresStageConfirmation(policy, payload.stage)) {
|
|
33500
|
+
const confirmationPayload = await this.#confirmationPayload(location, state, payload.stage);
|
|
33501
|
+
return this.#result(location, confirmationPayload, true);
|
|
33502
|
+
}
|
|
33503
|
+
return this.#advance(location, state, payload.stage);
|
|
33504
|
+
}
|
|
33505
|
+
async #advance(location, state, stage) {
|
|
33506
|
+
const nextState = {
|
|
33507
|
+
...state,
|
|
33508
|
+
lastCompletedStep: stage,
|
|
33509
|
+
updatedAt: this.#nextTimestamp(state.updatedAt)
|
|
32628
33510
|
};
|
|
33511
|
+
await writePrivateJson(statePath(location.directory), nextState);
|
|
33512
|
+
return this.#result(location, await this.#stagePayload(location, nextState));
|
|
32629
33513
|
}
|
|
32630
33514
|
async listProjects() {
|
|
32631
33515
|
const projects = [];
|
|
@@ -32647,6 +33531,7 @@ var WorkflowCli = class {
|
|
|
32647
33531
|
projects.push({
|
|
32648
33532
|
...projectSummary(indexed.location),
|
|
32649
33533
|
available: true,
|
|
33534
|
+
directory: indexed.location.directory,
|
|
32650
33535
|
done: step === null,
|
|
32651
33536
|
step,
|
|
32652
33537
|
updatedAt: state.updatedAt
|
|
@@ -32655,96 +33540,82 @@ var WorkflowCli = class {
|
|
|
32655
33540
|
projects.sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
|
|
32656
33541
|
return { command: "project.list", data: { projects }, ok: true };
|
|
32657
33542
|
}
|
|
32658
|
-
async
|
|
32659
|
-
const
|
|
32660
|
-
if (
|
|
32661
|
-
|
|
33543
|
+
async deliveryInputs(workItemId) {
|
|
33544
|
+
const resolved = await this.#resolve(workItemId);
|
|
33545
|
+
if (resolved.payload.stage !== "delivery" || resolved.payload.action !== "delivery-preview" && resolved.payload.action !== "delivery-confirm") {
|
|
33546
|
+
throw new WorkflowCliError("DXC_WORK_ITEM_STALE", "\u5F53\u524D\u5DE5\u4F5C\u9879\u4E0D\u662F\u53EF\u4EA4\u4ED8\u5DE5\u4F5C\u9879\u3002");
|
|
32662
33547
|
}
|
|
32663
|
-
|
|
32664
|
-
|
|
32665
|
-
|
|
32666
|
-
|
|
32667
|
-
|
|
32668
|
-
};
|
|
33548
|
+
await validateRequiredInputs(resolved.location, "delivery");
|
|
33549
|
+
const titleSource = await readArtifact(resolved.location, "titles");
|
|
33550
|
+
const title = selectedTitle(frontmatter(titleSource));
|
|
33551
|
+
if (title === void 0) {
|
|
33552
|
+
throw new WorkflowCliError("DXC_WORKFLOW_ARTIFACT_INVALID", "\u6807\u9898\u4EA7\u7269\u7F3A\u5C11\u6700\u7EC8\u6807\u9898\u3002");
|
|
32669
33553
|
}
|
|
32670
|
-
|
|
32671
|
-
|
|
32672
|
-
|
|
33554
|
+
let sidecar;
|
|
33555
|
+
try {
|
|
33556
|
+
sidecar = await readWorkflowVisualAssetsSidecar(resolved.location.directory);
|
|
33557
|
+
await validateWorkflowVisualAssets({
|
|
33558
|
+
articleSource: await readArtifact(resolved.location, "article"),
|
|
33559
|
+
assetsDirectory: path8.join(
|
|
33560
|
+
resolved.location.directory,
|
|
33561
|
+
resolved.location.manifest.assetsDirectory
|
|
33562
|
+
),
|
|
33563
|
+
projectDirectory: resolved.location.directory,
|
|
33564
|
+
visualPlanSource: await readArtifact(resolved.location, "visual-plan")
|
|
33565
|
+
});
|
|
33566
|
+
} catch {
|
|
33567
|
+
throw new WorkflowCliError(
|
|
33568
|
+
"DXC_WORKFLOW_ARTIFACT_INVALID",
|
|
33569
|
+
"\u89C6\u89C9\u7D20\u6750 sidecar\uFF08\u65C1\u8F66\u5143\u6570\u636E\uFF09\u7F3A\u5931\uFF0C\u8BF7\u91CD\u65B0\u5B8C\u6210 visual-plan \u9636\u6BB5\u3002"
|
|
33570
|
+
);
|
|
32673
33571
|
}
|
|
32674
|
-
const state = await this.#loadState(location);
|
|
32675
|
-
const confirmationPolicy = await this.#confirmationPolicy();
|
|
32676
33572
|
return {
|
|
32677
|
-
|
|
32678
|
-
|
|
32679
|
-
|
|
33573
|
+
articleFile: artifactPath(resolved.location, "article"),
|
|
33574
|
+
assetsDirectory: path8.join(
|
|
33575
|
+
resolved.location.directory,
|
|
33576
|
+
resolved.location.manifest.assetsDirectory
|
|
33577
|
+
),
|
|
33578
|
+
project: projectSummary(resolved.location),
|
|
33579
|
+
projectDirectory: resolved.location.directory,
|
|
33580
|
+
title,
|
|
33581
|
+
visualPlanFile: sidecar.publishingVisualPlanPath
|
|
32680
33582
|
};
|
|
32681
33583
|
}
|
|
32682
|
-
async
|
|
32683
|
-
const
|
|
32684
|
-
|
|
32685
|
-
|
|
32686
|
-
const step = nextStep(state.lastCompletedStep);
|
|
32687
|
-
if (step === null) {
|
|
32688
|
-
return {
|
|
32689
|
-
command: "workflow.next",
|
|
32690
|
-
data: { match: "ready", work: workItem(location, state, confirmationPolicy) },
|
|
32691
|
-
ok: true
|
|
32692
|
-
};
|
|
32693
|
-
}
|
|
32694
|
-
if (step === "delivery") {
|
|
32695
|
-
throw new WorkflowCliError(
|
|
32696
|
-
"DXC_WORKFLOW_DELIVERY_REQUIRED",
|
|
32697
|
-
"\u5185\u5BB9\u5DF2\u7ECF\u51C6\u5907\u5B8C\u6210\uFF1B\u8BF7\u751F\u6210\u5FAE\u4FE1\u9884\u89C8\u5E76\u786E\u8BA4\u4EA4\u4ED8\u3002"
|
|
32698
|
-
);
|
|
32699
|
-
}
|
|
32700
|
-
const source = await readArtifact(location.directory, location.manifest.artifacts[step]);
|
|
32701
|
-
await validateStageResult(step, source, location);
|
|
32702
|
-
if (requiresStageConfirmation(confirmationPolicy, step) && !confirmed) {
|
|
32703
|
-
throw new WorkflowCliError(
|
|
32704
|
-
"DXC_WORKFLOW_CONFIRMATION_REQUIRED",
|
|
32705
|
-
`\u5F53\u524D\u786E\u8BA4\u7B56\u7565\u8981\u6C42\u7528\u6237\u786E\u8BA4${stageLabel(step)}\uFF1B\u786E\u8BA4\u91C7\u7528\u5F53\u524D\u4EA7\u7269\u540E\uFF0C\u8BF7\u4F7F\u7528 --confirm \u5B8C\u6210\u672C\u9636\u6BB5\u3002`
|
|
32706
|
-
);
|
|
33584
|
+
async issueDeliveryConfirmation(previewWorkItemId, bindingFingerprint, expiresAt) {
|
|
33585
|
+
const resolved = await this.#resolve(previewWorkItemId);
|
|
33586
|
+
if (resolved.payload.action !== "delivery-preview") {
|
|
33587
|
+
throw new WorkflowCliError("DXC_WORK_ITEM_STALE", "\u8BF7\u4ECE\u5F53\u524D delivery \u9884\u89C8\u5DE5\u4F5C\u9879\u5F00\u59CB\u3002");
|
|
32707
33588
|
}
|
|
32708
|
-
const
|
|
32709
|
-
...
|
|
32710
|
-
|
|
32711
|
-
|
|
32712
|
-
|
|
32713
|
-
|
|
32714
|
-
|
|
32715
|
-
|
|
32716
|
-
data: { match: "ready", work: workItem(location, nextState, confirmationPolicy) },
|
|
32717
|
-
ok: true
|
|
33589
|
+
const payload = {
|
|
33590
|
+
...await this.#basePayload(
|
|
33591
|
+
resolved.location,
|
|
33592
|
+
resolved.state,
|
|
33593
|
+
"delivery",
|
|
33594
|
+
"delivery-confirm"
|
|
33595
|
+
),
|
|
33596
|
+
bindingFingerprint
|
|
32718
33597
|
};
|
|
33598
|
+
return this.#result(resolved.location, payload, true, {
|
|
33599
|
+
expiresAt,
|
|
33600
|
+
type: "confirm-delivery"
|
|
33601
|
+
});
|
|
32719
33602
|
}
|
|
32720
|
-
async
|
|
32721
|
-
const
|
|
32722
|
-
|
|
32723
|
-
if (nextStep(state.lastCompletedStep) !== "delivery") {
|
|
33603
|
+
async resolveDeliveryConfirmation(workItemId, bindingFingerprint) {
|
|
33604
|
+
const resolved = await this.#resolve(workItemId);
|
|
33605
|
+
if (resolved.payload.action !== "delivery-confirm" || resolved.payload.bindingFingerprint !== bindingFingerprint) {
|
|
32724
33606
|
throw new WorkflowCliError(
|
|
32725
|
-
"
|
|
32726
|
-
"\
|
|
33607
|
+
"DXC_WORK_ITEM_STALE",
|
|
33608
|
+
"\u6700\u7EC8\u9884\u89C8\u7ED1\u5B9A\u5DF2\u53D8\u5316\uFF0C\u8BF7\u91CD\u65B0\u6253\u5F00\u5E76\u786E\u8BA4\u5F53\u524D\u9884\u89C8\u3002"
|
|
32727
33609
|
);
|
|
32728
33610
|
}
|
|
32729
|
-
|
|
32730
|
-
const title = selectedTitle(frontmatter(titleSource));
|
|
32731
|
-
return {
|
|
32732
|
-
articleFile: path8.join(location.directory, location.manifest.artifacts.article),
|
|
32733
|
-
assetsDirectory: path8.join(location.directory, location.manifest.assetsDirectory),
|
|
32734
|
-
project: projectSummary(location),
|
|
32735
|
-
projectDirectory: location.directory,
|
|
32736
|
-
title,
|
|
32737
|
-
visualPlanFile: path8.join(location.directory, location.manifest.artifacts["visual-plan"])
|
|
32738
|
-
};
|
|
33611
|
+
return this.deliveryInputs(workItemId);
|
|
32739
33612
|
}
|
|
32740
|
-
async completeDelivery(
|
|
32741
|
-
const
|
|
32742
|
-
|
|
32743
|
-
|
|
32744
|
-
if (nextStep(state.lastCompletedStep) !== "delivery") {
|
|
32745
|
-
throw new WorkflowCliError("DXC_WORKFLOW_NOT_READY", "\u5F53\u524D\u6587\u7AE0\u4E0D\u5728\u5FAE\u4FE1\u4EA4\u4ED8\u6B65\u9AA4\u3002");
|
|
33613
|
+
async completeDelivery(workItemId, bindingFingerprint, receipt) {
|
|
33614
|
+
const resolved = await this.#resolve(workItemId);
|
|
33615
|
+
if (resolved.payload.action !== "delivery-confirm" || resolved.payload.bindingFingerprint !== bindingFingerprint) {
|
|
33616
|
+
throw new WorkflowCliError("DXC_WORK_ITEM_STALE", "\u4EA4\u4ED8\u786E\u8BA4\u4E0D\u5C5E\u4E8E\u5F53\u524D\u4E0D\u53EF\u53D8\u9884\u89C8\u3002");
|
|
32746
33617
|
}
|
|
32747
|
-
const deliveryFile =
|
|
33618
|
+
const deliveryFile = artifactPath(resolved.location, "delivery");
|
|
32748
33619
|
await writePrivateBuffer(
|
|
32749
33620
|
deliveryFile,
|
|
32750
33621
|
Buffer.from(
|
|
@@ -32752,22 +33623,12 @@ var WorkflowCli = class {
|
|
|
32752
33623
|
|
|
32753
33624
|
- intentId: ${receipt.intentId}
|
|
32754
33625
|
- mediaId: ${receipt.mediaId}
|
|
32755
|
-
- completedAt: ${this.#
|
|
33626
|
+
- completedAt: ${this.#nextTimestamp(resolved.state.updatedAt)}
|
|
32756
33627
|
`,
|
|
32757
33628
|
"utf8"
|
|
32758
33629
|
)
|
|
32759
33630
|
);
|
|
32760
|
-
|
|
32761
|
-
...state,
|
|
32762
|
-
lastCompletedStep: "delivery",
|
|
32763
|
-
updatedAt: this.#now().toISOString()
|
|
32764
|
-
};
|
|
32765
|
-
await writePrivateJson(statePath(location.directory), nextState);
|
|
32766
|
-
return {
|
|
32767
|
-
command: "workflow.next",
|
|
32768
|
-
data: { match: "ready", work: workItem(location, nextState, confirmationPolicy) },
|
|
32769
|
-
ok: true
|
|
32770
|
-
};
|
|
33631
|
+
return this.#advance(resolved.location, resolved.state, "delivery");
|
|
32771
33632
|
}
|
|
32772
33633
|
};
|
|
32773
33634
|
|
|
@@ -32775,15 +33636,21 @@ var WorkflowCli = class {
|
|
|
32775
33636
|
var DELIVERY_STATE_FILE = ".dxc/delivery.json";
|
|
32776
33637
|
var DELIVERY_STATE_MAXIMUM_BYTES = 32 * 1024;
|
|
32777
33638
|
var MAXIMUM_POLL_ATTEMPTS = 150;
|
|
33639
|
+
var CHOICE_PATTERN = /^choice1_([A-Za-z0-9_-]+)\.([a-f0-9]{32})$/u;
|
|
33640
|
+
function sha2563(value) {
|
|
33641
|
+
return createHash8("sha256").update(value, "utf8").digest("hex");
|
|
33642
|
+
}
|
|
32778
33643
|
function selectedDraftIdempotencyKey(projectId, rootSnapshotHash, selectedSnapshotHash, selectionRevision) {
|
|
32779
|
-
const selectionDigest =
|
|
33644
|
+
const selectionDigest = sha2563(
|
|
33645
|
+
`${rootSnapshotHash}:${selectedSnapshotHash}:${selectionRevision}`
|
|
33646
|
+
);
|
|
32780
33647
|
return `dxc:${projectId}:${selectionDigest}`;
|
|
32781
33648
|
}
|
|
32782
33649
|
function isRecord2(value) {
|
|
32783
33650
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
32784
33651
|
}
|
|
32785
33652
|
function deliveryState(value) {
|
|
32786
|
-
if (!isRecord2(value) || value["version"] !== 1) {
|
|
33653
|
+
if (!isRecord2(value) || value["version"] !== 1 && value["version"] !== 2) {
|
|
32787
33654
|
return void 0;
|
|
32788
33655
|
}
|
|
32789
33656
|
const required = [
|
|
@@ -32803,31 +33670,86 @@ function deliveryState(value) {
|
|
|
32803
33670
|
if (value["intentId"] !== void 0 && typeof value["intentId"] !== "string") {
|
|
32804
33671
|
return void 0;
|
|
32805
33672
|
}
|
|
33673
|
+
if (value["version"] === 2 && (typeof value["selectedSnapshotHash"] !== "string" || typeof value["selectedSnapshotId"] !== "string" || !Number.isInteger(value["selectionRevision"]) || typeof value["templateId"] !== "string")) {
|
|
33674
|
+
return void 0;
|
|
33675
|
+
}
|
|
32806
33676
|
return value;
|
|
32807
33677
|
}
|
|
32808
|
-
function accountChoice(account) {
|
|
32809
|
-
return { id: account.id, name: account.displayName };
|
|
32810
|
-
}
|
|
32811
33678
|
function availableAccounts(accounts) {
|
|
32812
33679
|
return accounts.filter(
|
|
32813
33680
|
(account) => account.status === "ACTIVE" && account.draftCapability === "available" && account.permissions.includes(11)
|
|
32814
33681
|
);
|
|
32815
33682
|
}
|
|
33683
|
+
function encodeChoice(workItemId, account) {
|
|
33684
|
+
const payload = Buffer.from(
|
|
33685
|
+
JSON.stringify({ accountId: account.id, workItemFingerprint: sha2563(workItemId) }),
|
|
33686
|
+
"utf8"
|
|
33687
|
+
).toString("base64url");
|
|
33688
|
+
return `choice1_${payload}.${sha2563(payload).slice(0, 32)}`;
|
|
33689
|
+
}
|
|
33690
|
+
function decodeChoice(choiceId, workItemId) {
|
|
33691
|
+
const match = CHOICE_PATTERN.exec(choiceId);
|
|
33692
|
+
if (match === null || match[1] === void 0 || match[2] === void 0 || sha2563(match[1]).slice(0, 32) !== match[2]) {
|
|
33693
|
+
throw new WorkflowCliError("DXC_WORK_ITEM_INVALID", "\u516C\u4F17\u53F7 choiceId \u65E0\u6548\u3002");
|
|
33694
|
+
}
|
|
33695
|
+
try {
|
|
33696
|
+
const payload = JSON.parse(Buffer.from(match[1], "base64url").toString("utf8"));
|
|
33697
|
+
if (!isRecord2(payload) || typeof payload["accountId"] !== "string" || payload["workItemFingerprint"] !== sha2563(workItemId)) {
|
|
33698
|
+
throw new TypeError("choice binding mismatch");
|
|
33699
|
+
}
|
|
33700
|
+
return payload["accountId"];
|
|
33701
|
+
} catch {
|
|
33702
|
+
throw new WorkflowCliError(
|
|
33703
|
+
"DXC_WORK_ITEM_STALE",
|
|
33704
|
+
"\u516C\u4F17\u53F7 choiceId \u4E0D\u5C5E\u4E8E\u5F53\u524D delivery \u5DE5\u4F5C\u9879\uFF0C\u8BF7\u91CD\u65B0\u9009\u62E9\u3002"
|
|
33705
|
+
);
|
|
33706
|
+
}
|
|
33707
|
+
}
|
|
33708
|
+
function selectedState(state, preview) {
|
|
33709
|
+
return {
|
|
33710
|
+
...state,
|
|
33711
|
+
idempotencyKey: selectedDraftIdempotencyKey(
|
|
33712
|
+
state.projectId,
|
|
33713
|
+
state.rootSnapshotHash,
|
|
33714
|
+
preview.selectedSnapshotHash,
|
|
33715
|
+
preview.selectionRevision
|
|
33716
|
+
),
|
|
33717
|
+
selectedSnapshotHash: preview.selectedSnapshotHash,
|
|
33718
|
+
selectedSnapshotId: preview.selectedSnapshotId,
|
|
33719
|
+
selectionRevision: preview.selectionRevision,
|
|
33720
|
+
templateId: preview.templateId,
|
|
33721
|
+
version: 2
|
|
33722
|
+
};
|
|
33723
|
+
}
|
|
33724
|
+
function deliveryBindingFingerprint(state) {
|
|
33725
|
+
return sha2563(
|
|
33726
|
+
JSON.stringify({
|
|
33727
|
+
accountId: state.accountId,
|
|
33728
|
+
projectId: state.projectId,
|
|
33729
|
+
rootSnapshotHash: state.rootSnapshotHash,
|
|
33730
|
+
rootSnapshotId: state.rootSnapshotId,
|
|
33731
|
+
selectedSnapshotHash: state.selectedSnapshotHash,
|
|
33732
|
+
selectedSnapshotId: state.selectedSnapshotId,
|
|
33733
|
+
selectionRevision: state.selectionRevision,
|
|
33734
|
+
templateId: state.templateId
|
|
33735
|
+
})
|
|
33736
|
+
);
|
|
33737
|
+
}
|
|
33738
|
+
function completedVerification(verification) {
|
|
33739
|
+
return verification !== void 0 && verification.authorMatched === true && verification.contentMatched === true && verification.coverMatched === true && verification.digestMatched === true && verification.titleMatched === true && verification.imageMismatches.length === 0;
|
|
33740
|
+
}
|
|
32816
33741
|
var WorkflowDeliveryCli = class {
|
|
32817
33742
|
#output;
|
|
32818
33743
|
#sleep;
|
|
32819
33744
|
#wechat;
|
|
32820
33745
|
#workflow;
|
|
32821
33746
|
constructor(input) {
|
|
32822
|
-
this.#output = {
|
|
32823
|
-
writeStderr: input.output.writeStderr,
|
|
32824
|
-
writeStdout: () => void 0
|
|
32825
|
-
};
|
|
33747
|
+
this.#output = { writeStderr: input.output.writeStderr, writeStdout: () => void 0 };
|
|
32826
33748
|
this.#sleep = input.sleep ?? ((milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)));
|
|
32827
33749
|
this.#wechat = input.wechat;
|
|
32828
33750
|
this.#workflow = input.workflow;
|
|
32829
33751
|
}
|
|
32830
|
-
async #
|
|
33752
|
+
async #readStateIfPresent(projectDirectory) {
|
|
32831
33753
|
try {
|
|
32832
33754
|
const source = await readPrivateFile(
|
|
32833
33755
|
path9.join(projectDirectory, DELIVERY_STATE_FILE),
|
|
@@ -32839,10 +33761,7 @@ var WorkflowDeliveryCli = class {
|
|
|
32839
33761
|
}
|
|
32840
33762
|
} catch (error) {
|
|
32841
33763
|
if (error instanceof LocalStateError && error.failure === "missing") {
|
|
32842
|
-
|
|
32843
|
-
"DXC_WORKFLOW_PREVIEW_REQUIRED",
|
|
32844
|
-
"\u8BF7\u5148\u751F\u6210\u5E76\u67E5\u770B\u5F53\u524D\u6587\u7AE0\u7684\u5FAE\u4FE1\u9884\u89C8\u3002"
|
|
32845
|
-
);
|
|
33764
|
+
return void 0;
|
|
32846
33765
|
}
|
|
32847
33766
|
}
|
|
32848
33767
|
throw new WorkflowCliError(
|
|
@@ -32850,11 +33769,64 @@ var WorkflowDeliveryCli = class {
|
|
|
32850
33769
|
"\u672C\u5730\u4EA4\u4ED8\u72B6\u6001\u65E0\u6CD5\u8BFB\u53D6\uFF1B\u672A\u521B\u5EFA\u65B0\u7684\u5FAE\u4FE1\u8349\u7A3F\u3002"
|
|
32851
33770
|
);
|
|
32852
33771
|
}
|
|
33772
|
+
async #readState(projectDirectory) {
|
|
33773
|
+
const state = await this.#readStateIfPresent(projectDirectory);
|
|
33774
|
+
if (state !== void 0) {
|
|
33775
|
+
return state;
|
|
33776
|
+
}
|
|
33777
|
+
throw new WorkflowCliError(
|
|
33778
|
+
"DXC_WORKFLOW_PREVIEW_REQUIRED",
|
|
33779
|
+
"\u8BF7\u5148\u751F\u6210\u5E76\u67E5\u770B\u5F53\u524D\u6587\u7AE0\u7684\u5FAE\u4FE1\u9884\u89C8\u3002"
|
|
33780
|
+
);
|
|
33781
|
+
}
|
|
32853
33782
|
async #writeState(projectDirectory, state) {
|
|
32854
33783
|
await writePrivateJson(path9.join(projectDirectory, DELIVERY_STATE_FILE), state);
|
|
32855
33784
|
}
|
|
33785
|
+
async #selectState(projectDirectory, state) {
|
|
33786
|
+
const preview = await this.#wechat.draftPreviewStatus(
|
|
33787
|
+
{ snapshotHash: state.rootSnapshotHash, snapshotId: state.rootSnapshotId },
|
|
33788
|
+
this.#output
|
|
33789
|
+
);
|
|
33790
|
+
const selected = selectedState(state, preview);
|
|
33791
|
+
await this.#writeState(projectDirectory, selected);
|
|
33792
|
+
return selected;
|
|
33793
|
+
}
|
|
33794
|
+
#selectionWorkItem(workItemId, accounts) {
|
|
33795
|
+
const nextAction = {
|
|
33796
|
+
choices: accounts.map((account) => ({
|
|
33797
|
+
choiceId: encodeChoice(workItemId, account),
|
|
33798
|
+
label: account.displayName
|
|
33799
|
+
})),
|
|
33800
|
+
purpose: "wechat-account",
|
|
33801
|
+
type: "select-choice"
|
|
33802
|
+
};
|
|
33803
|
+
return {
|
|
33804
|
+
nextAction,
|
|
33805
|
+
skill: "dxc-wechat-publisher",
|
|
33806
|
+
stage: "delivery",
|
|
33807
|
+
workItemId
|
|
33808
|
+
};
|
|
33809
|
+
}
|
|
32856
33810
|
async preview(options) {
|
|
32857
|
-
const inputs = await this.#workflow.deliveryInputs(options.
|
|
33811
|
+
const inputs = await this.#workflow.deliveryInputs(options.workItemId);
|
|
33812
|
+
const existingState = await this.#readStateIfPresent(inputs.projectDirectory);
|
|
33813
|
+
if (existingState?.projectId === inputs.project.projectId && existingState.intentId !== void 0) {
|
|
33814
|
+
await this.#wechat.publishingDraftStatus(existingState.intentId, this.#output);
|
|
33815
|
+
const selected = await this.#selectState(inputs.projectDirectory, existingState);
|
|
33816
|
+
const confirmation2 = await this.#workflow.issueDeliveryConfirmation(
|
|
33817
|
+
options.workItemId,
|
|
33818
|
+
deliveryBindingFingerprint(selected),
|
|
33819
|
+
selected.previewExpiresAt
|
|
33820
|
+
);
|
|
33821
|
+
return {
|
|
33822
|
+
command: "workflow.preview",
|
|
33823
|
+
data: {
|
|
33824
|
+
...confirmation2.data,
|
|
33825
|
+
status: "needs-attention"
|
|
33826
|
+
},
|
|
33827
|
+
ok: true
|
|
33828
|
+
};
|
|
33829
|
+
}
|
|
32858
33830
|
const accounts = availableAccounts(await this.#wechat.accounts(this.#output));
|
|
32859
33831
|
if (accounts.length === 0) {
|
|
32860
33832
|
throw new WechatCliError(
|
|
@@ -32862,9 +33834,10 @@ var WorkflowDeliveryCli = class {
|
|
|
32862
33834
|
"\u5F53\u524D\u6CA1\u6709\u53EF\u521B\u5EFA\u8349\u7A3F\u7684\u516C\u4F17\u53F7\uFF0C\u8BF7\u5148\u5B8C\u6210\u516C\u4F17\u53F7\u7ED1\u5B9A\u3002"
|
|
32863
33835
|
);
|
|
32864
33836
|
}
|
|
32865
|
-
const
|
|
33837
|
+
const accountId = options.choiceId === void 0 ? void 0 : decodeChoice(options.choiceId, options.workItemId);
|
|
33838
|
+
const account = accountId === void 0 ? accounts.length === 1 ? accounts[0] : void 0 : accounts.find((candidate) => candidate.id === accountId);
|
|
32866
33839
|
if (account === void 0) {
|
|
32867
|
-
if (
|
|
33840
|
+
if (accountId !== void 0) {
|
|
32868
33841
|
throw new WechatCliError(
|
|
32869
33842
|
"DXC_PUBLISHING_ACCOUNT_UNAVAILABLE",
|
|
32870
33843
|
"\u9009\u62E9\u7684\u516C\u4F17\u53F7\u5F53\u524D\u4E0D\u53EF\u7528\u4E8E\u521B\u5EFA\u8349\u7A3F\u3002"
|
|
@@ -32873,17 +33846,15 @@ var WorkflowDeliveryCli = class {
|
|
|
32873
33846
|
return {
|
|
32874
33847
|
command: "workflow.preview",
|
|
32875
33848
|
data: {
|
|
32876
|
-
|
|
32877
|
-
status: "account-selection-required"
|
|
33849
|
+
project: inputs.project,
|
|
33850
|
+
status: "account-selection-required",
|
|
33851
|
+
workItem: this.#selectionWorkItem(options.workItemId, accounts)
|
|
32878
33852
|
},
|
|
32879
33853
|
ok: true
|
|
32880
33854
|
};
|
|
32881
33855
|
}
|
|
32882
33856
|
await this.#wechat.optimizeDraftImages(
|
|
32883
|
-
{
|
|
32884
|
-
projectDirectory: inputs.projectDirectory,
|
|
32885
|
-
visualPlanFile: inputs.visualPlanFile
|
|
32886
|
-
},
|
|
33857
|
+
{ projectDirectory: inputs.projectDirectory, visualPlanFile: inputs.visualPlanFile },
|
|
32887
33858
|
this.#output
|
|
32888
33859
|
);
|
|
32889
33860
|
const preview = await this.#wechat.previewDraft(
|
|
@@ -32891,14 +33862,14 @@ var WorkflowDeliveryCli = class {
|
|
|
32891
33862
|
accountId: account.id,
|
|
32892
33863
|
articleFile: inputs.articleFile,
|
|
32893
33864
|
assetsDirectory: inputs.assetsDirectory,
|
|
32894
|
-
browserMode:
|
|
33865
|
+
browserMode: "agent",
|
|
32895
33866
|
coverFile: "auto",
|
|
32896
33867
|
title: inputs.title,
|
|
32897
33868
|
visualPlanFile: inputs.visualPlanFile
|
|
32898
33869
|
},
|
|
32899
33870
|
this.#output
|
|
32900
33871
|
);
|
|
32901
|
-
await this.#
|
|
33872
|
+
const state = await this.#selectState(inputs.projectDirectory, {
|
|
32902
33873
|
accountId: account.id,
|
|
32903
33874
|
idempotencyKey: `dxc:${inputs.project.projectId}:${preview.snapshot.snapshotHash}`,
|
|
32904
33875
|
previewExpiresAt: preview.preview.expiresAt,
|
|
@@ -32908,14 +33879,14 @@ var WorkflowDeliveryCli = class {
|
|
|
32908
33879
|
rootSnapshotId: preview.snapshot.id,
|
|
32909
33880
|
version: 1
|
|
32910
33881
|
});
|
|
33882
|
+
const confirmation = await this.#workflow.issueDeliveryConfirmation(
|
|
33883
|
+
options.workItemId,
|
|
33884
|
+
deliveryBindingFingerprint(state),
|
|
33885
|
+
state.previewExpiresAt
|
|
33886
|
+
);
|
|
32911
33887
|
return {
|
|
32912
33888
|
command: "workflow.preview",
|
|
32913
|
-
data: {
|
|
32914
|
-
account: accountChoice(account),
|
|
32915
|
-
expiresAt: preview.preview.expiresAt,
|
|
32916
|
-
opened: true,
|
|
32917
|
-
status: "ready"
|
|
32918
|
-
},
|
|
33889
|
+
data: { ...confirmation.data, status: "ready" },
|
|
32919
33890
|
ok: true
|
|
32920
33891
|
};
|
|
32921
33892
|
}
|
|
@@ -32930,6 +33901,30 @@ var WorkflowDeliveryCli = class {
|
|
|
32930
33901
|
}
|
|
32931
33902
|
return current;
|
|
32932
33903
|
}
|
|
33904
|
+
async #diagnostics(result) {
|
|
33905
|
+
try {
|
|
33906
|
+
return await this.#wechat.publishingDraftDiagnostics(result.intent.id, this.#output);
|
|
33907
|
+
} catch {
|
|
33908
|
+
return {
|
|
33909
|
+
...result.intent.errorCode === void 0 ? {} : { errorCode: result.intent.errorCode },
|
|
33910
|
+
intentId: result.intent.id,
|
|
33911
|
+
reason: {
|
|
33912
|
+
message: result.intent.progress.message,
|
|
33913
|
+
nextAction: result.intent.progress.nextAction,
|
|
33914
|
+
phase: "unknown",
|
|
33915
|
+
retryAllowed: false
|
|
33916
|
+
},
|
|
33917
|
+
status: result.intent.status,
|
|
33918
|
+
...result.intent.verification === void 0 ? {} : {
|
|
33919
|
+
verification: {
|
|
33920
|
+
...result.intent.verification,
|
|
33921
|
+
coverMatched: null,
|
|
33922
|
+
imageMismatches: []
|
|
33923
|
+
}
|
|
33924
|
+
}
|
|
33925
|
+
};
|
|
33926
|
+
}
|
|
33927
|
+
}
|
|
32933
33928
|
async deliver(options) {
|
|
32934
33929
|
if (!options.confirmed) {
|
|
32935
33930
|
throw new WechatCliError(
|
|
@@ -32937,29 +33932,33 @@ var WorkflowDeliveryCli = class {
|
|
|
32937
33932
|
"\u8BF7\u5148\u67E5\u770B\u5FAE\u4FE1\u9884\u89C8\u5E76\u660E\u786E\u786E\u8BA4\u521B\u5EFA\u8349\u7A3F\u3002"
|
|
32938
33933
|
);
|
|
32939
33934
|
}
|
|
32940
|
-
const
|
|
32941
|
-
let state = await this.#
|
|
33935
|
+
const unresolvedInputs = await this.#workflow.deliveryInputs(options.workItemId);
|
|
33936
|
+
let state = await this.#selectState(
|
|
33937
|
+
unresolvedInputs.projectDirectory,
|
|
33938
|
+
await this.#readState(unresolvedInputs.projectDirectory)
|
|
33939
|
+
);
|
|
33940
|
+
const bindingFingerprint = deliveryBindingFingerprint(state);
|
|
33941
|
+
const inputs = await this.#workflow.resolveDeliveryConfirmation(
|
|
33942
|
+
options.workItemId,
|
|
33943
|
+
bindingFingerprint
|
|
33944
|
+
);
|
|
32942
33945
|
if (state.projectId !== inputs.project.projectId) {
|
|
32943
|
-
throw new WorkflowCliError(
|
|
32944
|
-
"DXC_WORKFLOW_DELIVERY_STATE_INVALID",
|
|
32945
|
-
"\u9884\u89C8\u4E0D\u5C5E\u4E8E\u5F53\u524D\u6587\u7AE0\uFF1B\u8BF7\u91CD\u65B0\u751F\u6210\u5FAE\u4FE1\u9884\u89C8\u3002"
|
|
32946
|
-
);
|
|
33946
|
+
throw new WorkflowCliError("DXC_WORK_ITEM_STALE", "\u9884\u89C8\u4E0D\u5C5E\u4E8E\u5F53\u524D\u6587\u7AE0\uFF1B\u8BF7\u91CD\u65B0\u751F\u6210\u5FAE\u4FE1\u9884\u89C8\u3002");
|
|
32947
33947
|
}
|
|
32948
33948
|
const preview = await this.#wechat.draftPreviewStatus(
|
|
32949
33949
|
{ snapshotHash: state.rootSnapshotHash, snapshotId: state.rootSnapshotId },
|
|
32950
33950
|
this.#output
|
|
32951
33951
|
);
|
|
32952
|
-
const
|
|
32953
|
-
|
|
32954
|
-
|
|
32955
|
-
|
|
32956
|
-
|
|
32957
|
-
|
|
32958
|
-
|
|
32959
|
-
if (state.intentId === void 0 && state.idempotencyKey !== selectedIdempotencyKey) {
|
|
32960
|
-
state = { ...state, idempotencyKey: selectedIdempotencyKey };
|
|
32961
|
-
await this.#writeState(inputs.projectDirectory, state);
|
|
33952
|
+
const current = selectedState(state, preview);
|
|
33953
|
+
if (deliveryBindingFingerprint(current) !== bindingFingerprint) {
|
|
33954
|
+
await this.#writeState(inputs.projectDirectory, current);
|
|
33955
|
+
throw new WorkflowCliError(
|
|
33956
|
+
"DXC_WORK_ITEM_STALE",
|
|
33957
|
+
"\u6A21\u677F\u3001\u8D26\u53F7\u6216\u4E0D\u53EF\u53D8\u5FEB\u7167\u9009\u62E9\u5DF2\u7ECF\u53D8\u5316\uFF0C\u8BF7\u91CD\u65B0\u67E5\u770B\u6700\u7EC8\u9884\u89C8\u3002"
|
|
33958
|
+
);
|
|
32962
33959
|
}
|
|
33960
|
+
state = current;
|
|
33961
|
+
const template = { id: state.templateId, selectionRevision: state.selectionRevision };
|
|
32963
33962
|
if (!preview.viewed) {
|
|
32964
33963
|
const refreshed = await this.#wechat.refreshDraftPreview(
|
|
32965
33964
|
{
|
|
@@ -32971,9 +33970,19 @@ var WorkflowDeliveryCli = class {
|
|
|
32971
33970
|
);
|
|
32972
33971
|
state = { ...state, previewExpiresAt: refreshed.expiresAt };
|
|
32973
33972
|
await this.#writeState(inputs.projectDirectory, state);
|
|
33973
|
+
const confirmation = await this.#workflow.issueDeliveryConfirmation(
|
|
33974
|
+
(await this.#workflow.next({ projectId: state.projectId })).data.workItem.workItemId,
|
|
33975
|
+
bindingFingerprint,
|
|
33976
|
+
refreshed.expiresAt
|
|
33977
|
+
);
|
|
32974
33978
|
return {
|
|
32975
33979
|
command: "workflow.deliver",
|
|
32976
|
-
data: {
|
|
33980
|
+
data: {
|
|
33981
|
+
expiresAt: refreshed.expiresAt,
|
|
33982
|
+
status: "preview-required",
|
|
33983
|
+
template,
|
|
33984
|
+
workItem: confirmation.data.workItem
|
|
33985
|
+
},
|
|
32977
33986
|
ok: true
|
|
32978
33987
|
};
|
|
32979
33988
|
}
|
|
@@ -32991,7 +34000,8 @@ var WorkflowDeliveryCli = class {
|
|
|
32991
34000
|
);
|
|
32992
34001
|
state = { ...state, intentId: result.intent.id };
|
|
32993
34002
|
await this.#writeState(inputs.projectDirectory, state);
|
|
32994
|
-
|
|
34003
|
+
let diagnostics = result.intent.status === "FAILED" ? await this.#diagnostics(result) : void 0;
|
|
34004
|
+
if (result.intent.status === "FAILED" && state.retryAttempt === 0 && diagnostics?.reason.retryAllowed === true) {
|
|
32995
34005
|
result = await this.#terminal(
|
|
32996
34006
|
await this.#wechat.retryFailedDraft(
|
|
32997
34007
|
{
|
|
@@ -33003,32 +34013,57 @@ var WorkflowDeliveryCli = class {
|
|
|
33003
34013
|
);
|
|
33004
34014
|
state = { ...state, intentId: result.intent.id, retryAttempt: 1 };
|
|
33005
34015
|
await this.#writeState(inputs.projectDirectory, state);
|
|
34016
|
+
diagnostics = void 0;
|
|
33006
34017
|
}
|
|
33007
|
-
if (result.intent.status === "CREATED_UNVERIFIED") {
|
|
33008
|
-
|
|
33009
|
-
await this.#
|
|
33010
|
-
|
|
34018
|
+
if (result.intent.status === "CREATED_UNVERIFIED" && result.intent.mediaId !== void 0) {
|
|
34019
|
+
try {
|
|
34020
|
+
result = await this.#terminal(
|
|
34021
|
+
await this.#wechat.reverifyDraft(result.intent.id, this.#output)
|
|
34022
|
+
);
|
|
34023
|
+
diagnostics = void 0;
|
|
34024
|
+
} catch {
|
|
34025
|
+
}
|
|
33011
34026
|
}
|
|
33012
34027
|
if (result.intent.status === "SUCCEEDED" && result.intent.mediaId !== void 0) {
|
|
33013
|
-
await this.#
|
|
33014
|
-
|
|
33015
|
-
|
|
33016
|
-
|
|
33017
|
-
|
|
33018
|
-
|
|
33019
|
-
|
|
33020
|
-
|
|
34028
|
+
const completedDiagnostics = await this.#diagnostics(result);
|
|
34029
|
+
if (completedVerification(completedDiagnostics.verification)) {
|
|
34030
|
+
await this.#workflow.completeDelivery(options.workItemId, bindingFingerprint, {
|
|
34031
|
+
intentId: result.intent.id,
|
|
34032
|
+
mediaId: result.intent.mediaId
|
|
34033
|
+
});
|
|
34034
|
+
return {
|
|
34035
|
+
command: "workflow.deliver",
|
|
34036
|
+
data: {
|
|
34037
|
+
mediaId: result.intent.mediaId,
|
|
34038
|
+
status: "completed",
|
|
34039
|
+
template,
|
|
34040
|
+
verification: completedDiagnostics.verification
|
|
34041
|
+
},
|
|
34042
|
+
ok: true
|
|
34043
|
+
};
|
|
34044
|
+
}
|
|
34045
|
+
diagnostics = {
|
|
34046
|
+
...completedDiagnostics,
|
|
34047
|
+
reason: {
|
|
34048
|
+
message: "\u8349\u7A3F\u5DF2\u521B\u5EFA\uFF0C\u4F46\u4E94\u5B57\u6BB5\u6216\u56FE\u7247\u8EAB\u4EFD\u56DE\u8BFB\u5C1A\u672A\u5168\u90E8\u901A\u8FC7\u3002",
|
|
34049
|
+
nextAction: "\u4FDD\u7559\u539F intent\uFF0C\u53EA\u8BFB\u6838\u9A8C\u540E\u7EE7\u7EED\u3002",
|
|
34050
|
+
phase: "draft-readback",
|
|
34051
|
+
retryAllowed: false
|
|
34052
|
+
}
|
|
33021
34053
|
};
|
|
33022
34054
|
}
|
|
34055
|
+
diagnostics ??= await this.#diagnostics(result);
|
|
33023
34056
|
return {
|
|
33024
34057
|
command: "workflow.deliver",
|
|
33025
34058
|
data: {
|
|
33026
34059
|
...result.intent.errorCode === void 0 ? {} : { errorCode: result.intent.errorCode },
|
|
33027
34060
|
intentId: result.intent.id,
|
|
33028
|
-
message:
|
|
34061
|
+
message: diagnostics.reason.message,
|
|
34062
|
+
reason: diagnostics.reason,
|
|
33029
34063
|
status: "needs-attention",
|
|
33030
34064
|
template,
|
|
33031
|
-
...result.intent.verification === void 0 ? {} : { verification: result.intent.verification }
|
|
34065
|
+
...result.intent.verification === void 0 ? {} : { verification: result.intent.verification },
|
|
34066
|
+
...diagnostics.verification === void 0 ? {} : { verificationDetails: diagnostics.verification }
|
|
33032
34067
|
},
|
|
33033
34068
|
ok: true
|
|
33034
34069
|
};
|
|
@@ -33063,12 +34098,6 @@ function positiveInteger(value, name = "value") {
|
|
|
33063
34098
|
}
|
|
33064
34099
|
return parsed;
|
|
33065
34100
|
}
|
|
33066
|
-
function previewBrowserMode(value) {
|
|
33067
|
-
if (value !== "agent" && value !== "system") {
|
|
33068
|
-
throw new CommanderError(1, "DXC_OPTION_INVALID", "browser must be agent or system");
|
|
33069
|
-
}
|
|
33070
|
-
return value;
|
|
33071
|
-
}
|
|
33072
34101
|
function skillInstallTarget(value) {
|
|
33073
34102
|
if (value !== "codex" && value !== "workbuddy") {
|
|
33074
34103
|
throw new CommanderError(1, "DXC_OPTION_INVALID", "target must be codex or workbuddy");
|
|
@@ -33088,10 +34117,20 @@ function actionError(error) {
|
|
|
33088
34117
|
};
|
|
33089
34118
|
}
|
|
33090
34119
|
if (error instanceof WorkflowCliError || error instanceof ProjectCliError || error instanceof ProfileCliError || error instanceof ContentMemoryCliError || error instanceof SkillInstallerError) {
|
|
33091
|
-
return {
|
|
34120
|
+
return {
|
|
34121
|
+
code: error.code,
|
|
34122
|
+
...error instanceof WorkflowCliError && error.details !== void 0 ? { details: error.details } : {},
|
|
34123
|
+
message: error.message,
|
|
34124
|
+
retryable: false
|
|
34125
|
+
};
|
|
33092
34126
|
}
|
|
33093
34127
|
if (error instanceof Error && error.name === "KnowledgeCliError" && "code" in error) {
|
|
33094
|
-
return {
|
|
34128
|
+
return {
|
|
34129
|
+
code: String(error.code),
|
|
34130
|
+
..."details" in error && error.details !== void 0 ? { details: error.details } : {},
|
|
34131
|
+
message: error.message,
|
|
34132
|
+
retryable: false
|
|
34133
|
+
};
|
|
33095
34134
|
}
|
|
33096
34135
|
return {
|
|
33097
34136
|
code: "DXC_COMMAND_FAILED",
|
|
@@ -33126,7 +34165,7 @@ async function loadKnowledgeModule() {
|
|
|
33126
34165
|
}
|
|
33127
34166
|
};
|
|
33128
34167
|
try {
|
|
33129
|
-
return await import("./chunks/knowledge-
|
|
34168
|
+
return await import("./chunks/knowledge-JCYMCMSP.js");
|
|
33130
34169
|
} finally {
|
|
33131
34170
|
process.emitWarning = emitWarning;
|
|
33132
34171
|
}
|
|
@@ -33217,24 +34256,27 @@ function createProgram(context) {
|
|
|
33217
34256
|
})
|
|
33218
34257
|
)
|
|
33219
34258
|
);
|
|
33220
|
-
workflow.command("next").description("\u8FD4\u56DE\u552F\u4E00\u9700\u8981\u6267\u884C\u7684\u4E0B\u4E00\u6B65").
|
|
33221
|
-
async (
|
|
34259
|
+
workflow.command("next").description("\u8FD4\u56DE\u552F\u4E00\u9700\u8981\u6267\u884C\u7684\u4E0B\u4E00\u6B65").option("--project <uuid>", "\u9879\u76EE ID").option("--work-item <id>", "\u5F53\u524D\u5DE5\u4F5C\u9879 ID").option("--json", "\u8F93\u51FA JSON").action(
|
|
34260
|
+
async (options) => runAction(
|
|
33222
34261
|
context,
|
|
33223
34262
|
options.json === true,
|
|
33224
34263
|
() => new WorkflowCli({
|
|
33225
34264
|
currentDirectory: context.currentDirectory,
|
|
33226
34265
|
homeDirectory: context.homeDirectory
|
|
33227
|
-
}).next(
|
|
34266
|
+
}).next({
|
|
34267
|
+
...options.project === void 0 ? {} : { projectId: options.project },
|
|
34268
|
+
...options.workItem === void 0 ? {} : { workItemId: options.workItem }
|
|
34269
|
+
})
|
|
33228
34270
|
)
|
|
33229
34271
|
);
|
|
33230
|
-
workflow.command("complete").description("\u4FDD\u5B58\u5F53\u524D\u6B65\u9AA4\u5E76\u8FD4\u56DE\u4E0B\u4E00\u6B65").
|
|
34272
|
+
workflow.command("complete").description("\u4FDD\u5B58\u5F53\u524D\u6B65\u9AA4\u5E76\u8FD4\u56DE\u4E0B\u4E00\u6B65").requiredOption("--work-item <id>", "\u5F53\u524D\u5DE5\u4F5C\u9879 ID").option("--confirm", "\u786E\u8BA4\u91C7\u7528\u5F53\u524D\u9636\u6BB5\u4EA7\u7269").option("--json", "\u8F93\u51FA JSON").action(
|
|
33231
34273
|
async (options) => runAction(
|
|
33232
34274
|
context,
|
|
33233
34275
|
options.json === true,
|
|
33234
34276
|
() => new WorkflowCli({
|
|
33235
34277
|
currentDirectory: context.currentDirectory,
|
|
33236
34278
|
homeDirectory: context.homeDirectory
|
|
33237
|
-
}).complete(options.
|
|
34279
|
+
}).complete(options.workItem, options.confirm === true)
|
|
33238
34280
|
)
|
|
33239
34281
|
);
|
|
33240
34282
|
const deliveryAction = async (json, action) => runAction(context, json, () => {
|
|
@@ -33250,24 +34292,21 @@ function createProgram(context) {
|
|
|
33250
34292
|
})
|
|
33251
34293
|
);
|
|
33252
34294
|
});
|
|
33253
|
-
workflow.command("preview").description("\u51C6\u5907\u5E76\u6253\u5F00\u5F53\u524D\u6587\u7AE0\u7684\u5FAE\u4FE1\u9884\u89C8").
|
|
34295
|
+
workflow.command("preview").description("\u51C6\u5907\u5E76\u6253\u5F00\u5F53\u524D\u6587\u7AE0\u7684\u5FAE\u4FE1\u9884\u89C8").requiredOption("--work-item <id>", "\u5F53\u524D delivery \u5DE5\u4F5C\u9879 ID").option("--choice <id>", "\u516C\u4F17\u53F7\u5019\u9009 choiceId").option("--json", "\u8F93\u51FA JSON").action(
|
|
33254
34296
|
async (options) => deliveryAction(
|
|
33255
34297
|
options.json === true,
|
|
33256
34298
|
(delivery) => delivery.preview({
|
|
33257
|
-
...options.
|
|
33258
|
-
|
|
33259
|
-
...options.directory === void 0 ? {} : { directory: options.directory },
|
|
33260
|
-
...options.project === void 0 ? {} : { projectId: options.project }
|
|
34299
|
+
...options.choice === void 0 ? {} : { choiceId: options.choice },
|
|
34300
|
+
workItemId: options.workItem
|
|
33261
34301
|
})
|
|
33262
34302
|
)
|
|
33263
34303
|
);
|
|
33264
|
-
workflow.command("deliver").description("\u786E\u8BA4\u5F53\u524D\u9884\u89C8\u5E76\u521B\u5EFA\u5FAE\u4FE1\u516C\u4F17\u53F7\u8349\u7A3F").
|
|
34304
|
+
workflow.command("deliver").description("\u786E\u8BA4\u5F53\u524D\u9884\u89C8\u5E76\u521B\u5EFA\u5FAE\u4FE1\u516C\u4F17\u53F7\u8349\u7A3F").requiredOption("--work-item <id>", "\u6700\u7EC8\u9884\u89C8\u7ED1\u5B9A\u5DE5\u4F5C\u9879 ID").option("--confirm", "\u786E\u8BA4\u5DF2\u7ECF\u67E5\u770B\u9884\u89C8\u5E76\u521B\u5EFA\u8349\u7A3F").option("--json", "\u8F93\u51FA JSON").action(
|
|
33265
34305
|
async (options) => deliveryAction(
|
|
33266
34306
|
options.json === true,
|
|
33267
34307
|
(delivery) => delivery.deliver({
|
|
33268
34308
|
confirmed: options.confirm === true,
|
|
33269
|
-
|
|
33270
|
-
...options.project === void 0 ? {} : { projectId: options.project }
|
|
34309
|
+
workItemId: options.workItem
|
|
33271
34310
|
})
|
|
33272
34311
|
)
|
|
33273
34312
|
);
|
|
@@ -33301,45 +34340,54 @@ function createProgram(context) {
|
|
|
33301
34340
|
})
|
|
33302
34341
|
);
|
|
33303
34342
|
const profile = program2.command("profile").description("\u7BA1\u7406\u672C\u5730\u521B\u4F5C\u753B\u50CF");
|
|
33304
|
-
profile.command("
|
|
34343
|
+
profile.command("begin").description("\u5F00\u59CB\u753B\u50CF\u95EE\u7B54").option("--json", "\u8F93\u51FA JSON").action(
|
|
33305
34344
|
async (options) => runAction(
|
|
33306
34345
|
context,
|
|
33307
34346
|
options.json === true,
|
|
33308
34347
|
() => new ProfileCli({
|
|
33309
34348
|
currentDirectory: context.currentDirectory,
|
|
33310
34349
|
homeDirectory: context.homeDirectory
|
|
33311
|
-
}).
|
|
34350
|
+
}).begin()
|
|
33312
34351
|
)
|
|
33313
34352
|
);
|
|
33314
|
-
profile.command("
|
|
34353
|
+
profile.command("answer").description("\u56DE\u7B54\u5F53\u524D\u753B\u50CF\u95EE\u9898").requiredOption("--session <uuid>", "\u753B\u50CF\u4F1A\u8BDD ID").option("--choice <id>", "\u9009\u62E9\u9879 choiceId\uFF0C\u53EF\u91CD\u590D", collectValues, []).option("--text <value>", "\u6587\u672C\u7B54\u6848").option("--note <value>", "\u8865\u5145\u8BF4\u660E").option("--json", "\u8F93\u51FA JSON").action(
|
|
33315
34354
|
async (options) => runAction(
|
|
33316
34355
|
context,
|
|
33317
34356
|
options.json === true,
|
|
33318
34357
|
() => new ProfileCli({
|
|
33319
34358
|
currentDirectory: context.currentDirectory,
|
|
33320
34359
|
homeDirectory: context.homeDirectory
|
|
33321
|
-
}).
|
|
34360
|
+
}).answer(options.session, {
|
|
34361
|
+
choices: options.choice,
|
|
34362
|
+
...options.note === void 0 ? {} : { note: options.note },
|
|
34363
|
+
...options.text === void 0 ? {} : { text: options.text }
|
|
34364
|
+
})
|
|
33322
34365
|
)
|
|
33323
34366
|
);
|
|
33324
|
-
profile.command("
|
|
34367
|
+
profile.command("status").description("\u67E5\u770B\u521B\u4F5C\u753B\u50CF").option("--json", "\u8F93\u51FA JSON").action(
|
|
33325
34368
|
async (options) => runAction(
|
|
33326
34369
|
context,
|
|
33327
34370
|
options.json === true,
|
|
33328
34371
|
() => new ProfileCli({
|
|
33329
34372
|
currentDirectory: context.currentDirectory,
|
|
33330
34373
|
homeDirectory: context.homeDirectory
|
|
33331
|
-
}).
|
|
34374
|
+
}).status()
|
|
33332
34375
|
)
|
|
33333
34376
|
);
|
|
33334
34377
|
const memory = program2.command("memory").description("\u7BA1\u7406\u672C\u5730\u5185\u5BB9\u8BB0\u5FC6");
|
|
33335
|
-
memory.command("add").description("\u4FDD\u5B58\u4E00\u6761\u7528\u6237\u786E\u8BA4\u7684\u5185\u5BB9\u8BB0\u5FC6").requiredOption("--
|
|
34378
|
+
memory.command("add").description("\u4FDD\u5B58\u4E00\u6761\u7528\u6237\u786E\u8BA4\u7684\u5185\u5BB9\u8BB0\u5FC6").requiredOption("--content <text>", "\u8BB0\u5FC6\u6B63\u6587").requiredOption("--kind <kind>", "\u8BB0\u5FC6\u9886\u57DF\u7C7B\u578B").requiredOption("--scope <scope>", "global \u6216 project").option("--expires-at <datetime>", "\u8FC7\u671F\u65F6\u95F4").option("--json", "\u8F93\u51FA JSON").action(
|
|
33336
34379
|
async (options) => runAction(
|
|
33337
34380
|
context,
|
|
33338
34381
|
options.json === true,
|
|
33339
34382
|
() => new ContentMemoryCli({
|
|
33340
34383
|
currentDirectory: context.currentDirectory,
|
|
33341
34384
|
homeDirectory: context.homeDirectory
|
|
33342
|
-
}).add(
|
|
34385
|
+
}).add({
|
|
34386
|
+
content: options.content,
|
|
34387
|
+
...options.expiresAt === void 0 ? {} : { expiresAt: options.expiresAt },
|
|
34388
|
+
kind: options.kind,
|
|
34389
|
+
scope: options.scope
|
|
34390
|
+
})
|
|
33343
34391
|
)
|
|
33344
34392
|
);
|
|
33345
34393
|
memory.command("list").description("\u67E5\u770B\u5185\u5BB9\u8BB0\u5FC6").option("--json", "\u8F93\u51FA JSON").action(
|
|
@@ -33352,42 +34400,49 @@ function createProgram(context) {
|
|
|
33352
34400
|
}).list()
|
|
33353
34401
|
)
|
|
33354
34402
|
);
|
|
33355
|
-
memory.command("
|
|
33356
|
-
async (
|
|
34403
|
+
memory.command("correct").description("\u539F\u5B50\u66F4\u6B63\u4E00\u6761\u5185\u5BB9\u8BB0\u5FC6").requiredOption("--memory <uuid>", "\u88AB\u66F4\u6B63\u7684\u8BB0\u5FC6 ID").requiredOption("--content <text>", "\u66F4\u6B63\u540E\u7684\u6B63\u6587").requiredOption("--kind <kind>", "\u8BB0\u5FC6\u9886\u57DF\u7C7B\u578B").requiredOption("--scope <scope>", "global \u6216 project").option("--expires-at <datetime>", "\u8FC7\u671F\u65F6\u95F4").option("--json", "\u8F93\u51FA JSON").action(
|
|
34404
|
+
async (options) => runAction(
|
|
33357
34405
|
context,
|
|
33358
34406
|
options.json === true,
|
|
33359
34407
|
() => new ContentMemoryCli({
|
|
33360
34408
|
currentDirectory: context.currentDirectory,
|
|
33361
34409
|
homeDirectory: context.homeDirectory
|
|
33362
|
-
}).
|
|
34410
|
+
}).correct(options.memory, {
|
|
34411
|
+
content: options.content,
|
|
34412
|
+
...options.expiresAt === void 0 ? {} : { expiresAt: options.expiresAt },
|
|
34413
|
+
kind: options.kind,
|
|
34414
|
+
scope: options.scope
|
|
34415
|
+
})
|
|
33363
34416
|
)
|
|
33364
34417
|
);
|
|
33365
|
-
|
|
33366
|
-
|
|
33367
|
-
async (options) => withKnowledge(context, "knowledge.status", options.json === true, (cli) => cli.status())
|
|
33368
|
-
);
|
|
33369
|
-
knowledge.command("import").description("\u5BFC\u5165\u7528\u6237\u660E\u786E\u9009\u62E9\u7684\u6587\u7AE0").argument("<files...>", "Markdown \u6216\u6587\u672C\u6587\u4EF6").option("--lexical-only", "\u53EA\u5EFA\u7ACB\u5173\u952E\u8BCD\u7D22\u5F15").option("--json", "\u8F93\u51FA JSON").action(
|
|
33370
|
-
async (files, options) => withKnowledge(
|
|
34418
|
+
memory.command("archive").description("\u5F52\u6863\u4E00\u6761\u5185\u5BB9\u8BB0\u5FC6").requiredOption("--memory <uuid>", "\u8BB0\u5FC6 ID").option("--json", "\u8F93\u51FA JSON").action(
|
|
34419
|
+
async (options) => runAction(
|
|
33371
34420
|
context,
|
|
33372
|
-
"knowledge.import",
|
|
33373
34421
|
options.json === true,
|
|
33374
|
-
(
|
|
34422
|
+
() => new ContentMemoryCli({
|
|
34423
|
+
currentDirectory: context.currentDirectory,
|
|
34424
|
+
homeDirectory: context.homeDirectory
|
|
34425
|
+
}).archive(options.memory)
|
|
33375
34426
|
)
|
|
33376
34427
|
);
|
|
33377
|
-
knowledge.command("
|
|
34428
|
+
const knowledge = program2.command("knowledge").description("\u7BA1\u7406\u672C\u5730\u5386\u53F2\u6587\u7AE0\u548C\u91D1\u53E5");
|
|
34429
|
+
knowledge.command("status").description("\u67E5\u770B\u77E5\u8BC6\u5E93\u72B6\u6001").option("--json", "\u8F93\u51FA JSON").action(
|
|
34430
|
+
async (options) => withKnowledge(context, "knowledge.status", options.json === true, (cli) => cli.status())
|
|
34431
|
+
);
|
|
34432
|
+
knowledge.command("import").description("\u5BFC\u5165\u7528\u6237\u660E\u786E\u9009\u62E9\u7684\u6587\u7AE0").requiredOption("--source <path>", "\u7528\u6237\u660E\u786E\u9009\u62E9\u7684\u5355\u6587\u4EF6\u6216\u76EE\u5F55").option("--lexical-only", "\u53EA\u5EFA\u7ACB\u5173\u952E\u8BCD\u7D22\u5F15").option("--choice <id>", "\u6A21\u578B\u4E0D\u53EF\u7528\u65F6 CLI \u8FD4\u56DE\u7684 choiceId").option("--json", "\u8F93\u51FA JSON").action(
|
|
33378
34433
|
async (options) => withKnowledge(
|
|
33379
34434
|
context,
|
|
33380
34435
|
"knowledge.import",
|
|
33381
34436
|
options.json === true,
|
|
33382
|
-
(cli) => cli.
|
|
34437
|
+
(cli) => cli.importSource(options.source, options.lexicalOnly === true, options.choice)
|
|
33383
34438
|
)
|
|
33384
34439
|
);
|
|
33385
|
-
knowledge.command("search").description("\u68C0\u7D22\u5386\u53F2\u6587\u7AE0\u548C\u91D1\u53E5").argument("<query>", "\u68C0\u7D22\u76EE\u6807").option("--mode <mode>", "hybrid / lexical / semantic", "hybrid").option("--limit <count>", "\u6700\u591A\u8FD4\u56DE\u6761\u6570", "8").option("--json", "\u8F93\u51FA JSON").action(
|
|
34440
|
+
knowledge.command("search").description("\u68C0\u7D22\u5386\u53F2\u6587\u7AE0\u548C\u91D1\u53E5").argument("<query>", "\u68C0\u7D22\u76EE\u6807").option("--mode <mode>", "hybrid / lexical / semantic", "hybrid").option("--limit <count>", "\u6700\u591A\u8FD4\u56DE\u6761\u6570", "8").option("--choice <id>", "\u6A21\u578B\u4E0D\u53EF\u7528\u65F6 CLI \u8FD4\u56DE\u7684 choiceId").option("--json", "\u8F93\u51FA JSON").action(
|
|
33386
34441
|
async (query, options) => withKnowledge(
|
|
33387
34442
|
context,
|
|
33388
34443
|
"knowledge.search",
|
|
33389
34444
|
options.json === true,
|
|
33390
|
-
(cli) => cli.search(query, options.mode, positiveInteger(options.limit, "limit"))
|
|
34445
|
+
(cli) => cli.search(query, options.mode, positiveInteger(options.limit, "limit"), options.choice)
|
|
33391
34446
|
)
|
|
33392
34447
|
);
|
|
33393
34448
|
knowledge.command("remove").description("\u5220\u9664\u4E00\u7BC7\u672C\u5730\u5386\u53F2\u6587\u7AE0").argument("<article-id>", "\u6587\u7AE0 ID").option("--json", "\u8F93\u51FA JSON").action(
|
|
@@ -33399,14 +34454,6 @@ function createProgram(context) {
|
|
|
33399
34454
|
)
|
|
33400
34455
|
);
|
|
33401
34456
|
const quotes = knowledge.command("quotes").description("\u7BA1\u7406\u672C\u5730\u91D1\u53E5");
|
|
33402
|
-
quotes.command("init").description("\u521D\u59CB\u5316\u91D1\u53E5\u5E93").option("--json", "\u8F93\u51FA JSON").action(
|
|
33403
|
-
async (options) => withKnowledge(
|
|
33404
|
-
context,
|
|
33405
|
-
"knowledge.quotes.init",
|
|
33406
|
-
options.json === true,
|
|
33407
|
-
(cli) => cli.initQuotes()
|
|
33408
|
-
)
|
|
33409
|
-
);
|
|
33410
34457
|
quotes.command("status").description("\u67E5\u770B\u91D1\u53E5\u5E93\u72B6\u6001").option("--json", "\u8F93\u51FA JSON").action(
|
|
33411
34458
|
async (options) => withKnowledge(
|
|
33412
34459
|
context,
|
|
@@ -33461,14 +34508,6 @@ function createProgram(context) {
|
|
|
33461
34508
|
(cli) => cli.archiveQuote(quoteId)
|
|
33462
34509
|
)
|
|
33463
34510
|
);
|
|
33464
|
-
quotes.command("sync").description("\u540C\u6B65\u91D1\u53E5\u5E93\u7D22\u5F15").option("--lexical-only", "\u53EA\u5EFA\u7ACB\u5173\u952E\u8BCD\u7D22\u5F15").option("--json", "\u8F93\u51FA JSON").action(
|
|
33465
|
-
async (options) => withKnowledge(
|
|
33466
|
-
context,
|
|
33467
|
-
"knowledge.quotes.sync",
|
|
33468
|
-
options.json === true,
|
|
33469
|
-
(cli) => cli.syncQuotes(options.lexicalOnly === true)
|
|
33470
|
-
)
|
|
33471
|
-
);
|
|
33472
34511
|
const auth = program2.command("auth").description("\u7BA1\u7406\u5F53\u524D\u8BBE\u5907\u767B\u5F55");
|
|
33473
34512
|
const authAction = (options, action) => runAction(
|
|
33474
34513
|
context,
|