@deployxai/dxc 0.2.6 → 0.3.1
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-7G7C3AZW.js → chunk-6JNQZHAQ.js} +209 -56
- package/dist/chunks/{knowledge-LSRBVSCZ.js → knowledge-JCYMCMSP.js} +140 -65
- package/dist/index.js +1904 -965
- package/package.json +1 -1
- package/skills/dxc-article-outline/SKILL.md +8 -19
- package/skills/dxc-article-outline/references/outline-methods.md +17 -48
- package/skills/dxc-article-write/SKILL.md +8 -34
- package/skills/dxc-article-write/references/writing-methods.md +26 -46
- package/skills/dxc-content-brief/SKILL.md +9 -25
- package/skills/dxc-content-brief/references/brief-method.md +15 -43
- package/skills/dxc-content-review/SKILL.md +8 -29
- package/skills/dxc-content-review/references/review-checklist.md +15 -38
- 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 +9 -33
- package/skills/dxc-research/references/research-method.md +20 -66
- package/skills/dxc-title-write/SKILL.md +9 -26
- package/skills/dxc-title-write/references/title-methods.md +15 -36
- package/skills/dxc-visual-plan/SKILL.md +18 -36
- package/skills/dxc-visual-plan/references/visual-methods.md +19 -45
- 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,
|
|
@@ -53,7 +52,7 @@ import {
|
|
|
53
52
|
wechatRenderResultSchema,
|
|
54
53
|
writePrivateBuffer,
|
|
55
54
|
writePrivateJson
|
|
56
|
-
} from "./chunks/chunk-
|
|
55
|
+
} from "./chunks/chunk-6JNQZHAQ.js";
|
|
57
56
|
|
|
58
57
|
// node_modules/.pnpm/pino-std-serializers@7.1.0/node_modules/pino-std-serializers/lib/err-helpers.js
|
|
59
58
|
var require_err_helpers = __commonJS({
|
|
@@ -1307,7 +1306,7 @@ var require_sonic_boom = __commonJS({
|
|
|
1307
1306
|
if (!(this instanceof SonicBoom)) {
|
|
1308
1307
|
return new SonicBoom(opts);
|
|
1309
1308
|
}
|
|
1310
|
-
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 || {};
|
|
1311
1310
|
fd = fd || dest;
|
|
1312
1311
|
this._len = 0;
|
|
1313
1312
|
this.fd = -1;
|
|
@@ -1332,7 +1331,7 @@ var require_sonic_boom = __commonJS({
|
|
|
1332
1331
|
this.append = append2 || false;
|
|
1333
1332
|
this.mode = mode;
|
|
1334
1333
|
this.retryEAGAIN = retryEAGAIN || (() => true);
|
|
1335
|
-
this.mkdir =
|
|
1334
|
+
this.mkdir = mkdir6 || false;
|
|
1336
1335
|
let fsWriteSync;
|
|
1337
1336
|
let fsWrite;
|
|
1338
1337
|
if (contentMode === kContentModeBuffer) {
|
|
@@ -23267,7 +23266,7 @@ import os3 from "node:os";
|
|
|
23267
23266
|
// apps/cli/package.json
|
|
23268
23267
|
var package_default = {
|
|
23269
23268
|
name: "@dxc/cli",
|
|
23270
|
-
version: "0.
|
|
23269
|
+
version: "0.3.1",
|
|
23271
23270
|
private: true,
|
|
23272
23271
|
type: "module",
|
|
23273
23272
|
bin: {
|
|
@@ -26712,13 +26711,78 @@ async function runDoctor(runtime) {
|
|
|
26712
26711
|
|
|
26713
26712
|
// apps/cli/src/profile.ts
|
|
26714
26713
|
import { randomUUID } from "node:crypto";
|
|
26715
|
-
import {
|
|
26714
|
+
import { unlink } from "node:fs/promises";
|
|
26716
26715
|
import path2 from "node:path";
|
|
26717
26716
|
var PROFILE_DISPLAY_PATH = "~/.dxc/content-profile.json";
|
|
26718
26717
|
var MEMORY_DISPLAY_PATH = "~/.dxc/content-memory.json";
|
|
26719
26718
|
var USER_MEMORY_DISPLAY_PATH = "~/.dxc/USER.md";
|
|
26720
26719
|
var PROFILE_MAXIMUM_BYTES = 64 * 1024;
|
|
26721
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
|
+
];
|
|
26722
26786
|
var ProfileCliError = class extends Error {
|
|
26723
26787
|
constructor(code, message, hint, fields) {
|
|
26724
26788
|
super(message);
|
|
@@ -26748,6 +26812,23 @@ function userMemoryPath(homeDirectory) {
|
|
|
26748
26812
|
function memoryPath(homeDirectory) {
|
|
26749
26813
|
return path2.join(homeDirectory, ".dxc", "content-memory.json");
|
|
26750
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
|
+
}
|
|
26751
26832
|
function singleLine(value) {
|
|
26752
26833
|
return value.replace(/[\r\n]+/gu, " ").replace(/\s+/gu, " ").trim();
|
|
26753
26834
|
}
|
|
@@ -26907,149 +26988,133 @@ async function refreshUserMemory(homeDirectory, user, now) {
|
|
|
26907
26988
|
Buffer.from(renderUserMemory(user, memory.memories))
|
|
26908
26989
|
);
|
|
26909
26990
|
}
|
|
26910
|
-
async function readProfileInput(currentDirectory, homeDirectory, inputPath) {
|
|
26911
|
-
try {
|
|
26912
|
-
const target = resolveUserPath({ currentDirectory, homeDirectory, input: inputPath });
|
|
26913
|
-
const metadata = await stat(target);
|
|
26914
|
-
if (!metadata.isFile() || metadata.size > PROFILE_MAXIMUM_BYTES) {
|
|
26915
|
-
throw new ProfileCliError("DXC_PROFILE_INPUT_INVALID", "Profile input is invalid");
|
|
26916
|
-
}
|
|
26917
|
-
return parseJson(
|
|
26918
|
-
await readFile(target, "utf8"),
|
|
26919
|
-
"DXC_PROFILE_INPUT_INVALID",
|
|
26920
|
-
"Profile input is invalid"
|
|
26921
|
-
);
|
|
26922
|
-
} catch (error) {
|
|
26923
|
-
if (error instanceof ProfileCliError) {
|
|
26924
|
-
throw error;
|
|
26925
|
-
}
|
|
26926
|
-
throw new ProfileCliError(
|
|
26927
|
-
"DXC_PROFILE_INPUT_INVALID",
|
|
26928
|
-
"\u753B\u50CF\u8F93\u5165\u6587\u4EF6\u65E0\u6CD5\u8BFB\u53D6\u6216\u4E0D\u662F\u6709\u6548 JSON\u3002",
|
|
26929
|
-
"\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"
|
|
26930
|
-
);
|
|
26931
|
-
}
|
|
26932
|
-
}
|
|
26933
|
-
function issueFields(issues) {
|
|
26934
|
-
return [
|
|
26935
|
-
...new Set(
|
|
26936
|
-
issues.map((issue) => issue.path.map(String).join(".")).filter((field) => field.length > 0)
|
|
26937
|
-
)
|
|
26938
|
-
];
|
|
26939
|
-
}
|
|
26940
|
-
async function readProfileForSave(target, timestamp) {
|
|
26941
|
-
try {
|
|
26942
|
-
return await readProfile(target);
|
|
26943
|
-
} catch (error) {
|
|
26944
|
-
if (!(error instanceof ProfileCliError) || error.code !== "DXC_PROFILE_INVALID") {
|
|
26945
|
-
throw error;
|
|
26946
|
-
}
|
|
26947
|
-
try {
|
|
26948
|
-
const metadata = await lstat(target);
|
|
26949
|
-
if (!metadata.isFile() || metadata.isSymbolicLink()) {
|
|
26950
|
-
throw error;
|
|
26951
|
-
}
|
|
26952
|
-
const suffix = timestamp.replaceAll(":", "-");
|
|
26953
|
-
await rename(target, `${target}.invalid-${suffix}.bak`);
|
|
26954
|
-
return void 0;
|
|
26955
|
-
} catch (recoveryError) {
|
|
26956
|
-
if (recoveryError === error) {
|
|
26957
|
-
throw error;
|
|
26958
|
-
}
|
|
26959
|
-
throw new ProfileCliError(
|
|
26960
|
-
"DXC_PROFILE_INVALID",
|
|
26961
|
-
"\u53D1\u73B0\u65E0\u6548\u7684\u65E7\u753B\u50CF\uFF0C\u4F46\u65E0\u6CD5\u5B89\u5168\u5907\u4EFD\u5E76\u6062\u590D\u3002",
|
|
26962
|
-
"\u8BF7\u8BA9 DxC \u5DE5\u4F5C\u6D41\u91CD\u8BD5\uFF1B\u4E0D\u8981\u624B\u52A8\u5220\u9664 ~/.dxc \u4E2D\u7684\u6587\u4EF6\u3002"
|
|
26963
|
-
);
|
|
26964
|
-
}
|
|
26965
|
-
}
|
|
26966
|
-
}
|
|
26967
26991
|
var ProfileCli = class {
|
|
26968
|
-
#currentDirectory;
|
|
26969
26992
|
#homeDirectory;
|
|
26970
26993
|
#now;
|
|
26971
26994
|
#randomUUID;
|
|
26972
26995
|
constructor(dependencies) {
|
|
26973
|
-
this.#currentDirectory = dependencies.currentDirectory;
|
|
26974
26996
|
this.#homeDirectory = dependencies.homeDirectory;
|
|
26975
26997
|
this.#now = dependencies.now ?? (() => /* @__PURE__ */ new Date());
|
|
26976
26998
|
this.#randomUUID = dependencies.randomUUID ?? randomUUID;
|
|
26977
26999
|
}
|
|
26978
|
-
async
|
|
26979
|
-
const
|
|
26980
|
-
|
|
26981
|
-
|
|
26982
|
-
|
|
26983
|
-
|
|
26984
|
-
|
|
26985
|
-
|
|
26986
|
-
|
|
26987
|
-
|
|
26988
|
-
|
|
26989
|
-
|
|
26990
|
-
|
|
26991
|
-
const target = profilePath(this.#homeDirectory);
|
|
26992
|
-
const timestamp = this.#now().toISOString();
|
|
26993
|
-
const existing = await readProfileForSave(target, timestamp);
|
|
26994
|
-
const profile = contentProfileSchema.parse({
|
|
26995
|
-
...input.data,
|
|
26996
|
-
createdAt: existing?.createdAt ?? timestamp,
|
|
26997
|
-
profileId: existing?.profileId ?? this.#randomUUID(),
|
|
26998
|
-
schemaVersion: "1",
|
|
26999
|
-
updatedAt: timestamp
|
|
27000
|
-
});
|
|
27001
|
-
try {
|
|
27002
|
-
await writePrivateJson(target, profile);
|
|
27003
|
-
await refreshUserMemory(this.#homeDirectory, profile.user, this.#now());
|
|
27004
|
-
} catch {
|
|
27005
|
-
throw new ProfileCliError("DXC_PROFILE_IO_FAILED", "Unable to save local content profile");
|
|
27006
|
-
}
|
|
27007
|
-
return contentProfileSaveResultSchema.parse({
|
|
27008
|
-
command: "profile.save",
|
|
27009
|
-
data: {
|
|
27010
|
-
profile,
|
|
27011
|
-
profilePath: PROFILE_DISPLAY_PATH,
|
|
27012
|
-
userMemoryPath: USER_MEMORY_DISPLAY_PATH
|
|
27013
|
-
},
|
|
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" },
|
|
27014
27013
|
ok: true
|
|
27015
27014
|
});
|
|
27016
27015
|
}
|
|
27017
|
-
async
|
|
27018
|
-
const
|
|
27019
|
-
|
|
27020
|
-
|
|
27021
|
-
|
|
27022
|
-
|
|
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");
|
|
27023
27033
|
}
|
|
27024
|
-
const
|
|
27025
|
-
|
|
27026
|
-
|
|
27027
|
-
throw new ProfileCliError("DXC_PROFILE_INVALID", "Content profile is not initialized");
|
|
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");
|
|
27028
27037
|
}
|
|
27029
|
-
const
|
|
27030
|
-
|
|
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
|
+
});
|
|
27067
|
+
}
|
|
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")
|
|
27031
27079
|
);
|
|
27032
|
-
|
|
27033
|
-
|
|
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");
|
|
27034
27096
|
}
|
|
27035
27097
|
const timestamp = this.#now().toISOString();
|
|
27036
27098
|
const profile = contentProfileSchema.parse({
|
|
27037
|
-
...
|
|
27038
|
-
|
|
27039
|
-
|
|
27099
|
+
...parsedInput.data,
|
|
27100
|
+
createdAt: existing?.createdAt ?? timestamp,
|
|
27101
|
+
profileId: existing?.profileId ?? this.#randomUUID(),
|
|
27102
|
+
schemaVersion: "1",
|
|
27040
27103
|
updatedAt: timestamp
|
|
27041
27104
|
});
|
|
27042
27105
|
try {
|
|
27043
|
-
await writePrivateJson(
|
|
27106
|
+
await writePrivateJson(profilePath(this.#homeDirectory), profile);
|
|
27044
27107
|
await refreshUserMemory(this.#homeDirectory, profile.user, this.#now());
|
|
27108
|
+
await unlink(target);
|
|
27045
27109
|
} catch {
|
|
27046
|
-
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");
|
|
27047
27111
|
}
|
|
27048
|
-
return
|
|
27049
|
-
command: "profile.
|
|
27112
|
+
return contentProfileSessionResultSchema.parse({
|
|
27113
|
+
command: "profile.answer",
|
|
27050
27114
|
data: {
|
|
27051
27115
|
profile,
|
|
27052
27116
|
profilePath: PROFILE_DISPLAY_PATH,
|
|
27117
|
+
status: "completed",
|
|
27053
27118
|
userMemoryPath: USER_MEMORY_DISPLAY_PATH
|
|
27054
27119
|
},
|
|
27055
27120
|
ok: true
|
|
@@ -27074,20 +27139,16 @@ var ProfileCli = class {
|
|
|
27074
27139
|
}
|
|
27075
27140
|
};
|
|
27076
27141
|
var ContentMemoryCli = class {
|
|
27077
|
-
#currentDirectory;
|
|
27078
27142
|
#homeDirectory;
|
|
27079
27143
|
#now;
|
|
27080
27144
|
#randomUUID;
|
|
27081
27145
|
constructor(dependencies) {
|
|
27082
|
-
this.#currentDirectory = dependencies.currentDirectory;
|
|
27083
27146
|
this.#homeDirectory = dependencies.homeDirectory;
|
|
27084
27147
|
this.#now = dependencies.now ?? (() => /* @__PURE__ */ new Date());
|
|
27085
27148
|
this.#randomUUID = dependencies.randomUUID ?? randomUUID;
|
|
27086
27149
|
}
|
|
27087
|
-
async add(
|
|
27088
|
-
const input = contentMemoryInputSchema.safeParse(
|
|
27089
|
-
await readProfileInput(this.#currentDirectory, this.#homeDirectory, inputPath)
|
|
27090
|
-
);
|
|
27150
|
+
async add(inputValue) {
|
|
27151
|
+
const input = contentMemoryInputSchema.safeParse(inputValue);
|
|
27091
27152
|
if (!input.success) {
|
|
27092
27153
|
throw new ContentMemoryCliError(
|
|
27093
27154
|
"DXC_MEMORY_INPUT_INVALID",
|
|
@@ -27182,11 +27243,73 @@ var ContentMemoryCli = class {
|
|
|
27182
27243
|
ok: true
|
|
27183
27244
|
});
|
|
27184
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
|
+
}
|
|
27185
27308
|
};
|
|
27186
27309
|
|
|
27187
27310
|
// apps/cli/src/project.ts
|
|
27188
27311
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
27189
|
-
import { lstat
|
|
27312
|
+
import { lstat, mkdir } from "node:fs/promises";
|
|
27190
27313
|
import path3 from "node:path";
|
|
27191
27314
|
var MANIFEST_NAME = "dxc.project.json";
|
|
27192
27315
|
var MANIFEST_MAXIMUM_BYTES = 32 * 1024;
|
|
@@ -27292,7 +27415,7 @@ var ProjectCli = class {
|
|
|
27292
27415
|
});
|
|
27293
27416
|
const manifestTarget = path3.join(directory, MANIFEST_NAME);
|
|
27294
27417
|
try {
|
|
27295
|
-
await
|
|
27418
|
+
await lstat(manifestTarget);
|
|
27296
27419
|
throw new ProjectCliError("DXC_PROJECT_EXISTS", "\u8BE5\u76EE\u5F55\u5DF2\u7ECF\u662F DxC \u5185\u5BB9\u9879\u76EE\u3002");
|
|
27297
27420
|
} catch (error) {
|
|
27298
27421
|
if (error instanceof ProjectCliError) {
|
|
@@ -27428,7 +27551,17 @@ var ProjectCli = class {
|
|
|
27428
27551
|
};
|
|
27429
27552
|
|
|
27430
27553
|
// apps/cli/src/skills.ts
|
|
27431
|
-
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";
|
|
27432
27565
|
import os from "node:os";
|
|
27433
27566
|
import path4 from "node:path";
|
|
27434
27567
|
import { fileURLToPath } from "node:url";
|
|
@@ -27458,7 +27591,7 @@ var SkillInstallerError = class extends Error {
|
|
|
27458
27591
|
};
|
|
27459
27592
|
async function isDirectory(directory) {
|
|
27460
27593
|
try {
|
|
27461
|
-
return (await
|
|
27594
|
+
return (await lstat2(directory)).isDirectory();
|
|
27462
27595
|
} catch {
|
|
27463
27596
|
return false;
|
|
27464
27597
|
}
|
|
@@ -27482,7 +27615,7 @@ async function findBundledSkills() {
|
|
|
27482
27615
|
async function assertRegularSkillTree(directory) {
|
|
27483
27616
|
for (const entry of await readdir(directory, { withFileTypes: true })) {
|
|
27484
27617
|
const entryPath = path4.join(directory, entry.name);
|
|
27485
|
-
const entryStat = await
|
|
27618
|
+
const entryStat = await lstat2(entryPath);
|
|
27486
27619
|
if (entryStat.isSymbolicLink()) {
|
|
27487
27620
|
throw new SkillInstallerError(
|
|
27488
27621
|
"DXC_SKILL_SOURCE_UNSAFE",
|
|
@@ -27501,6 +27634,26 @@ async function assertRegularSkillTree(directory) {
|
|
|
27501
27634
|
}
|
|
27502
27635
|
}
|
|
27503
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
|
+
}
|
|
27504
27657
|
function defaultTargetDirectory(homeDirectory, target) {
|
|
27505
27658
|
return path4.join(homeDirectory, target === "codex" ? ".codex" : ".workbuddy", "skills");
|
|
27506
27659
|
}
|
|
@@ -27543,10 +27696,11 @@ var SkillInstaller = class {
|
|
|
27543
27696
|
errorOnExist: true,
|
|
27544
27697
|
recursive: true
|
|
27545
27698
|
});
|
|
27699
|
+
await renderCliInvocation(sourceRoot, stagedSkill);
|
|
27546
27700
|
if (destinationExists) {
|
|
27547
|
-
await
|
|
27701
|
+
await rename(destination, backup);
|
|
27548
27702
|
}
|
|
27549
|
-
await
|
|
27703
|
+
await rename(stagedSkill, destination);
|
|
27550
27704
|
installed.push(skill);
|
|
27551
27705
|
if (destinationExists) {
|
|
27552
27706
|
try {
|
|
@@ -27557,7 +27711,7 @@ var SkillInstaller = class {
|
|
|
27557
27711
|
}
|
|
27558
27712
|
} catch (error) {
|
|
27559
27713
|
if (!await isDirectory(destination) && await isDirectory(backup)) {
|
|
27560
|
-
await
|
|
27714
|
+
await rename(backup, destination);
|
|
27561
27715
|
}
|
|
27562
27716
|
throw error;
|
|
27563
27717
|
} finally {
|
|
@@ -27588,7 +27742,7 @@ import {
|
|
|
27588
27742
|
randomUUID as randomUUID4
|
|
27589
27743
|
} from "node:crypto";
|
|
27590
27744
|
import { constants as fileConstants3 } from "node:fs";
|
|
27591
|
-
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";
|
|
27592
27746
|
import os2 from "node:os";
|
|
27593
27747
|
import path7 from "node:path";
|
|
27594
27748
|
|
|
@@ -27736,10 +27890,10 @@ var LOG_REDACTION_PATHS = Object.freeze([
|
|
|
27736
27890
|
]);
|
|
27737
27891
|
|
|
27738
27892
|
// apps/cli/src/publishing-assets.ts
|
|
27739
|
-
import { createHash as
|
|
27740
|
-
import { constants as
|
|
27741
|
-
import { lstat as lstat4, open, readdir as readdir2, realpath } from "node:fs/promises";
|
|
27742
|
-
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";
|
|
27743
27897
|
|
|
27744
27898
|
// packages/renderer-wechat/src/article.ts
|
|
27745
27899
|
import { createHash as createHash2 } from "node:crypto";
|
|
@@ -29861,7 +30015,24 @@ function rewriteWechatAssetSources(html, replacements) {
|
|
|
29861
30015
|
}
|
|
29862
30016
|
|
|
29863
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
|
|
29864
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";
|
|
29865
30036
|
import sharp from "sharp";
|
|
29866
30037
|
|
|
29867
30038
|
// apps/cli/src/wechat-error.ts
|
|
@@ -29880,47 +30051,402 @@ var WechatCliError = class extends Error {
|
|
|
29880
30051
|
fields;
|
|
29881
30052
|
};
|
|
29882
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
|
+
|
|
29883
30403
|
// apps/cli/src/publishing-assets.ts
|
|
29884
30404
|
var MAXIMUM_ARTICLE_BYTES = 512 * 1024;
|
|
29885
|
-
var
|
|
29886
|
-
var
|
|
29887
|
-
var
|
|
29888
|
-
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;
|
|
29889
30412
|
var SUPPORTED_IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([".jpeg", ".jpg", ".png"]);
|
|
29890
|
-
var
|
|
30413
|
+
var VISUAL_PLAN_MAXIMUM_BYTES2 = 128 * 1024;
|
|
29891
30414
|
var ARTICLE_FRONTMATTER = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)([\s\S]*)$/u;
|
|
29892
|
-
var
|
|
30415
|
+
var VISUAL_PLAN_FRONTMATTER2 = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/u;
|
|
29893
30416
|
var LOCAL_WORKFLOW_FRONTMATTER_KEYS = ["dxc", "goldenLinesPath", "goldenLinesSha256"];
|
|
29894
|
-
|
|
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) {
|
|
29895
30421
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
29896
30422
|
}
|
|
29897
30423
|
async function validatePublishingImage(bytes, target) {
|
|
29898
30424
|
let metadata;
|
|
29899
30425
|
try {
|
|
29900
|
-
metadata = await
|
|
30426
|
+
metadata = await sharp2(bytes, { failOn: "error", limitInputPixels: 8e7 }).metadata();
|
|
29901
30427
|
} catch {
|
|
29902
30428
|
throw new WechatCliError(
|
|
29903
30429
|
"DXC_PUBLISHING_INPUT_INVALID",
|
|
29904
|
-
`\u56FE\u7247 ${
|
|
30430
|
+
`\u56FE\u7247 ${path6.basename(target)} \u65E0\u6CD5\u88AB\u5B89\u5168\u89E3\u7801\uFF1B\u4EC5\u652F\u6301\u6709\u6548 PNG/JPEG\u3002`
|
|
29905
30431
|
);
|
|
29906
30432
|
}
|
|
29907
|
-
const extension =
|
|
30433
|
+
const extension = path6.extname(target).toLowerCase();
|
|
29908
30434
|
const expectedFormat = extension === ".png" ? "png" : extension === ".jpg" || extension === ".jpeg" ? "jpeg" : void 0;
|
|
29909
30435
|
if (expectedFormat === void 0 || metadata.format !== expectedFormat || metadata.width === void 0 || metadata.height === void 0) {
|
|
29910
30436
|
throw new WechatCliError(
|
|
29911
30437
|
"DXC_PUBLISHING_INPUT_INVALID",
|
|
29912
|
-
`\u56FE\u7247 ${
|
|
30438
|
+
`\u56FE\u7247 ${path6.basename(target)} \u7684\u6269\u5C55\u540D\u4E0E\u771F\u5B9E PNG/JPEG \u683C\u5F0F\u4E0D\u4E00\u81F4\u3002`
|
|
29913
30439
|
);
|
|
29914
30440
|
}
|
|
29915
30441
|
}
|
|
29916
30442
|
async function readPublishingInput(inputPath, maximumBytes, role = "article") {
|
|
29917
|
-
const target =
|
|
30443
|
+
const target = path6.resolve(inputPath);
|
|
29918
30444
|
let handle;
|
|
29919
30445
|
try {
|
|
29920
|
-
handle = await
|
|
30446
|
+
handle = await open2(target, fileConstants2.O_RDONLY | fileConstants2.O_NOFOLLOW);
|
|
29921
30447
|
const metadata = await handle.stat();
|
|
29922
30448
|
if (metadata.isFile() && metadata.size > maximumBytes) {
|
|
29923
|
-
const fileName =
|
|
30449
|
+
const fileName = path6.basename(target);
|
|
29924
30450
|
if (role === "inline-image") {
|
|
29925
30451
|
throw new WechatCliError(
|
|
29926
30452
|
"DXC_PUBLISHING_INLINE_IMAGE_TOO_LARGE",
|
|
@@ -29941,7 +30467,7 @@ async function readPublishingInput(inputPath, maximumBytes, role = "article") {
|
|
|
29941
30467
|
if (!metadata.isFile() || metadata.size <= 0) {
|
|
29942
30468
|
throw new WechatCliError(
|
|
29943
30469
|
"DXC_PUBLISHING_INPUT_INVALID",
|
|
29944
|
-
`\u6587\u4EF6 ${
|
|
30470
|
+
`\u6587\u4EF6 ${path6.basename(target)} \u4E0D\u662F\u53EF\u8BFB\u53D6\u7684\u975E\u7A7A\u666E\u901A\u6587\u4EF6\u3002`
|
|
29945
30471
|
);
|
|
29946
30472
|
}
|
|
29947
30473
|
const bytes = await handle.readFile();
|
|
@@ -29955,7 +30481,7 @@ async function readPublishingInput(inputPath, maximumBytes, role = "article") {
|
|
|
29955
30481
|
}
|
|
29956
30482
|
throw new WechatCliError(
|
|
29957
30483
|
"DXC_PUBLISHING_INPUT_INVALID",
|
|
29958
|
-
`\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`
|
|
29959
30485
|
);
|
|
29960
30486
|
} finally {
|
|
29961
30487
|
await handle?.close();
|
|
@@ -29964,16 +30490,16 @@ async function readPublishingInput(inputPath, maximumBytes, role = "article") {
|
|
|
29964
30490
|
async function readContainedPublishingInput(inputPath, maximumBytes, allowedDirectories, role) {
|
|
29965
30491
|
try {
|
|
29966
30492
|
const [target, ...directories] = await Promise.all([
|
|
29967
|
-
|
|
29968
|
-
...allowedDirectories.map((directory) =>
|
|
30493
|
+
realpath2(path6.resolve(inputPath)),
|
|
30494
|
+
...allowedDirectories.map((directory) => realpath2(path6.resolve(directory)))
|
|
29969
30495
|
]);
|
|
29970
30496
|
const contained = directories.some(
|
|
29971
|
-
(directory) => target !== directory && target.startsWith(`${directory}${
|
|
30497
|
+
(directory) => target !== directory && target.startsWith(`${directory}${path6.sep}`)
|
|
29972
30498
|
);
|
|
29973
30499
|
if (!contained) {
|
|
29974
30500
|
throw new WechatCliError(
|
|
29975
30501
|
"DXC_PUBLISHING_INPUT_INVALID",
|
|
29976
|
-
`\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`
|
|
29977
30503
|
);
|
|
29978
30504
|
}
|
|
29979
30505
|
} catch (error) {
|
|
@@ -29982,13 +30508,13 @@ async function readContainedPublishingInput(inputPath, maximumBytes, allowedDire
|
|
|
29982
30508
|
}
|
|
29983
30509
|
throw new WechatCliError(
|
|
29984
30510
|
"DXC_PUBLISHING_INPUT_INVALID",
|
|
29985
|
-
`\u65E0\u6CD5\u5B89\u5168\u89E3\u6790\u7D20\u6750 ${
|
|
30511
|
+
`\u65E0\u6CD5\u5B89\u5168\u89E3\u6790\u7D20\u6750 ${path6.basename(inputPath)}\u3002`
|
|
29986
30512
|
);
|
|
29987
30513
|
}
|
|
29988
30514
|
return readPublishingInput(inputPath, maximumBytes, role);
|
|
29989
30515
|
}
|
|
29990
30516
|
function publishingImageMediaType(inputPath) {
|
|
29991
|
-
const extension =
|
|
30517
|
+
const extension = path6.extname(inputPath).toLowerCase();
|
|
29992
30518
|
if (extension === ".png") {
|
|
29993
30519
|
return "image/png";
|
|
29994
30520
|
}
|
|
@@ -30001,13 +30527,13 @@ function safeFileName(value) {
|
|
|
30001
30527
|
return value.normalize("NFKC").replaceAll(/[^A-Za-z0-9._-]+/gu, "-").replaceAll(/^-+|-+$/gu, "").slice(0, 80);
|
|
30002
30528
|
}
|
|
30003
30529
|
function isWithinDirectory(target, directory) {
|
|
30004
|
-
const relative =
|
|
30005
|
-
return relative === "" || !relative.startsWith(`..${
|
|
30530
|
+
const relative = path6.relative(directory, target);
|
|
30531
|
+
return relative === "" || !relative.startsWith(`..${path6.sep}`) && relative !== "..";
|
|
30006
30532
|
}
|
|
30007
30533
|
function commonDirectory(left, right) {
|
|
30008
|
-
let directory =
|
|
30534
|
+
let directory = path6.resolve(left);
|
|
30009
30535
|
while (!isWithinDirectory(right, directory)) {
|
|
30010
|
-
const parent =
|
|
30536
|
+
const parent = path6.dirname(directory);
|
|
30011
30537
|
if (parent === directory) {
|
|
30012
30538
|
return directory;
|
|
30013
30539
|
}
|
|
@@ -30019,7 +30545,7 @@ async function collectedImages(directoryInput, articleDirectory) {
|
|
|
30019
30545
|
if (directoryInput === void 0) {
|
|
30020
30546
|
return [];
|
|
30021
30547
|
}
|
|
30022
|
-
const directory =
|
|
30548
|
+
const directory = path6.resolve(directoryInput);
|
|
30023
30549
|
let entries;
|
|
30024
30550
|
try {
|
|
30025
30551
|
const metadata = await lstat4(directory);
|
|
@@ -30031,12 +30557,12 @@ async function collectedImages(directoryInput, articleDirectory) {
|
|
|
30031
30557
|
}
|
|
30032
30558
|
const sharedDirectory = commonDirectory(articleDirectory, directory);
|
|
30033
30559
|
const [resolvedDirectory, resolvedSharedDirectory] = await Promise.all([
|
|
30034
|
-
|
|
30035
|
-
|
|
30560
|
+
realpath2(directory),
|
|
30561
|
+
realpath2(sharedDirectory)
|
|
30036
30562
|
]);
|
|
30037
|
-
const expectedDirectory =
|
|
30563
|
+
const expectedDirectory = path6.resolve(
|
|
30038
30564
|
resolvedSharedDirectory,
|
|
30039
|
-
|
|
30565
|
+
path6.relative(sharedDirectory, directory)
|
|
30040
30566
|
);
|
|
30041
30567
|
if (resolvedDirectory !== expectedDirectory) {
|
|
30042
30568
|
throw new WechatCliError(
|
|
@@ -30052,8 +30578,8 @@ async function collectedImages(directoryInput, articleDirectory) {
|
|
|
30052
30578
|
throw new WechatCliError("DXC_PUBLISHING_ASSETS_DIRECTORY_INVALID");
|
|
30053
30579
|
}
|
|
30054
30580
|
return entries.filter(
|
|
30055
|
-
(entry) => entry.isFile() && SUPPORTED_IMAGE_EXTENSIONS.has(
|
|
30056
|
-
).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"));
|
|
30057
30583
|
}
|
|
30058
30584
|
function injectCollectedImages(source, images) {
|
|
30059
30585
|
const diagnosticText = (value, maximum = 120) => {
|
|
@@ -30083,8 +30609,14 @@ function injectCollectedImages(source, images) {
|
|
|
30083
30609
|
}
|
|
30084
30610
|
const insertions = /* @__PURE__ */ new Map();
|
|
30085
30611
|
for (const [index, image] of images.entries()) {
|
|
30086
|
-
let headingLine = headingLines[index];
|
|
30087
|
-
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) {
|
|
30088
30620
|
const match = /^after-heading:(.+)$/u.exec(image.placementAnchor);
|
|
30089
30621
|
const requestedHeading = match?.[1]?.trim().replace(/^##\s+/u, "").replace(/\s+#+\s*$/u, "").trim();
|
|
30090
30622
|
const matches = requestedHeading === void 0 ? void 0 : headingLineByText.get(requestedHeading);
|
|
@@ -30114,12 +30646,12 @@ function injectCollectedImages(source, images) {
|
|
|
30114
30646
|
return output.join("\n");
|
|
30115
30647
|
}
|
|
30116
30648
|
function parsedVisualPlan(source) {
|
|
30117
|
-
const yamlSource =
|
|
30649
|
+
const yamlSource = VISUAL_PLAN_FRONTMATTER2.exec(source)?.[1];
|
|
30118
30650
|
if (yamlSource === void 0) {
|
|
30119
30651
|
throw new WechatCliError("DXC_PUBLISHING_VISUAL_PLAN_INVALID");
|
|
30120
30652
|
}
|
|
30121
30653
|
try {
|
|
30122
|
-
const plan =
|
|
30654
|
+
const plan = recordValue2((0, import_yaml3.parse)(yamlSource, { maxAliasCount: 10, uniqueKeys: true }));
|
|
30123
30655
|
if (plan === void 0) {
|
|
30124
30656
|
throw new WechatCliError("DXC_PUBLISHING_VISUAL_PLAN_INVALID");
|
|
30125
30657
|
}
|
|
@@ -30131,29 +30663,299 @@ function parsedVisualPlan(source) {
|
|
|
30131
30663
|
throw new WechatCliError("DXC_PUBLISHING_VISUAL_PLAN_INVALID");
|
|
30132
30664
|
}
|
|
30133
30665
|
}
|
|
30134
|
-
function
|
|
30135
|
-
const
|
|
30136
|
-
const
|
|
30137
|
-
|
|
30138
|
-
|
|
30139
|
-
|
|
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) {
|
|
30140
30681
|
throw new WechatCliError(
|
|
30141
30682
|
"DXC_PUBLISHING_VISUAL_PLAN_INVALID",
|
|
30142
|
-
|
|
30683
|
+
`\u89C6\u89C9\u7D20\u6750 ${expectedAssetId} \u7684 sidecar\uFF08\u65C1\u8F66\u5143\u6570\u636E\uFF09\u65E0\u6548\u3002`
|
|
30143
30684
|
);
|
|
30144
30685
|
}
|
|
30686
|
+
const parsedSectionId = typeof sectionId === "string" ? sectionId : void 0;
|
|
30145
30687
|
return {
|
|
30146
|
-
|
|
30147
|
-
|
|
30148
|
-
|
|
30688
|
+
assetId: expectedAssetId,
|
|
30689
|
+
relativePath,
|
|
30690
|
+
role: index === 0 ? "cover" : "inline",
|
|
30691
|
+
...parsedSectionId === void 0 ? {} : { sectionId: parsedSectionId },
|
|
30692
|
+
sha256: asset["sha256"]
|
|
30149
30693
|
};
|
|
30150
30694
|
});
|
|
30151
|
-
|
|
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");
|
|
30706
|
+
}
|
|
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;
|
|
30152
30954
|
}
|
|
30153
30955
|
async function plannedVisualAssets(visualPlanFile, assetsDirectoryInput, maximumCoverBytes = MAXIMUM_IMAGE_BYTES, maximumInlineBytes = MAXIMUM_INLINE_IMAGE_BYTES) {
|
|
30154
30956
|
let source;
|
|
30155
30957
|
try {
|
|
30156
|
-
source = (await readPublishingInput(visualPlanFile,
|
|
30958
|
+
source = (await readPublishingInput(visualPlanFile, VISUAL_PLAN_MAXIMUM_BYTES2, "visual-plan")).bytes.toString("utf8");
|
|
30157
30959
|
} catch {
|
|
30158
30960
|
throw new WechatCliError("DXC_PUBLISHING_VISUAL_PLAN_INVALID");
|
|
30159
30961
|
}
|
|
@@ -30169,12 +30971,12 @@ async function plannedVisualAssets(visualPlanFile, assetsDirectoryInput, maximum
|
|
|
30169
30971
|
"\u4F7F\u7528\u89C6\u89C9\u8BA1\u5212\u65F6\u5FC5\u987B\u663E\u5F0F\u63D0\u4F9B\u5176\u58F0\u660E\u7684\u7D20\u6750\u76EE\u5F55\u3002"
|
|
30170
30972
|
);
|
|
30171
30973
|
}
|
|
30172
|
-
const assetsDirectory =
|
|
30974
|
+
const assetsDirectory = path6.resolve(assetsDirectoryInput);
|
|
30173
30975
|
const projectDirectory = commonDirectory(
|
|
30174
|
-
|
|
30976
|
+
path6.dirname(path6.resolve(visualPlanFile)),
|
|
30175
30977
|
assetsDirectory
|
|
30176
30978
|
);
|
|
30177
|
-
const declaredAssetsDirectory = typeof plan["assetsDirectory"] === "string" ?
|
|
30979
|
+
const declaredAssetsDirectory = typeof plan["assetsDirectory"] === "string" ? path6.resolve(projectDirectory, plan["assetsDirectory"]) : assetsDirectory;
|
|
30178
30980
|
if (!isWithinDirectory(assetsDirectory, declaredAssetsDirectory)) {
|
|
30179
30981
|
throw new WechatCliError(
|
|
30180
30982
|
"DXC_PUBLISHING_VISUAL_PLAN_INVALID",
|
|
@@ -30182,7 +30984,7 @@ async function plannedVisualAssets(visualPlanFile, assetsDirectoryInput, maximum
|
|
|
30182
30984
|
);
|
|
30183
30985
|
}
|
|
30184
30986
|
const resolvePlannedAsset = (assetPath) => {
|
|
30185
|
-
const target =
|
|
30987
|
+
const target = path6.resolve(projectDirectory, assetPath);
|
|
30186
30988
|
if (!isWithinDirectory(target, declaredAssetsDirectory) || !isWithinDirectory(target, assetsDirectory)) {
|
|
30187
30989
|
throw new WechatCliError("DXC_PUBLISHING_VISUAL_PLAN_INVALID");
|
|
30188
30990
|
}
|
|
@@ -30199,18 +31001,19 @@ async function plannedVisualAssets(visualPlanFile, assetsDirectoryInput, maximum
|
|
|
30199
31001
|
coverAbsolutePath,
|
|
30200
31002
|
inline: await Promise.all(
|
|
30201
31003
|
inlineAssets.map(async (rawAsset) => {
|
|
30202
|
-
const asset =
|
|
30203
|
-
|
|
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)) {
|
|
30204
31007
|
throw new WechatCliError(
|
|
30205
31008
|
"DXC_PUBLISHING_VISUAL_PLAN_INVALID",
|
|
30206
|
-
"\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"
|
|
30207
31010
|
);
|
|
30208
31011
|
}
|
|
30209
31012
|
const absolutePath = resolvePlannedAsset(asset["path"]);
|
|
30210
31013
|
if (!isWithinDirectory(absolutePath, assetsDirectory)) {
|
|
30211
31014
|
throw new WechatCliError(
|
|
30212
31015
|
"DXC_PUBLISHING_VISUAL_PLAN_INVALID",
|
|
30213
|
-
`\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`
|
|
30214
31017
|
);
|
|
30215
31018
|
}
|
|
30216
31019
|
await readContainedPublishingInput(
|
|
@@ -30226,13 +31029,14 @@ async function plannedVisualAssets(visualPlanFile, assetsDirectoryInput, maximum
|
|
|
30226
31029
|
"\u6B63\u6587\u914D\u56FE\u7684\u539F\u59CB\u8DEF\u5F84\u5FC5\u987B\u662F\u9879\u76EE\u5185\u5B89\u5168\u76F8\u5BF9\u8DEF\u5F84\u3002"
|
|
30227
31030
|
);
|
|
30228
31031
|
}
|
|
30229
|
-
const digest =
|
|
30230
|
-
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`;
|
|
30231
31034
|
return {
|
|
30232
31035
|
absolutePath,
|
|
30233
|
-
alt: typeof asset["purpose"] === "string" ? asset["purpose"] :
|
|
31036
|
+
alt: typeof asset["purpose"] === "string" ? asset["purpose"] : path6.basename(absolutePath, path6.extname(absolutePath)),
|
|
30234
31037
|
logicalPath: `assets/dxc-visuals/${digest}-${fileName}`,
|
|
30235
|
-
|
|
31038
|
+
...typeof headingIndex === "number" ? { headingIndex } : {},
|
|
31039
|
+
...typeof asset["placementAnchor"] === "string" ? { placementAnchor: asset["placementAnchor"] } : {},
|
|
30236
31040
|
plannedPath: asset["path"],
|
|
30237
31041
|
...sourceLogicalPath === void 0 ? {} : { sourceLogicalPath }
|
|
30238
31042
|
};
|
|
@@ -30240,30 +31044,6 @@ async function plannedVisualAssets(visualPlanFile, assetsDirectoryInput, maximum
|
|
|
30240
31044
|
)
|
|
30241
31045
|
};
|
|
30242
31046
|
}
|
|
30243
|
-
async function validateWorkflowVisualPlan(input) {
|
|
30244
|
-
const plan = parsedVisualPlan(input.visualPlanSource);
|
|
30245
|
-
if (typeof plan["assetsDirectory"] !== "string" || plan["assetsDirectory"].trim().length === 0) {
|
|
30246
|
-
throw new WechatCliError(
|
|
30247
|
-
"DXC_PUBLISHING_VISUAL_PLAN_INVALID",
|
|
30248
|
-
"\u89C6\u89C9\u8BA1\u5212\u5FC5\u987B\u58F0\u660E\u9879\u76EE\u7D20\u6750\u57FA\u7840\u76EE\u5F55 assetsDirectory\u3002"
|
|
30249
|
-
);
|
|
30250
|
-
}
|
|
30251
|
-
const expectedAssetsDirectory = path5.resolve(input.assetsDirectory);
|
|
30252
|
-
const declaredAssetsDirectory = path5.resolve(input.projectDirectory, plan["assetsDirectory"]);
|
|
30253
|
-
if (declaredAssetsDirectory !== expectedAssetsDirectory) {
|
|
30254
|
-
throw new WechatCliError(
|
|
30255
|
-
"DXC_PUBLISHING_VISUAL_PLAN_INVALID",
|
|
30256
|
-
`\u89C6\u89C9\u8BA1\u5212 assetsDirectory \u5FC5\u987B\u662F\u9879\u76EE\u7D20\u6750\u57FA\u7840\u76EE\u5F55 ${path5.relative(input.projectDirectory, expectedAssetsDirectory) || "."}\uFF0C\u4E0D\u80FD\u586B\u5199\u5176\u5B50\u76EE\u5F55\u3002`
|
|
30257
|
-
);
|
|
30258
|
-
}
|
|
30259
|
-
await plannedVisualAssets(
|
|
30260
|
-
input.visualPlanFile,
|
|
30261
|
-
expectedAssetsDirectory,
|
|
30262
|
-
MAXIMUM_OPTIMIZABLE_IMAGE_BYTES,
|
|
30263
|
-
MAXIMUM_OPTIMIZABLE_IMAGE_BYTES
|
|
30264
|
-
);
|
|
30265
|
-
validateVisualPlanPlacementAnchors(input.articleSource, input.visualPlanSource);
|
|
30266
|
-
}
|
|
30267
31047
|
function logicalInlinePaths(bundle) {
|
|
30268
31048
|
return bundle.assets.filter((asset) => asset.role === "inline").map((asset) => asset.logicalPath);
|
|
30269
31049
|
}
|
|
@@ -30274,7 +31054,7 @@ function publishingArticleSource(source, digestOverride) {
|
|
|
30274
31054
|
if (yamlSource === void 0 || body === void 0) {
|
|
30275
31055
|
throw new WechatCliError("DXC_PUBLISHING_ARTICLE_INVALID");
|
|
30276
31056
|
}
|
|
30277
|
-
const document = (0,
|
|
31057
|
+
const document = (0, import_yaml3.parseDocument)(yamlSource, { uniqueKeys: true });
|
|
30278
31058
|
if (document.errors.length > 0) {
|
|
30279
31059
|
throw new WechatCliError("DXC_PUBLISHING_ARTICLE_INVALID");
|
|
30280
31060
|
}
|
|
@@ -30299,21 +31079,21 @@ async function preparePublishingDraft(input) {
|
|
|
30299
31079
|
} catch {
|
|
30300
31080
|
throw new WechatCliError("DXC_PUBLISHING_ARTICLE_INVALID");
|
|
30301
31081
|
}
|
|
30302
|
-
const articleDirectory =
|
|
31082
|
+
const articleDirectory = path6.dirname(articleInput.path);
|
|
30303
31083
|
const availableImages = await collectedImages(input.assetsDirectory, articleDirectory);
|
|
30304
31084
|
const availableByFileName = new Map(
|
|
30305
|
-
availableImages.map((candidate) => [
|
|
31085
|
+
availableImages.map((candidate) => [path6.basename(candidate), candidate])
|
|
30306
31086
|
);
|
|
30307
|
-
const projectDirectory = input.assetsDirectory === void 0 ? articleDirectory : commonDirectory(articleDirectory,
|
|
30308
|
-
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);
|
|
30309
31089
|
const referenced = new Set(logicalInlinePaths(originalBundle));
|
|
30310
31090
|
const automaticAssetDirectories = [
|
|
30311
31091
|
articleDirectory,
|
|
30312
|
-
...input.assetsDirectory === void 0 ? [] : [
|
|
31092
|
+
...input.assetsDirectory === void 0 ? [] : [path6.resolve(input.assetsDirectory)]
|
|
30313
31093
|
];
|
|
30314
31094
|
const articleCoverCandidate = originalBundle.coverImage !== void 0 && isSafeLogicalAssetPath(originalBundle.coverImage) ? resolveDeclaredAsset(originalBundle.coverImage) : void 0;
|
|
30315
31095
|
const namedCoverCandidate = availableImages.find(
|
|
30316
|
-
(candidate) => /^cover(?:[._-]|$)/iu.test(
|
|
31096
|
+
(candidate) => /^cover(?:[._-]|$)/iu.test(path6.basename(candidate))
|
|
30317
31097
|
);
|
|
30318
31098
|
const explicitCover = input.coverFile !== void 0 && input.coverFile !== "auto" ? input.coverFile : void 0;
|
|
30319
31099
|
const planned = input.visualPlanFile === void 0 ? void 0 : await plannedVisualAssets(input.visualPlanFile, input.assetsDirectory);
|
|
@@ -30339,16 +31119,16 @@ async function preparePublishingDraft(input) {
|
|
|
30339
31119
|
const coverCandidate = explicitCover ?? planned?.coverAbsolutePath ?? articleCoverCandidate ?? namedCoverCandidate;
|
|
30340
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;
|
|
30341
31121
|
const pickupCandidates = availableImages.filter(
|
|
30342
|
-
(candidate) => candidate !== namedCoverCandidate && candidate !== articleCoverCandidate && !referencedFiles.has(
|
|
31122
|
+
(candidate) => candidate !== namedCoverCandidate && candidate !== articleCoverCandidate && !referencedFiles.has(path6.resolve(candidate)) && input.visualPlanFile === void 0
|
|
30343
31123
|
);
|
|
30344
31124
|
const injected = [
|
|
30345
31125
|
...plannedInlineForInjection,
|
|
30346
31126
|
...pickupCandidates.slice(0, Math.max(0, MAXIMUM_INLINE_IMAGES - referenced.size)).map((candidate) => {
|
|
30347
|
-
const digest =
|
|
30348
|
-
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`;
|
|
30349
31129
|
return {
|
|
30350
31130
|
absolutePath: candidate,
|
|
30351
|
-
alt:
|
|
31131
|
+
alt: path6.basename(candidate, path6.extname(candidate)),
|
|
30352
31132
|
logicalPath: `assets/dxc-visuals/${digest}-${fileName}`
|
|
30353
31133
|
};
|
|
30354
31134
|
}).filter((asset) => !referenced.has(asset.logicalPath))
|
|
@@ -30392,7 +31172,7 @@ async function preparePublishingDraft(input) {
|
|
|
30392
31172
|
);
|
|
30393
31173
|
const inlineAssets = await Promise.all(
|
|
30394
31174
|
logicalInlinePaths(bundle).map(async (logicalPath) => {
|
|
30395
|
-
const target = injectedByLogicalPath.get(logicalPath) ?? referencedFilesByLogicalPath.get(logicalPath) ??
|
|
31175
|
+
const target = injectedByLogicalPath.get(logicalPath) ?? referencedFilesByLogicalPath.get(logicalPath) ?? path6.resolve(articleDirectory, logicalPath);
|
|
30396
31176
|
const asset = await readContainedPublishingInput(
|
|
30397
31177
|
target,
|
|
30398
31178
|
MAXIMUM_INLINE_IMAGE_BYTES,
|
|
@@ -30433,354 +31213,6 @@ async function preparePublishingDraft(input) {
|
|
|
30433
31213
|
};
|
|
30434
31214
|
}
|
|
30435
31215
|
|
|
30436
|
-
// apps/cli/src/publishing-image-optimization.ts
|
|
30437
|
-
var import_yaml3 = __toESM(require_dist(), 1);
|
|
30438
|
-
import { createHash as createHash5, randomUUID as randomUUID3 } from "node:crypto";
|
|
30439
|
-
import { constants as fileConstants2 } from "node:fs";
|
|
30440
|
-
import {
|
|
30441
|
-
lstat as lstat5,
|
|
30442
|
-
mkdir as mkdir3,
|
|
30443
|
-
open as open2,
|
|
30444
|
-
readFile as readFile2,
|
|
30445
|
-
realpath as realpath2,
|
|
30446
|
-
rename as rename3,
|
|
30447
|
-
unlink,
|
|
30448
|
-
writeFile
|
|
30449
|
-
} from "node:fs/promises";
|
|
30450
|
-
import path6 from "node:path";
|
|
30451
|
-
import sharp2 from "sharp";
|
|
30452
|
-
var MAXIMUM_INPUT_BYTES = 32 * 1024 * 1024;
|
|
30453
|
-
var INLINE_IMAGE_LIMIT = 1024 * 1024 - 1;
|
|
30454
|
-
var INLINE_IMAGE_TARGET = 950 * 1024;
|
|
30455
|
-
var COVER_IMAGE_LIMIT = 5 * 1024 * 1024;
|
|
30456
|
-
var COVER_IMAGE_TARGET = 4500 * 1024;
|
|
30457
|
-
var VISUAL_PLAN_MAXIMUM_BYTES2 = 128 * 1024;
|
|
30458
|
-
var VISUAL_PLAN_FRONTMATTER2 = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)([\s\S]*)$/u;
|
|
30459
|
-
function sha256(value) {
|
|
30460
|
-
return createHash5("sha256").update(value).digest("hex");
|
|
30461
|
-
}
|
|
30462
|
-
function safeDerivativeBase(value) {
|
|
30463
|
-
return value.normalize("NFKC").replaceAll(/[^A-Za-z0-9._-]+/gu, "-").replaceAll(/^-+|-+$/gu, "").slice(0, 80) || "image";
|
|
30464
|
-
}
|
|
30465
|
-
function recordValue2(value) {
|
|
30466
|
-
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
30467
|
-
}
|
|
30468
|
-
function portablePath(value, label) {
|
|
30469
|
-
if (typeof value !== "string" || value.trim().length === 0 || path6.isAbsolute(value) || value.includes("\\") || value.split("/").some((segment) => segment === "" || segment === "." || segment === "..")) {
|
|
30470
|
-
throw new WechatCliError(
|
|
30471
|
-
"DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
|
|
30472
|
-
`${label} \u5FC5\u987B\u662F\u9879\u76EE\u5185\u4F7F\u7528 / \u5206\u9694\u7684\u5B89\u5168\u76F8\u5BF9\u8DEF\u5F84\u3002`
|
|
30473
|
-
);
|
|
30474
|
-
}
|
|
30475
|
-
return value;
|
|
30476
|
-
}
|
|
30477
|
-
function isWithin(target, directory) {
|
|
30478
|
-
const relative = path6.relative(directory, target);
|
|
30479
|
-
return relative === "" || !relative.startsWith(`..${path6.sep}`) && relative !== "..";
|
|
30480
|
-
}
|
|
30481
|
-
async function regularImage(target) {
|
|
30482
|
-
let handle;
|
|
30483
|
-
try {
|
|
30484
|
-
handle = await open2(target, fileConstants2.O_RDONLY | fileConstants2.O_NOFOLLOW);
|
|
30485
|
-
const metadata = await handle.stat();
|
|
30486
|
-
if (!metadata.isFile() || metadata.size <= 0 || metadata.size > MAXIMUM_INPUT_BYTES) {
|
|
30487
|
-
throw new Error("invalid image");
|
|
30488
|
-
}
|
|
30489
|
-
return await handle.readFile();
|
|
30490
|
-
} catch {
|
|
30491
|
-
throw new WechatCliError(
|
|
30492
|
-
"DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
|
|
30493
|
-
`\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`
|
|
30494
|
-
);
|
|
30495
|
-
} finally {
|
|
30496
|
-
await handle?.close();
|
|
30497
|
-
}
|
|
30498
|
-
}
|
|
30499
|
-
async function requirePreservedAlpha(bytes) {
|
|
30500
|
-
const metadata = await sharp2(bytes, {
|
|
30501
|
-
failOn: "error",
|
|
30502
|
-
limitInputPixels: 8e7
|
|
30503
|
-
}).metadata();
|
|
30504
|
-
if (metadata.format !== "png" || metadata.hasAlpha !== true) {
|
|
30505
|
-
throw new WechatCliError(
|
|
30506
|
-
"DXC_PUBLISHING_IMAGE_ALPHA_LOST",
|
|
30507
|
-
"\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"
|
|
30508
|
-
);
|
|
30509
|
-
}
|
|
30510
|
-
}
|
|
30511
|
-
async function decodedImageMetadata(source, sourcePath) {
|
|
30512
|
-
let metadata;
|
|
30513
|
-
try {
|
|
30514
|
-
metadata = await sharp2(source, { failOn: "error", limitInputPixels: 8e7 }).metadata();
|
|
30515
|
-
} catch {
|
|
30516
|
-
throw new WechatCliError(
|
|
30517
|
-
"DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
|
|
30518
|
-
"\u56FE\u7247\u65E0\u6CD5\u88AB\u5B89\u5168\u89E3\u7801\uFF1B\u4EC5\u652F\u6301\u6709\u6548 PNG/JPEG\u3002"
|
|
30519
|
-
);
|
|
30520
|
-
}
|
|
30521
|
-
const extension = path6.extname(sourcePath).toLowerCase();
|
|
30522
|
-
const expectedFormat = extension === ".png" ? "png" : extension === ".jpg" || extension === ".jpeg" ? "jpeg" : void 0;
|
|
30523
|
-
if (expectedFormat === void 0 || metadata.format !== expectedFormat || metadata.width === void 0 || metadata.height === void 0) {
|
|
30524
|
-
throw new WechatCliError(
|
|
30525
|
-
"DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
|
|
30526
|
-
"\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"
|
|
30527
|
-
);
|
|
30528
|
-
}
|
|
30529
|
-
return {
|
|
30530
|
-
format: expectedFormat,
|
|
30531
|
-
hasAlpha: metadata.hasAlpha === true,
|
|
30532
|
-
height: metadata.height,
|
|
30533
|
-
width: metadata.width
|
|
30534
|
-
};
|
|
30535
|
-
}
|
|
30536
|
-
async function writeExclusiveOrVerify(target, bytes) {
|
|
30537
|
-
await mkdir3(path6.dirname(target), { recursive: true, mode: 448 });
|
|
30538
|
-
try {
|
|
30539
|
-
await writeFile(target, bytes, { flag: "wx", mode: 384 });
|
|
30540
|
-
return true;
|
|
30541
|
-
} catch (error) {
|
|
30542
|
-
if (error.code !== "EEXIST") {
|
|
30543
|
-
throw error;
|
|
30544
|
-
}
|
|
30545
|
-
const existing = await regularImage(target);
|
|
30546
|
-
if (sha256(existing) !== sha256(bytes)) {
|
|
30547
|
-
throw new WechatCliError(
|
|
30548
|
-
"DXC_PUBLISHING_IMAGE_OPTIMIZATION_CONFLICT",
|
|
30549
|
-
`\u4F18\u5316\u76EE\u6807 ${path6.basename(target)} \u5DF2\u5B58\u5728\u4F46\u5185\u5BB9\u4E0D\u540C\uFF1B\u672A\u8986\u76D6\u4EFB\u4F55\u6587\u4EF6\u3002`
|
|
30550
|
-
);
|
|
30551
|
-
}
|
|
30552
|
-
return false;
|
|
30553
|
-
}
|
|
30554
|
-
}
|
|
30555
|
-
async function safeRealPathWithin(target, directory, label) {
|
|
30556
|
-
const resolved = await realpath2(target).catch(() => void 0);
|
|
30557
|
-
if (resolved === void 0 || !isWithin(resolved, directory)) {
|
|
30558
|
-
throw new WechatCliError(
|
|
30559
|
-
"DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
|
|
30560
|
-
`${label} \u7684\u771F\u5B9E\u8DEF\u5F84\u4E0D\u5728\u5141\u8BB8\u7684\u9879\u76EE\u76EE\u5F55\u5185\u3002`
|
|
30561
|
-
);
|
|
30562
|
-
}
|
|
30563
|
-
return resolved;
|
|
30564
|
-
}
|
|
30565
|
-
async function ensureSafeOptimizedDirectory(assetsDirectory, realAssetsDirectory) {
|
|
30566
|
-
const optimizedDirectory = path6.join(assetsDirectory, "optimized");
|
|
30567
|
-
await mkdir3(optimizedDirectory, { recursive: true, mode: 448 });
|
|
30568
|
-
const metadata = await lstat5(optimizedDirectory).catch(() => void 0);
|
|
30569
|
-
if (metadata === void 0 || !metadata.isDirectory() || metadata.isSymbolicLink()) {
|
|
30570
|
-
throw new WechatCliError(
|
|
30571
|
-
"DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
|
|
30572
|
-
"\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"
|
|
30573
|
-
);
|
|
30574
|
-
}
|
|
30575
|
-
await safeRealPathWithin(optimizedDirectory, realAssetsDirectory, "\u4F18\u5316\u76EE\u5F55");
|
|
30576
|
-
return optimizedDirectory;
|
|
30577
|
-
}
|
|
30578
|
-
async function writePlanAtomically(target, expectedSource, source) {
|
|
30579
|
-
const temporary = `${target}.${randomUUID3()}.tmp`;
|
|
30580
|
-
try {
|
|
30581
|
-
await writeFile(temporary, source, { encoding: "utf8", flag: "wx", mode: 384 });
|
|
30582
|
-
if (await readFile2(target, "utf8") !== expectedSource) {
|
|
30583
|
-
throw new WechatCliError(
|
|
30584
|
-
"DXC_PUBLISHING_IMAGE_OPTIMIZATION_CONFLICT",
|
|
30585
|
-
"\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"
|
|
30586
|
-
);
|
|
30587
|
-
}
|
|
30588
|
-
await rename3(temporary, target);
|
|
30589
|
-
} finally {
|
|
30590
|
-
await unlink(temporary).catch(() => void 0);
|
|
30591
|
-
}
|
|
30592
|
-
}
|
|
30593
|
-
function candidateWidths(width) {
|
|
30594
|
-
return [.../* @__PURE__ */ new Set([width, 2400, 2e3, 1600, 1280, 1080, 900, 720])].filter((candidate) => candidate > 0 && candidate <= width).sort((left, right) => right - left);
|
|
30595
|
-
}
|
|
30596
|
-
async function optimizedImage(source, targetBytes, metadata) {
|
|
30597
|
-
const hasAlpha = metadata.hasAlpha;
|
|
30598
|
-
for (const width of candidateWidths(metadata.width)) {
|
|
30599
|
-
if (hasAlpha) {
|
|
30600
|
-
const lossless = await sharp2(source, { failOn: "error", limitInputPixels: 8e7 }).rotate().resize({ fit: "inside", width, withoutEnlargement: true }).png({ compressionLevel: 9, effort: 10 }).toBuffer();
|
|
30601
|
-
if (lossless.byteLength <= targetBytes) {
|
|
30602
|
-
await requirePreservedAlpha(lossless);
|
|
30603
|
-
return { alphaPreserved: true, bytes: lossless, extension: ".png" };
|
|
30604
|
-
}
|
|
30605
|
-
for (const colours of [256, 192, 128, 96, 64]) {
|
|
30606
|
-
const quantized = await sharp2(source, {
|
|
30607
|
-
failOn: "error",
|
|
30608
|
-
limitInputPixels: 8e7
|
|
30609
|
-
}).rotate().resize({ fit: "inside", width, withoutEnlargement: true }).png({ colours, compressionLevel: 9, effort: 10, palette: true }).toBuffer();
|
|
30610
|
-
if (quantized.byteLength <= targetBytes) {
|
|
30611
|
-
await requirePreservedAlpha(quantized);
|
|
30612
|
-
return { alphaPreserved: true, bytes: quantized, extension: ".png" };
|
|
30613
|
-
}
|
|
30614
|
-
}
|
|
30615
|
-
continue;
|
|
30616
|
-
}
|
|
30617
|
-
for (const quality of [88, 82, 76, 70, 64, 58]) {
|
|
30618
|
-
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();
|
|
30619
|
-
if (jpeg.byteLength <= targetBytes) {
|
|
30620
|
-
return { alphaPreserved: true, bytes: jpeg, extension: ".jpg" };
|
|
30621
|
-
}
|
|
30622
|
-
}
|
|
30623
|
-
}
|
|
30624
|
-
throw new WechatCliError(
|
|
30625
|
-
"DXC_PUBLISHING_IMAGE_OPTIMIZATION_LIMIT_UNREACHABLE",
|
|
30626
|
-
`\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`
|
|
30627
|
-
);
|
|
30628
|
-
}
|
|
30629
|
-
async function optimizePublishingImages(input) {
|
|
30630
|
-
const projectDirectory = path6.resolve(input.projectDirectory);
|
|
30631
|
-
const visualPlanPath = path6.resolve(input.visualPlanFile);
|
|
30632
|
-
if (!isWithin(visualPlanPath, projectDirectory)) {
|
|
30633
|
-
throw new WechatCliError(
|
|
30634
|
-
"DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
|
|
30635
|
-
"\u89C6\u89C9\u8BA1\u5212\u5FC5\u987B\u4F4D\u4E8E\u5F53\u524D\u5185\u5BB9\u9879\u76EE\u5185\u3002"
|
|
30636
|
-
);
|
|
30637
|
-
}
|
|
30638
|
-
const projectMetadata = await lstat5(projectDirectory).catch(() => void 0);
|
|
30639
|
-
const visualPlanMetadata = await lstat5(visualPlanPath).catch(() => void 0);
|
|
30640
|
-
if (projectMetadata === void 0 || !projectMetadata.isDirectory() || projectMetadata.isSymbolicLink() || visualPlanMetadata === void 0 || !visualPlanMetadata.isFile() || visualPlanMetadata.isSymbolicLink() || visualPlanMetadata.size > VISUAL_PLAN_MAXIMUM_BYTES2) {
|
|
30641
|
-
throw new WechatCliError(
|
|
30642
|
-
"DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
|
|
30643
|
-
"\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"
|
|
30644
|
-
);
|
|
30645
|
-
}
|
|
30646
|
-
const realProjectDirectory = await realpath2(projectDirectory);
|
|
30647
|
-
await safeRealPathWithin(visualPlanPath, realProjectDirectory, "\u89C6\u89C9\u8BA1\u5212");
|
|
30648
|
-
const source = await readFile2(visualPlanPath, "utf8").catch(() => "");
|
|
30649
|
-
if (Buffer.byteLength(source, "utf8") > VISUAL_PLAN_MAXIMUM_BYTES2) {
|
|
30650
|
-
throw new WechatCliError("DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID");
|
|
30651
|
-
}
|
|
30652
|
-
const match = VISUAL_PLAN_FRONTMATTER2.exec(source);
|
|
30653
|
-
if (match?.[1] === void 0 || match[2] === void 0) {
|
|
30654
|
-
throw new WechatCliError("DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID");
|
|
30655
|
-
}
|
|
30656
|
-
let frontmatter2;
|
|
30657
|
-
try {
|
|
30658
|
-
frontmatter2 = recordValue2((0, import_yaml3.parse)(match[1], { maxAliasCount: 10, uniqueKeys: true }));
|
|
30659
|
-
} catch {
|
|
30660
|
-
throw new WechatCliError("DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID");
|
|
30661
|
-
}
|
|
30662
|
-
if (frontmatter2 === void 0) {
|
|
30663
|
-
throw new WechatCliError(
|
|
30664
|
-
"DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
|
|
30665
|
-
"\u89C6\u89C9\u8BA1\u5212\u7684 YAML \u5934\u65E0\u6CD5\u8BFB\u53D6\u3002"
|
|
30666
|
-
);
|
|
30667
|
-
}
|
|
30668
|
-
const assetsRelative = frontmatter2["assetsDirectory"] === void 0 ? "assets" : portablePath(frontmatter2["assetsDirectory"], "assetsDirectory");
|
|
30669
|
-
frontmatter2["assetsDirectory"] = assetsRelative;
|
|
30670
|
-
frontmatter2["inlineImagesSupported"] = true;
|
|
30671
|
-
const assetsDirectory = path6.resolve(projectDirectory, assetsRelative);
|
|
30672
|
-
if (!isWithin(assetsDirectory, projectDirectory)) {
|
|
30673
|
-
throw new WechatCliError("DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID");
|
|
30674
|
-
}
|
|
30675
|
-
const assetsMetadata = await lstat5(assetsDirectory).catch(() => void 0);
|
|
30676
|
-
if (assetsMetadata === void 0 || !assetsMetadata.isDirectory() || assetsMetadata.isSymbolicLink()) {
|
|
30677
|
-
throw new WechatCliError("DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID");
|
|
30678
|
-
}
|
|
30679
|
-
const realAssetsDirectory = await safeRealPathWithin(
|
|
30680
|
-
assetsDirectory,
|
|
30681
|
-
realProjectDirectory,
|
|
30682
|
-
"\u7D20\u6750\u76EE\u5F55"
|
|
30683
|
-
);
|
|
30684
|
-
const inlineAssets = Array.isArray(frontmatter2["inlineAssets"]) ? frontmatter2["inlineAssets"] : [];
|
|
30685
|
-
const entries = [
|
|
30686
|
-
{
|
|
30687
|
-
limit: COVER_IMAGE_LIMIT,
|
|
30688
|
-
record: { path: frontmatter2["coverAsset"] },
|
|
30689
|
-
role: "cover",
|
|
30690
|
-
target: COVER_IMAGE_TARGET
|
|
30691
|
-
},
|
|
30692
|
-
...inlineAssets.map((asset) => ({
|
|
30693
|
-
limit: INLINE_IMAGE_LIMIT,
|
|
30694
|
-
record: recordValue2(asset),
|
|
30695
|
-
role: "inline",
|
|
30696
|
-
target: INLINE_IMAGE_TARGET
|
|
30697
|
-
}))
|
|
30698
|
-
];
|
|
30699
|
-
const createdFiles = [];
|
|
30700
|
-
const mutations = [];
|
|
30701
|
-
let unchangedCount = 0;
|
|
30702
|
-
let optimizedDirectory;
|
|
30703
|
-
try {
|
|
30704
|
-
for (const entry of entries) {
|
|
30705
|
-
const assetPath = portablePath(entry.record?.["path"], `${entry.role} \u56FE\u7247\u8DEF\u5F84`);
|
|
30706
|
-
const absolutePath = path6.resolve(projectDirectory, assetPath);
|
|
30707
|
-
if (!isWithin(absolutePath, assetsDirectory)) {
|
|
30708
|
-
throw new WechatCliError(
|
|
30709
|
-
"DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
|
|
30710
|
-
`${assetPath} \u4E0D\u5728\u89C6\u89C9\u8BA1\u5212\u58F0\u660E\u7684\u7D20\u6750\u76EE\u5F55\u5185\u3002`
|
|
30711
|
-
);
|
|
30712
|
-
}
|
|
30713
|
-
await safeRealPathWithin(absolutePath, realAssetsDirectory, `${assetPath} \u56FE\u7247`);
|
|
30714
|
-
const bytes = await regularImage(absolutePath);
|
|
30715
|
-
const metadata = await decodedImageMetadata(bytes, assetPath);
|
|
30716
|
-
const beforeSha256 = sha256(bytes);
|
|
30717
|
-
let finalPath = assetPath;
|
|
30718
|
-
let finalBytes = bytes;
|
|
30719
|
-
let alphaPreserved = true;
|
|
30720
|
-
if (bytes.byteLength > entry.limit) {
|
|
30721
|
-
const optimized = await optimizedImage(bytes, entry.target, metadata);
|
|
30722
|
-
optimizedDirectory ??= await ensureSafeOptimizedDirectory(
|
|
30723
|
-
assetsDirectory,
|
|
30724
|
-
realAssetsDirectory
|
|
30725
|
-
);
|
|
30726
|
-
const baseName = safeDerivativeBase(path6.basename(assetPath, path6.extname(assetPath)));
|
|
30727
|
-
const optimizedSha256 = sha256(optimized.bytes);
|
|
30728
|
-
const optimizedName = `${baseName}-${entry.role}-${beforeSha256.slice(0, 12)}-${optimizedSha256.slice(0, 12)}${optimized.extension}`;
|
|
30729
|
-
const optimizedAbsolute = path6.join(optimizedDirectory, optimizedName);
|
|
30730
|
-
const created = await writeExclusiveOrVerify(optimizedAbsolute, optimized.bytes);
|
|
30731
|
-
if (created) {
|
|
30732
|
-
createdFiles.push(optimizedAbsolute);
|
|
30733
|
-
}
|
|
30734
|
-
finalPath = path6.relative(projectDirectory, optimizedAbsolute).split(path6.sep).join("/");
|
|
30735
|
-
finalBytes = optimized.bytes;
|
|
30736
|
-
alphaPreserved = optimized.alphaPreserved;
|
|
30737
|
-
mutations.push({
|
|
30738
|
-
alphaPreserved,
|
|
30739
|
-
afterBytes: finalBytes.byteLength,
|
|
30740
|
-
afterSha256: sha256(finalBytes),
|
|
30741
|
-
beforeBytes: bytes.byteLength,
|
|
30742
|
-
beforeSha256,
|
|
30743
|
-
from: assetPath,
|
|
30744
|
-
role: entry.role,
|
|
30745
|
-
to: finalPath
|
|
30746
|
-
});
|
|
30747
|
-
} else {
|
|
30748
|
-
unchangedCount += 1;
|
|
30749
|
-
}
|
|
30750
|
-
if (entry.role === "cover") {
|
|
30751
|
-
frontmatter2["coverAsset"] = finalPath;
|
|
30752
|
-
frontmatter2["coverSha256"] = sha256(finalBytes);
|
|
30753
|
-
} else if (entry.record !== void 0) {
|
|
30754
|
-
if (finalPath !== assetPath && entry.record["sourcePath"] === void 0) {
|
|
30755
|
-
entry.record["sourcePath"] = assetPath;
|
|
30756
|
-
}
|
|
30757
|
-
entry.record["path"] = finalPath;
|
|
30758
|
-
entry.record["sha256"] = sha256(finalBytes);
|
|
30759
|
-
}
|
|
30760
|
-
}
|
|
30761
|
-
frontmatter2["inlineAssets"] = inlineAssets;
|
|
30762
|
-
const normalizedSource = `---
|
|
30763
|
-
${(0, import_yaml3.stringify)(frontmatter2, { lineWidth: 0 }).trimEnd()}
|
|
30764
|
-
---
|
|
30765
|
-
${match[2]}`;
|
|
30766
|
-
await writePlanAtomically(visualPlanPath, source, normalizedSource);
|
|
30767
|
-
} catch (error) {
|
|
30768
|
-
await Promise.all(createdFiles.map((target) => unlink(target).catch(() => void 0)));
|
|
30769
|
-
if (error instanceof WechatCliError) {
|
|
30770
|
-
throw error;
|
|
30771
|
-
}
|
|
30772
|
-
throw new WechatCliError(
|
|
30773
|
-
"DXC_PUBLISHING_IMAGE_OPTIMIZATION_FAILED",
|
|
30774
|
-
"\u56FE\u7247\u4F18\u5316\u672A\u5B8C\u6210\uFF1B\u539F\u56FE\u548C\u89C6\u89C9\u8BA1\u5212\u5747\u672A\u88AB\u8986\u76D6\u3002"
|
|
30775
|
-
);
|
|
30776
|
-
}
|
|
30777
|
-
return {
|
|
30778
|
-
command: "wechat.draft.optimize-images",
|
|
30779
|
-
data: { mutations, unchangedCount, visualPlanPath },
|
|
30780
|
-
ok: true
|
|
30781
|
-
};
|
|
30782
|
-
}
|
|
30783
|
-
|
|
30784
31216
|
// apps/cli/src/wechat.ts
|
|
30785
31217
|
var DEFAULT_API_BASE_URL = "https://content.deployxai.com";
|
|
30786
31218
|
var DEFAULT_POLL_INTERVAL_MS = 2e3;
|
|
@@ -30894,19 +31326,19 @@ function localPreviewOutputConflict() {
|
|
|
30894
31326
|
async function ensureLocalPreviewDirectory(directory) {
|
|
30895
31327
|
let metadata;
|
|
30896
31328
|
try {
|
|
30897
|
-
metadata = await
|
|
31329
|
+
metadata = await lstat5(directory);
|
|
30898
31330
|
} catch (error) {
|
|
30899
31331
|
if (fileSystemErrorCode(error) !== "ENOENT") {
|
|
30900
31332
|
throw error;
|
|
30901
31333
|
}
|
|
30902
31334
|
try {
|
|
30903
|
-
await
|
|
31335
|
+
await mkdir5(directory, { mode: 448 });
|
|
30904
31336
|
} catch (mkdirError) {
|
|
30905
31337
|
if (fileSystemErrorCode(mkdirError) !== "EEXIST") {
|
|
30906
31338
|
throw mkdirError;
|
|
30907
31339
|
}
|
|
30908
31340
|
}
|
|
30909
|
-
metadata = await
|
|
31341
|
+
metadata = await lstat5(directory);
|
|
30910
31342
|
}
|
|
30911
31343
|
if (!metadata.isDirectory() || metadata.isSymbolicLink()) {
|
|
30912
31344
|
throw localPreviewOutputConflict();
|
|
@@ -30921,7 +31353,7 @@ async function safeLocalPreviewOutput(options) {
|
|
|
30921
31353
|
throw localPreviewOutputConflict();
|
|
30922
31354
|
}
|
|
30923
31355
|
try {
|
|
30924
|
-
const projectMetadata = await
|
|
31356
|
+
const projectMetadata = await lstat5(projectDirectory);
|
|
30925
31357
|
if (!projectMetadata.isDirectory() || projectMetadata.isSymbolicLink()) {
|
|
30926
31358
|
throw localPreviewOutputConflict();
|
|
30927
31359
|
}
|
|
@@ -30932,7 +31364,7 @@ async function safeLocalPreviewOutput(options) {
|
|
|
30932
31364
|
await ensureLocalPreviewDirectory(directory);
|
|
30933
31365
|
}
|
|
30934
31366
|
try {
|
|
30935
|
-
const outputMetadata = await
|
|
31367
|
+
const outputMetadata = await lstat5(outputFile);
|
|
30936
31368
|
if (!outputMetadata.isFile() || outputMetadata.isSymbolicLink()) {
|
|
30937
31369
|
throw localPreviewOutputConflict();
|
|
30938
31370
|
}
|
|
@@ -31073,17 +31505,17 @@ async function readProtectedStateFile(target, invalidCode) {
|
|
|
31073
31505
|
}
|
|
31074
31506
|
}
|
|
31075
31507
|
async function saveSession(stateDirectory, session) {
|
|
31076
|
-
await
|
|
31508
|
+
await mkdir5(stateDirectory, { mode: 448, recursive: true });
|
|
31077
31509
|
await chmod(stateDirectory, 448);
|
|
31078
31510
|
const target = sessionPath(stateDirectory);
|
|
31079
31511
|
const temporary = `${target}.${process.pid}.tmp`;
|
|
31080
|
-
await
|
|
31512
|
+
await writeFile3(temporary, `${JSON.stringify(session)}
|
|
31081
31513
|
`, {
|
|
31082
31514
|
encoding: "utf8",
|
|
31083
31515
|
mode: 384
|
|
31084
31516
|
});
|
|
31085
31517
|
await chmod(temporary, 384);
|
|
31086
|
-
await
|
|
31518
|
+
await rename3(temporary, target);
|
|
31087
31519
|
await chmod(target, 384);
|
|
31088
31520
|
}
|
|
31089
31521
|
async function readSessionValue(stateDirectory) {
|
|
@@ -31206,17 +31638,17 @@ async function loadOrCreateDeviceIdentity(stateDirectory) {
|
|
|
31206
31638
|
publicKeyFingerprint: keyPair.publicKeyFingerprint,
|
|
31207
31639
|
publicKeyPem: keyPair.publicKeyPem
|
|
31208
31640
|
};
|
|
31209
|
-
await
|
|
31641
|
+
await mkdir5(stateDirectory, { mode: 448, recursive: true });
|
|
31210
31642
|
await chmod(stateDirectory, 448);
|
|
31211
31643
|
const target = deviceIdentityPath(stateDirectory);
|
|
31212
31644
|
const temporary = `${target}.${process.pid}.tmp`;
|
|
31213
|
-
await
|
|
31645
|
+
await writeFile3(temporary, `${JSON.stringify(identity)}
|
|
31214
31646
|
`, {
|
|
31215
31647
|
encoding: "utf8",
|
|
31216
31648
|
mode: 384
|
|
31217
31649
|
});
|
|
31218
31650
|
await chmod(temporary, 384);
|
|
31219
|
-
await
|
|
31651
|
+
await rename3(temporary, target);
|
|
31220
31652
|
await chmod(target, 384);
|
|
31221
31653
|
return { created: true, identity };
|
|
31222
31654
|
}
|
|
@@ -32292,28 +32724,36 @@ ${session.authorizationUrl}
|
|
|
32292
32724
|
};
|
|
32293
32725
|
|
|
32294
32726
|
// apps/cli/src/workflow-delivery.ts
|
|
32295
|
-
import { createHash as
|
|
32727
|
+
import { createHash as createHash8 } from "node:crypto";
|
|
32296
32728
|
import path9 from "node:path";
|
|
32297
32729
|
|
|
32298
32730
|
// apps/cli/src/workflow.ts
|
|
32299
|
-
import {
|
|
32731
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
32732
|
+
import { lstat as lstat6, readFile as readFile4 } from "node:fs/promises";
|
|
32300
32733
|
import path8 from "node:path";
|
|
32301
32734
|
var import_yaml4 = __toESM(require_dist(), 1);
|
|
32302
32735
|
var WORKFLOW_STATE_FILE = ".dxc/workflow.json";
|
|
32303
32736
|
var WORKFLOW_STATE_MAXIMUM_BYTES = 16 * 1024;
|
|
32304
32737
|
var ARTIFACT_MAXIMUM_BYTES = 5 * 1024 * 1024;
|
|
32305
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";
|
|
32306
32741
|
var WorkflowCliError = class extends Error {
|
|
32307
|
-
constructor(code, message) {
|
|
32742
|
+
constructor(code, message, details) {
|
|
32308
32743
|
super(message);
|
|
32309
32744
|
this.code = code;
|
|
32745
|
+
this.details = details;
|
|
32310
32746
|
this.name = "WorkflowCliError";
|
|
32311
32747
|
}
|
|
32312
32748
|
code;
|
|
32749
|
+
details;
|
|
32313
32750
|
};
|
|
32314
32751
|
function isRecord(value) {
|
|
32315
32752
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
32316
32753
|
}
|
|
32754
|
+
function sha2562(value) {
|
|
32755
|
+
return createHash7("sha256").update(value).digest("hex");
|
|
32756
|
+
}
|
|
32317
32757
|
function workflowState(value, projectId) {
|
|
32318
32758
|
if (!isRecord(value) || value["version"] !== 1 || value["projectId"] !== projectId) {
|
|
32319
32759
|
return void 0;
|
|
@@ -32334,11 +32774,7 @@ function statePath(directory) {
|
|
|
32334
32774
|
return path8.join(directory, WORKFLOW_STATE_FILE);
|
|
32335
32775
|
}
|
|
32336
32776
|
function projectSummary(location) {
|
|
32337
|
-
return {
|
|
32338
|
-
directory: location.directory,
|
|
32339
|
-
projectId: location.manifest.projectId,
|
|
32340
|
-
title: location.manifest.title
|
|
32341
|
-
};
|
|
32777
|
+
return { projectId: location.manifest.projectId, title: location.manifest.title };
|
|
32342
32778
|
}
|
|
32343
32779
|
function nextStep(lastCompletedStep) {
|
|
32344
32780
|
const nextIndex = lastCompletedStep === null ? 0 : CONTENT_ARTIFACT_KINDS.indexOf(lastCompletedStep) + 1;
|
|
@@ -32349,23 +32785,16 @@ function previousStep(step) {
|
|
|
32349
32785
|
return index <= 0 ? null : CONTENT_ARTIFACT_KINDS[index - 1] ?? null;
|
|
32350
32786
|
}
|
|
32351
32787
|
function requestedStep(value) {
|
|
32352
|
-
|
|
32353
|
-
if (!CONTENT_ARTIFACT_KINDS.includes(step)) {
|
|
32788
|
+
if (!CONTENT_ARTIFACT_KINDS.includes(value)) {
|
|
32354
32789
|
throw new WorkflowCliError(
|
|
32355
32790
|
"DXC_WORKFLOW_STEP_INVALID",
|
|
32356
|
-
`\u672A\u77E5\u9636\u6BB5 ${
|
|
32791
|
+
`\u672A\u77E5\u9636\u6BB5 ${value}\u3002\u8BF7\u4F7F\u7528 ${CONTENT_ARTIFACT_KINDS.join("\u3001")}\u3002`
|
|
32357
32792
|
);
|
|
32358
32793
|
}
|
|
32359
|
-
return
|
|
32360
|
-
}
|
|
32361
|
-
function inputPaths(directory, manifest, step) {
|
|
32362
|
-
const inputs = CONTENT_STAGE_INPUTS[step];
|
|
32363
|
-
return [...inputs.required, ...inputs.optional].map(
|
|
32364
|
-
(kind) => path8.join(directory, manifest.artifacts[kind])
|
|
32365
|
-
);
|
|
32794
|
+
return value;
|
|
32366
32795
|
}
|
|
32367
32796
|
function requiresStageConfirmation(policy, step) {
|
|
32368
|
-
if (step ===
|
|
32797
|
+
if (step === "delivery" || policy === "auto-until-delivery") {
|
|
32369
32798
|
return false;
|
|
32370
32799
|
}
|
|
32371
32800
|
if (policy === "review-every-stage") {
|
|
@@ -32385,71 +32814,264 @@ function stageLabel(step) {
|
|
|
32385
32814
|
"visual-plan": "\u56FE\u7247\u548C\u89C6\u89C9\u7ED3\u679C"
|
|
32386
32815
|
}[step];
|
|
32387
32816
|
}
|
|
32388
|
-
function
|
|
32389
|
-
const
|
|
32390
|
-
|
|
32391
|
-
|
|
32392
|
-
|
|
32393
|
-
|
|
32394
|
-
|
|
32395
|
-
|
|
32396
|
-
|
|
32397
|
-
|
|
32398
|
-
}
|
|
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
|
+
}
|
|
32828
|
+
}
|
|
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]);
|
|
32399
32835
|
}
|
|
32400
|
-
async function readArtifact(
|
|
32401
|
-
const target = path8.resolve(directory,
|
|
32402
|
-
const relative = path8.relative(directory, target);
|
|
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);
|
|
32403
32839
|
if (relative.startsWith("..") || path8.isAbsolute(relative)) {
|
|
32404
|
-
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
|
+
);
|
|
32405
32845
|
}
|
|
32406
32846
|
try {
|
|
32407
|
-
const metadata = await
|
|
32847
|
+
const metadata = await lstat6(target);
|
|
32408
32848
|
if (!metadata.isFile() || metadata.isSymbolicLink() || metadata.size === 0 || metadata.size > ARTIFACT_MAXIMUM_BYTES) {
|
|
32409
32849
|
throw new WorkflowCliError(
|
|
32410
32850
|
"DXC_WORKFLOW_ARTIFACT_INVALID",
|
|
32411
|
-
|
|
32851
|
+
`${kind} \u4EA7\u7269\u4E3A\u7A7A\u3001\u8FC7\u5927\u6216\u4E0D\u662F\u666E\u901A\u6587\u4EF6\u3002`,
|
|
32852
|
+
{ path: target, stage: kind }
|
|
32412
32853
|
);
|
|
32413
32854
|
}
|
|
32414
|
-
return await
|
|
32855
|
+
return await readFile4(target, "utf8");
|
|
32415
32856
|
} catch (error) {
|
|
32416
32857
|
if (error instanceof WorkflowCliError) {
|
|
32417
32858
|
throw error;
|
|
32418
32859
|
}
|
|
32419
|
-
throw new WorkflowCliError(
|
|
32420
|
-
|
|
32421
|
-
|
|
32422
|
-
);
|
|
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
|
+
});
|
|
32423
32864
|
}
|
|
32424
32865
|
}
|
|
32425
|
-
function
|
|
32426
|
-
const
|
|
32427
|
-
|
|
32428
|
-
|
|
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
|
+
});
|
|
32429
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
|
+
`;
|
|
32933
|
+
}
|
|
32934
|
+
}
|
|
32935
|
+
async function ensureStageScaffold(location, stage) {
|
|
32936
|
+
if (stage === "delivery") {
|
|
32937
|
+
return "not-applicable";
|
|
32938
|
+
}
|
|
32939
|
+
const target = artifactPath(location, stage);
|
|
32430
32940
|
try {
|
|
32431
|
-
const
|
|
32432
|
-
|
|
32433
|
-
|
|
32434
|
-
|
|
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
|
+
}
|
|
32435
32956
|
}
|
|
32957
|
+
await writePrivateBuffer(target, Buffer.from(stageScaffold(stage, location.manifest.title)));
|
|
32958
|
+
return "created";
|
|
32436
32959
|
}
|
|
32437
|
-
function
|
|
32438
|
-
|
|
32439
|
-
|
|
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));
|
|
33011
|
+
}
|
|
33012
|
+
function cursorFingerprint(state) {
|
|
33013
|
+
return sha2562(JSON.stringify(state));
|
|
32440
33014
|
}
|
|
32441
|
-
|
|
32442
|
-
|
|
32443
|
-
|
|
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");
|
|
33026
|
+
}
|
|
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");
|
|
32444
33045
|
}
|
|
32445
|
-
|
|
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") {
|
|
32446
33067
|
let article;
|
|
32447
33068
|
try {
|
|
32448
33069
|
article = parseArticleDocument(source);
|
|
32449
33070
|
} catch {
|
|
32450
33071
|
throw new WorkflowCliError(
|
|
32451
33072
|
"DXC_WORKFLOW_ARTIFACT_INVALID",
|
|
32452
|
-
"\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 }
|
|
32453
33075
|
);
|
|
32454
33076
|
}
|
|
32455
33077
|
const lengths = {
|
|
@@ -32461,62 +33083,41 @@ async function validateStageResult(step, source, location) {
|
|
|
32461
33083
|
if (invalid !== void 0) {
|
|
32462
33084
|
throw new WorkflowCliError(
|
|
32463
33085
|
"DXC_WORKFLOW_ARTICLE_FIELD_INVALID",
|
|
32464
|
-
`${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 }
|
|
32465
33088
|
);
|
|
32466
33089
|
}
|
|
32467
33090
|
}
|
|
32468
|
-
if (
|
|
33091
|
+
if (stage === "titles") {
|
|
32469
33092
|
const title = selectedTitle(frontmatter(source));
|
|
32470
|
-
if (title === void 0 || [...title].length >
|
|
33093
|
+
if (title === void 0 || [...title].length > WECHAT_TITLE_CHARACTER_LIMIT) {
|
|
32471
33094
|
throw new WorkflowCliError(
|
|
32472
33095
|
"DXC_WORKFLOW_ARTIFACT_INVALID",
|
|
32473
|
-
|
|
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 }
|
|
32474
33098
|
);
|
|
32475
33099
|
}
|
|
32476
33100
|
}
|
|
32477
|
-
if (
|
|
32478
|
-
const
|
|
32479
|
-
|
|
32480
|
-
|
|
32481
|
-
|
|
32482
|
-
|
|
32483
|
-
);
|
|
32484
|
-
}
|
|
32485
|
-
const articleSource = await readArtifact(
|
|
32486
|
-
location.directory,
|
|
32487
|
-
location.manifest.artifacts.article
|
|
32488
|
-
);
|
|
32489
|
-
try {
|
|
32490
|
-
await validateWorkflowVisualPlan({
|
|
32491
|
-
articleSource,
|
|
32492
|
-
assetsDirectory: path8.join(location.directory, location.manifest.assetsDirectory),
|
|
32493
|
-
projectDirectory: location.directory,
|
|
32494
|
-
visualPlanFile: path8.join(location.directory, location.manifest.artifacts["visual-plan"]),
|
|
32495
|
-
visualPlanSource: source
|
|
32496
|
-
});
|
|
32497
|
-
} catch (error) {
|
|
32498
|
-
if (error instanceof WechatCliError) {
|
|
32499
|
-
throw new WorkflowCliError(error.code, error.guidance ?? error.message);
|
|
32500
|
-
}
|
|
32501
|
-
throw error;
|
|
32502
|
-
}
|
|
33101
|
+
if (stage === "visual-plan") {
|
|
33102
|
+
const articleSource = await readArtifact(location, "article");
|
|
33103
|
+
validateWorkflowSemanticVisualPlan({
|
|
33104
|
+
sections: parseWorkflowArticleSections(articleSource),
|
|
33105
|
+
source
|
|
33106
|
+
});
|
|
32503
33107
|
}
|
|
32504
|
-
if (
|
|
33108
|
+
if (stage === "quality-review" && frontmatter(source)["verdict"] !== "pass") {
|
|
32505
33109
|
throw new WorkflowCliError(
|
|
32506
33110
|
"DXC_WORKFLOW_ARTIFACT_INVALID",
|
|
32507
|
-
"\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 }
|
|
32508
33113
|
);
|
|
32509
33114
|
}
|
|
32510
33115
|
}
|
|
32511
33116
|
var WorkflowCli = class {
|
|
32512
|
-
#currentDirectory;
|
|
32513
|
-
#homeDirectory;
|
|
32514
33117
|
#now;
|
|
32515
33118
|
#profile;
|
|
32516
33119
|
#projects;
|
|
32517
33120
|
constructor(input) {
|
|
32518
|
-
this.#currentDirectory = input.currentDirectory;
|
|
32519
|
-
this.#homeDirectory = input.homeDirectory;
|
|
32520
33121
|
this.#now = input.now ?? (() => /* @__PURE__ */ new Date());
|
|
32521
33122
|
this.#profile = new ProfileCli({
|
|
32522
33123
|
currentDirectory: input.currentDirectory,
|
|
@@ -32533,15 +33134,6 @@ var WorkflowCli = class {
|
|
|
32533
33134
|
const status = await this.#profile.status();
|
|
32534
33135
|
return status.data.configured ? status.data.profile.user.confirmationPolicy : "guided";
|
|
32535
33136
|
}
|
|
32536
|
-
async #locate(directory, projectId) {
|
|
32537
|
-
if (directory !== void 0 && projectId !== void 0) {
|
|
32538
|
-
throw new WorkflowCliError(
|
|
32539
|
-
"DXC_WORKFLOW_PROJECT_REFERENCE_INVALID",
|
|
32540
|
-
"\u9879\u76EE\u76EE\u5F55\u548C\u9879\u76EE ID \u53EA\u80FD\u6307\u5B9A\u4E00\u4E2A\u3002"
|
|
32541
|
-
);
|
|
32542
|
-
}
|
|
32543
|
-
return projectId === void 0 ? this.#projects.locate(directory) : this.#projects.locateByProjectId(projectId);
|
|
32544
|
-
}
|
|
32545
33137
|
async #loadState(location, persistMigration = true, migrationUpdatedAt = this.#now().toISOString()) {
|
|
32546
33138
|
try {
|
|
32547
33139
|
const raw = await readPrivateFile(
|
|
@@ -32596,79 +33188,328 @@ var WorkflowCli = class {
|
|
|
32596
33188
|
}
|
|
32597
33189
|
return migrated;
|
|
32598
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
|
+
}
|
|
32599
33386
|
async start(options) {
|
|
32600
|
-
if (options.
|
|
33387
|
+
if (options.projectId !== void 0 && (options.directory !== void 0 || options.title !== void 0)) {
|
|
32601
33388
|
throw new WorkflowCliError(
|
|
32602
33389
|
"DXC_WORKFLOW_PROJECT_REFERENCE_INVALID",
|
|
32603
|
-
"\u9879\u76EE\
|
|
33390
|
+
"\u5DF2\u6709\u9879\u76EE\u53EA\u80FD\u4F7F\u7528 --project\uFF0C\u4E0D\u63A5\u53D7\u6807\u9898\u6216\u76EE\u5F55\u3002"
|
|
32604
33391
|
);
|
|
32605
33392
|
}
|
|
32606
|
-
const directory = options.directory === void 0 ? void 0 : resolveUserPath({
|
|
32607
|
-
currentDirectory: this.#currentDirectory,
|
|
32608
|
-
homeDirectory: this.#homeDirectory,
|
|
32609
|
-
input: options.directory
|
|
32610
|
-
});
|
|
32611
33393
|
const requested = options.from === void 0 ? void 0 : requestedStep(options.from);
|
|
32612
33394
|
let location;
|
|
33395
|
+
let existingState;
|
|
32613
33396
|
if (options.projectId !== void 0) {
|
|
32614
33397
|
location = await this.#projects.locateByProjectId(options.projectId);
|
|
32615
|
-
|
|
32616
|
-
|
|
32617
|
-
location
|
|
32618
|
-
} catch (error) {
|
|
32619
|
-
if (!(error instanceof ProjectCliError) || error.code !== "DXC_PROJECT_NOT_FOUND") {
|
|
32620
|
-
throw error;
|
|
32621
|
-
}
|
|
32622
|
-
if (options.title === void 0 || options.title.trim().length === 0) {
|
|
32623
|
-
throw new WorkflowCliError(
|
|
32624
|
-
"DXC_WORKFLOW_TITLE_REQUIRED",
|
|
32625
|
-
"\u521B\u5EFA\u65B0\u9879\u76EE\u65F6\u9700\u8981\u63D0\u4F9B\u6587\u7AE0\u4E3B\u9898\u3002"
|
|
32626
|
-
);
|
|
32627
|
-
}
|
|
32628
|
-
const initialized = await this.#projects.initialize(directory, options.title);
|
|
32629
|
-
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));
|
|
32630
33401
|
}
|
|
32631
33402
|
} else {
|
|
32632
33403
|
if (options.title === void 0 || options.title.trim().length === 0) {
|
|
32633
33404
|
throw new WorkflowCliError("DXC_WORKFLOW_TITLE_REQUIRED", "\u521B\u5EFA\u65B0\u9879\u76EE\u65F6\u9700\u8981\u63D0\u4F9B\u6587\u7AE0\u4E3B\u9898\u3002");
|
|
32634
33405
|
}
|
|
32635
|
-
const initialized = await this.#projects.initialize(
|
|
33406
|
+
const initialized = await this.#projects.initialize(options.directory, options.title);
|
|
32636
33407
|
location = { directory: initialized.data.directory, manifest: initialized.data.manifest };
|
|
32637
33408
|
}
|
|
32638
|
-
|
|
32639
|
-
const state2 = await this.#loadState(location);
|
|
32640
|
-
const confirmationPolicy2 = await this.#confirmationPolicy();
|
|
32641
|
-
return {
|
|
32642
|
-
command: "workflow.next",
|
|
32643
|
-
data: { match: "ready", work: workItem(location, state2, confirmationPolicy2) },
|
|
32644
|
-
ok: true
|
|
32645
|
-
};
|
|
32646
|
-
}
|
|
32647
|
-
if (requested === void 0 && directory !== void 0) {
|
|
32648
|
-
const state2 = await this.#loadState(location);
|
|
32649
|
-
if (state2.lastCompletedStep !== null) {
|
|
32650
|
-
const confirmationPolicy2 = await this.#confirmationPolicy();
|
|
32651
|
-
return {
|
|
32652
|
-
command: "workflow.next",
|
|
32653
|
-
data: { match: "ready", work: workItem(location, state2, confirmationPolicy2) },
|
|
32654
|
-
ok: true
|
|
32655
|
-
};
|
|
32656
|
-
}
|
|
32657
|
-
}
|
|
32658
|
-
const step = requested ?? "research";
|
|
33409
|
+
const stage = requested ?? "research";
|
|
32659
33410
|
const state = {
|
|
32660
|
-
lastCompletedStep: previousStep(
|
|
33411
|
+
lastCompletedStep: previousStep(stage),
|
|
32661
33412
|
projectId: location.manifest.projectId,
|
|
32662
|
-
updatedAt: this.#
|
|
33413
|
+
updatedAt: this.#nextTimestamp(existingState?.updatedAt),
|
|
32663
33414
|
version: 1
|
|
32664
33415
|
};
|
|
32665
33416
|
await writePrivateJson(statePath(location.directory), state);
|
|
32666
|
-
|
|
32667
|
-
|
|
32668
|
-
|
|
32669
|
-
|
|
32670
|
-
|
|
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)
|
|
32671
33510
|
};
|
|
33511
|
+
await writePrivateJson(statePath(location.directory), nextState);
|
|
33512
|
+
return this.#result(location, await this.#stagePayload(location, nextState));
|
|
32672
33513
|
}
|
|
32673
33514
|
async listProjects() {
|
|
32674
33515
|
const projects = [];
|
|
@@ -32690,6 +33531,7 @@ var WorkflowCli = class {
|
|
|
32690
33531
|
projects.push({
|
|
32691
33532
|
...projectSummary(indexed.location),
|
|
32692
33533
|
available: true,
|
|
33534
|
+
directory: indexed.location.directory,
|
|
32693
33535
|
done: step === null,
|
|
32694
33536
|
step,
|
|
32695
33537
|
updatedAt: state.updatedAt
|
|
@@ -32698,96 +33540,82 @@ var WorkflowCli = class {
|
|
|
32698
33540
|
projects.sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
|
|
32699
33541
|
return { command: "project.list", data: { projects }, ok: true };
|
|
32700
33542
|
}
|
|
32701
|
-
async
|
|
32702
|
-
const
|
|
32703
|
-
if (
|
|
32704
|
-
|
|
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");
|
|
32705
33547
|
}
|
|
32706
|
-
|
|
32707
|
-
|
|
32708
|
-
|
|
32709
|
-
|
|
32710
|
-
|
|
32711
|
-
};
|
|
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");
|
|
32712
33553
|
}
|
|
32713
|
-
|
|
32714
|
-
|
|
32715
|
-
|
|
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
|
+
);
|
|
32716
33571
|
}
|
|
32717
|
-
const state = await this.#loadState(location);
|
|
32718
|
-
const confirmationPolicy = await this.#confirmationPolicy();
|
|
32719
33572
|
return {
|
|
32720
|
-
|
|
32721
|
-
|
|
32722
|
-
|
|
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
|
|
32723
33582
|
};
|
|
32724
33583
|
}
|
|
32725
|
-
async
|
|
32726
|
-
const
|
|
32727
|
-
|
|
32728
|
-
|
|
32729
|
-
const step = nextStep(state.lastCompletedStep);
|
|
32730
|
-
if (step === null) {
|
|
32731
|
-
return {
|
|
32732
|
-
command: "workflow.next",
|
|
32733
|
-
data: { match: "ready", work: workItem(location, state, confirmationPolicy) },
|
|
32734
|
-
ok: true
|
|
32735
|
-
};
|
|
32736
|
-
}
|
|
32737
|
-
if (step === "delivery") {
|
|
32738
|
-
throw new WorkflowCliError(
|
|
32739
|
-
"DXC_WORKFLOW_DELIVERY_REQUIRED",
|
|
32740
|
-
"\u5185\u5BB9\u5DF2\u7ECF\u51C6\u5907\u5B8C\u6210\uFF1B\u8BF7\u751F\u6210\u5FAE\u4FE1\u9884\u89C8\u5E76\u786E\u8BA4\u4EA4\u4ED8\u3002"
|
|
32741
|
-
);
|
|
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");
|
|
32742
33588
|
}
|
|
32743
|
-
const
|
|
32744
|
-
|
|
32745
|
-
|
|
32746
|
-
|
|
32747
|
-
"
|
|
32748
|
-
|
|
32749
|
-
)
|
|
32750
|
-
|
|
32751
|
-
const nextState = {
|
|
32752
|
-
...state,
|
|
32753
|
-
lastCompletedStep: step,
|
|
32754
|
-
updatedAt: this.#now().toISOString()
|
|
32755
|
-
};
|
|
32756
|
-
await writePrivateJson(statePath(location.directory), nextState);
|
|
32757
|
-
return {
|
|
32758
|
-
command: "workflow.next",
|
|
32759
|
-
data: { match: "ready", work: workItem(location, nextState, confirmationPolicy) },
|
|
32760
|
-
ok: true
|
|
33589
|
+
const payload = {
|
|
33590
|
+
...await this.#basePayload(
|
|
33591
|
+
resolved.location,
|
|
33592
|
+
resolved.state,
|
|
33593
|
+
"delivery",
|
|
33594
|
+
"delivery-confirm"
|
|
33595
|
+
),
|
|
33596
|
+
bindingFingerprint
|
|
32761
33597
|
};
|
|
33598
|
+
return this.#result(resolved.location, payload, true, {
|
|
33599
|
+
expiresAt,
|
|
33600
|
+
type: "confirm-delivery"
|
|
33601
|
+
});
|
|
32762
33602
|
}
|
|
32763
|
-
async
|
|
32764
|
-
const
|
|
32765
|
-
|
|
32766
|
-
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) {
|
|
32767
33606
|
throw new WorkflowCliError(
|
|
32768
|
-
"
|
|
32769
|
-
"\
|
|
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"
|
|
32770
33609
|
);
|
|
32771
33610
|
}
|
|
32772
|
-
|
|
32773
|
-
const title = selectedTitle(frontmatter(titleSource));
|
|
32774
|
-
return {
|
|
32775
|
-
articleFile: path8.join(location.directory, location.manifest.artifacts.article),
|
|
32776
|
-
assetsDirectory: path8.join(location.directory, location.manifest.assetsDirectory),
|
|
32777
|
-
project: projectSummary(location),
|
|
32778
|
-
projectDirectory: location.directory,
|
|
32779
|
-
title,
|
|
32780
|
-
visualPlanFile: path8.join(location.directory, location.manifest.artifacts["visual-plan"])
|
|
32781
|
-
};
|
|
33611
|
+
return this.deliveryInputs(workItemId);
|
|
32782
33612
|
}
|
|
32783
|
-
async completeDelivery(
|
|
32784
|
-
const
|
|
32785
|
-
|
|
32786
|
-
|
|
32787
|
-
if (nextStep(state.lastCompletedStep) !== "delivery") {
|
|
32788
|
-
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");
|
|
32789
33617
|
}
|
|
32790
|
-
const deliveryFile =
|
|
33618
|
+
const deliveryFile = artifactPath(resolved.location, "delivery");
|
|
32791
33619
|
await writePrivateBuffer(
|
|
32792
33620
|
deliveryFile,
|
|
32793
33621
|
Buffer.from(
|
|
@@ -32795,22 +33623,12 @@ var WorkflowCli = class {
|
|
|
32795
33623
|
|
|
32796
33624
|
- intentId: ${receipt.intentId}
|
|
32797
33625
|
- mediaId: ${receipt.mediaId}
|
|
32798
|
-
- completedAt: ${this.#
|
|
33626
|
+
- completedAt: ${this.#nextTimestamp(resolved.state.updatedAt)}
|
|
32799
33627
|
`,
|
|
32800
33628
|
"utf8"
|
|
32801
33629
|
)
|
|
32802
33630
|
);
|
|
32803
|
-
|
|
32804
|
-
...state,
|
|
32805
|
-
lastCompletedStep: "delivery",
|
|
32806
|
-
updatedAt: this.#now().toISOString()
|
|
32807
|
-
};
|
|
32808
|
-
await writePrivateJson(statePath(location.directory), nextState);
|
|
32809
|
-
return {
|
|
32810
|
-
command: "workflow.next",
|
|
32811
|
-
data: { match: "ready", work: workItem(location, nextState, confirmationPolicy) },
|
|
32812
|
-
ok: true
|
|
32813
|
-
};
|
|
33631
|
+
return this.#advance(resolved.location, resolved.state, "delivery");
|
|
32814
33632
|
}
|
|
32815
33633
|
};
|
|
32816
33634
|
|
|
@@ -32818,15 +33636,21 @@ var WorkflowCli = class {
|
|
|
32818
33636
|
var DELIVERY_STATE_FILE = ".dxc/delivery.json";
|
|
32819
33637
|
var DELIVERY_STATE_MAXIMUM_BYTES = 32 * 1024;
|
|
32820
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
|
+
}
|
|
32821
33643
|
function selectedDraftIdempotencyKey(projectId, rootSnapshotHash, selectedSnapshotHash, selectionRevision) {
|
|
32822
|
-
const selectionDigest =
|
|
33644
|
+
const selectionDigest = sha2563(
|
|
33645
|
+
`${rootSnapshotHash}:${selectedSnapshotHash}:${selectionRevision}`
|
|
33646
|
+
);
|
|
32823
33647
|
return `dxc:${projectId}:${selectionDigest}`;
|
|
32824
33648
|
}
|
|
32825
33649
|
function isRecord2(value) {
|
|
32826
33650
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
32827
33651
|
}
|
|
32828
33652
|
function deliveryState(value) {
|
|
32829
|
-
if (!isRecord2(value) || value["version"] !== 1) {
|
|
33653
|
+
if (!isRecord2(value) || value["version"] !== 1 && value["version"] !== 2) {
|
|
32830
33654
|
return void 0;
|
|
32831
33655
|
}
|
|
32832
33656
|
const required = [
|
|
@@ -32846,26 +33670,81 @@ function deliveryState(value) {
|
|
|
32846
33670
|
if (value["intentId"] !== void 0 && typeof value["intentId"] !== "string") {
|
|
32847
33671
|
return void 0;
|
|
32848
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
|
+
}
|
|
32849
33676
|
return value;
|
|
32850
33677
|
}
|
|
32851
|
-
function accountChoice(account) {
|
|
32852
|
-
return { id: account.id, name: account.displayName };
|
|
32853
|
-
}
|
|
32854
33678
|
function availableAccounts(accounts) {
|
|
32855
33679
|
return accounts.filter(
|
|
32856
33680
|
(account) => account.status === "ACTIVE" && account.draftCapability === "available" && account.permissions.includes(11)
|
|
32857
33681
|
);
|
|
32858
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
|
+
}
|
|
32859
33741
|
var WorkflowDeliveryCli = class {
|
|
32860
33742
|
#output;
|
|
32861
33743
|
#sleep;
|
|
32862
33744
|
#wechat;
|
|
32863
33745
|
#workflow;
|
|
32864
33746
|
constructor(input) {
|
|
32865
|
-
this.#output = {
|
|
32866
|
-
writeStderr: input.output.writeStderr,
|
|
32867
|
-
writeStdout: () => void 0
|
|
32868
|
-
};
|
|
33747
|
+
this.#output = { writeStderr: input.output.writeStderr, writeStdout: () => void 0 };
|
|
32869
33748
|
this.#sleep = input.sleep ?? ((milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)));
|
|
32870
33749
|
this.#wechat = input.wechat;
|
|
32871
33750
|
this.#workflow = input.workflow;
|
|
@@ -32903,18 +33782,50 @@ var WorkflowDeliveryCli = class {
|
|
|
32903
33782
|
async #writeState(projectDirectory, state) {
|
|
32904
33783
|
await writePrivateJson(path9.join(projectDirectory, DELIVERY_STATE_FILE), state);
|
|
32905
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
|
+
}
|
|
32906
33810
|
async preview(options) {
|
|
32907
|
-
const inputs = await this.#workflow.deliveryInputs(options.
|
|
33811
|
+
const inputs = await this.#workflow.deliveryInputs(options.workItemId);
|
|
32908
33812
|
const existingState = await this.#readStateIfPresent(inputs.projectDirectory);
|
|
32909
33813
|
if (existingState?.projectId === inputs.project.projectId && existingState.intentId !== void 0) {
|
|
32910
|
-
|
|
32911
|
-
|
|
32912
|
-
|
|
32913
|
-
|
|
32914
|
-
|
|
32915
|
-
|
|
32916
|
-
`\u5F53\u524D\u9879\u76EE\u4ECD\u7ED1\u5B9A\u8349\u7A3F\u610F\u56FE ${existing.intent.id}\uFF08${existing.intent.status}\uFF09\uFF1B\u5DF2\u4FDD\u7559\u539F\u4EA4\u4ED8\u72B6\u6001\u4E14\u672A\u751F\u6210\u65B0\u9884\u89C8\u3002\u8BF7\u7EE7\u7EED\u6267\u884C workflow deliver --confirm\uFF0C\u8BA9 CLI \u53EA\u8BFB\u56DE\u8BFB\u3001\u8BCA\u65AD\u6216\u5B8C\u6210\u539F\u610F\u56FE\u3002`
|
|
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
|
|
32917
33820
|
);
|
|
33821
|
+
return {
|
|
33822
|
+
command: "workflow.preview",
|
|
33823
|
+
data: {
|
|
33824
|
+
...confirmation2.data,
|
|
33825
|
+
status: "needs-attention"
|
|
33826
|
+
},
|
|
33827
|
+
ok: true
|
|
33828
|
+
};
|
|
32918
33829
|
}
|
|
32919
33830
|
const accounts = availableAccounts(await this.#wechat.accounts(this.#output));
|
|
32920
33831
|
if (accounts.length === 0) {
|
|
@@ -32923,9 +33834,10 @@ var WorkflowDeliveryCli = class {
|
|
|
32923
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"
|
|
32924
33835
|
);
|
|
32925
33836
|
}
|
|
32926
|
-
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);
|
|
32927
33839
|
if (account === void 0) {
|
|
32928
|
-
if (
|
|
33840
|
+
if (accountId !== void 0) {
|
|
32929
33841
|
throw new WechatCliError(
|
|
32930
33842
|
"DXC_PUBLISHING_ACCOUNT_UNAVAILABLE",
|
|
32931
33843
|
"\u9009\u62E9\u7684\u516C\u4F17\u53F7\u5F53\u524D\u4E0D\u53EF\u7528\u4E8E\u521B\u5EFA\u8349\u7A3F\u3002"
|
|
@@ -32934,17 +33846,15 @@ var WorkflowDeliveryCli = class {
|
|
|
32934
33846
|
return {
|
|
32935
33847
|
command: "workflow.preview",
|
|
32936
33848
|
data: {
|
|
32937
|
-
|
|
32938
|
-
status: "account-selection-required"
|
|
33849
|
+
project: inputs.project,
|
|
33850
|
+
status: "account-selection-required",
|
|
33851
|
+
workItem: this.#selectionWorkItem(options.workItemId, accounts)
|
|
32939
33852
|
},
|
|
32940
33853
|
ok: true
|
|
32941
33854
|
};
|
|
32942
33855
|
}
|
|
32943
33856
|
await this.#wechat.optimizeDraftImages(
|
|
32944
|
-
{
|
|
32945
|
-
projectDirectory: inputs.projectDirectory,
|
|
32946
|
-
visualPlanFile: inputs.visualPlanFile
|
|
32947
|
-
},
|
|
33857
|
+
{ projectDirectory: inputs.projectDirectory, visualPlanFile: inputs.visualPlanFile },
|
|
32948
33858
|
this.#output
|
|
32949
33859
|
);
|
|
32950
33860
|
const preview = await this.#wechat.previewDraft(
|
|
@@ -32952,14 +33862,14 @@ var WorkflowDeliveryCli = class {
|
|
|
32952
33862
|
accountId: account.id,
|
|
32953
33863
|
articleFile: inputs.articleFile,
|
|
32954
33864
|
assetsDirectory: inputs.assetsDirectory,
|
|
32955
|
-
browserMode:
|
|
33865
|
+
browserMode: "agent",
|
|
32956
33866
|
coverFile: "auto",
|
|
32957
33867
|
title: inputs.title,
|
|
32958
33868
|
visualPlanFile: inputs.visualPlanFile
|
|
32959
33869
|
},
|
|
32960
33870
|
this.#output
|
|
32961
33871
|
);
|
|
32962
|
-
await this.#
|
|
33872
|
+
const state = await this.#selectState(inputs.projectDirectory, {
|
|
32963
33873
|
accountId: account.id,
|
|
32964
33874
|
idempotencyKey: `dxc:${inputs.project.projectId}:${preview.snapshot.snapshotHash}`,
|
|
32965
33875
|
previewExpiresAt: preview.preview.expiresAt,
|
|
@@ -32969,14 +33879,14 @@ var WorkflowDeliveryCli = class {
|
|
|
32969
33879
|
rootSnapshotId: preview.snapshot.id,
|
|
32970
33880
|
version: 1
|
|
32971
33881
|
});
|
|
33882
|
+
const confirmation = await this.#workflow.issueDeliveryConfirmation(
|
|
33883
|
+
options.workItemId,
|
|
33884
|
+
deliveryBindingFingerprint(state),
|
|
33885
|
+
state.previewExpiresAt
|
|
33886
|
+
);
|
|
32972
33887
|
return {
|
|
32973
33888
|
command: "workflow.preview",
|
|
32974
|
-
data: {
|
|
32975
|
-
account: accountChoice(account),
|
|
32976
|
-
expiresAt: preview.preview.expiresAt,
|
|
32977
|
-
opened: true,
|
|
32978
|
-
status: "ready"
|
|
32979
|
-
},
|
|
33889
|
+
data: { ...confirmation.data, status: "ready" },
|
|
32980
33890
|
ok: true
|
|
32981
33891
|
};
|
|
32982
33892
|
}
|
|
@@ -33022,29 +33932,33 @@ var WorkflowDeliveryCli = class {
|
|
|
33022
33932
|
"\u8BF7\u5148\u67E5\u770B\u5FAE\u4FE1\u9884\u89C8\u5E76\u660E\u786E\u786E\u8BA4\u521B\u5EFA\u8349\u7A3F\u3002"
|
|
33023
33933
|
);
|
|
33024
33934
|
}
|
|
33025
|
-
const
|
|
33026
|
-
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
|
+
);
|
|
33027
33945
|
if (state.projectId !== inputs.project.projectId) {
|
|
33028
|
-
throw new WorkflowCliError(
|
|
33029
|
-
"DXC_WORKFLOW_DELIVERY_STATE_INVALID",
|
|
33030
|
-
"\u9884\u89C8\u4E0D\u5C5E\u4E8E\u5F53\u524D\u6587\u7AE0\uFF1B\u8BF7\u91CD\u65B0\u751F\u6210\u5FAE\u4FE1\u9884\u89C8\u3002"
|
|
33031
|
-
);
|
|
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");
|
|
33032
33947
|
}
|
|
33033
33948
|
const preview = await this.#wechat.draftPreviewStatus(
|
|
33034
33949
|
{ snapshotHash: state.rootSnapshotHash, snapshotId: state.rootSnapshotId },
|
|
33035
33950
|
this.#output
|
|
33036
33951
|
);
|
|
33037
|
-
const
|
|
33038
|
-
|
|
33039
|
-
|
|
33040
|
-
|
|
33041
|
-
|
|
33042
|
-
|
|
33043
|
-
|
|
33044
|
-
if (state.intentId === void 0 && state.idempotencyKey !== selectedIdempotencyKey) {
|
|
33045
|
-
state = { ...state, idempotencyKey: selectedIdempotencyKey };
|
|
33046
|
-
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
|
+
);
|
|
33047
33959
|
}
|
|
33960
|
+
state = current;
|
|
33961
|
+
const template = { id: state.templateId, selectionRevision: state.selectionRevision };
|
|
33048
33962
|
if (!preview.viewed) {
|
|
33049
33963
|
const refreshed = await this.#wechat.refreshDraftPreview(
|
|
33050
33964
|
{
|
|
@@ -33056,9 +33970,19 @@ var WorkflowDeliveryCli = class {
|
|
|
33056
33970
|
);
|
|
33057
33971
|
state = { ...state, previewExpiresAt: refreshed.expiresAt };
|
|
33058
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
|
+
);
|
|
33059
33978
|
return {
|
|
33060
33979
|
command: "workflow.deliver",
|
|
33061
|
-
data: {
|
|
33980
|
+
data: {
|
|
33981
|
+
expiresAt: refreshed.expiresAt,
|
|
33982
|
+
status: "preview-required",
|
|
33983
|
+
template,
|
|
33984
|
+
workItem: confirmation.data.workItem
|
|
33985
|
+
},
|
|
33062
33986
|
ok: true
|
|
33063
33987
|
};
|
|
33064
33988
|
}
|
|
@@ -33102,19 +34026,30 @@ var WorkflowDeliveryCli = class {
|
|
|
33102
34026
|
}
|
|
33103
34027
|
if (result.intent.status === "SUCCEEDED" && result.intent.mediaId !== void 0) {
|
|
33104
34028
|
const completedDiagnostics = await this.#diagnostics(result);
|
|
33105
|
-
|
|
33106
|
-
|
|
33107
|
-
|
|
33108
|
-
|
|
33109
|
-
|
|
33110
|
-
|
|
33111
|
-
|
|
33112
|
-
|
|
33113
|
-
|
|
33114
|
-
|
|
33115
|
-
|
|
33116
|
-
|
|
33117
|
-
|
|
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
|
+
}
|
|
33118
34053
|
};
|
|
33119
34054
|
}
|
|
33120
34055
|
diagnostics ??= await this.#diagnostics(result);
|
|
@@ -33163,12 +34098,6 @@ function positiveInteger(value, name = "value") {
|
|
|
33163
34098
|
}
|
|
33164
34099
|
return parsed;
|
|
33165
34100
|
}
|
|
33166
|
-
function previewBrowserMode(value) {
|
|
33167
|
-
if (value !== "agent" && value !== "system") {
|
|
33168
|
-
throw new CommanderError(1, "DXC_OPTION_INVALID", "browser must be agent or system");
|
|
33169
|
-
}
|
|
33170
|
-
return value;
|
|
33171
|
-
}
|
|
33172
34101
|
function skillInstallTarget(value) {
|
|
33173
34102
|
if (value !== "codex" && value !== "workbuddy") {
|
|
33174
34103
|
throw new CommanderError(1, "DXC_OPTION_INVALID", "target must be codex or workbuddy");
|
|
@@ -33188,10 +34117,20 @@ function actionError(error) {
|
|
|
33188
34117
|
};
|
|
33189
34118
|
}
|
|
33190
34119
|
if (error instanceof WorkflowCliError || error instanceof ProjectCliError || error instanceof ProfileCliError || error instanceof ContentMemoryCliError || error instanceof SkillInstallerError) {
|
|
33191
|
-
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
|
+
};
|
|
33192
34126
|
}
|
|
33193
34127
|
if (error instanceof Error && error.name === "KnowledgeCliError" && "code" in error) {
|
|
33194
|
-
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
|
+
};
|
|
33195
34134
|
}
|
|
33196
34135
|
return {
|
|
33197
34136
|
code: "DXC_COMMAND_FAILED",
|
|
@@ -33226,7 +34165,7 @@ async function loadKnowledgeModule() {
|
|
|
33226
34165
|
}
|
|
33227
34166
|
};
|
|
33228
34167
|
try {
|
|
33229
|
-
return await import("./chunks/knowledge-
|
|
34168
|
+
return await import("./chunks/knowledge-JCYMCMSP.js");
|
|
33230
34169
|
} finally {
|
|
33231
34170
|
process.emitWarning = emitWarning;
|
|
33232
34171
|
}
|
|
@@ -33317,24 +34256,27 @@ function createProgram(context) {
|
|
|
33317
34256
|
})
|
|
33318
34257
|
)
|
|
33319
34258
|
);
|
|
33320
|
-
workflow.command("next").description("\u8FD4\u56DE\u552F\u4E00\u9700\u8981\u6267\u884C\u7684\u4E0B\u4E00\u6B65").
|
|
33321
|
-
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(
|
|
33322
34261
|
context,
|
|
33323
34262
|
options.json === true,
|
|
33324
34263
|
() => new WorkflowCli({
|
|
33325
34264
|
currentDirectory: context.currentDirectory,
|
|
33326
34265
|
homeDirectory: context.homeDirectory
|
|
33327
|
-
}).next(
|
|
34266
|
+
}).next({
|
|
34267
|
+
...options.project === void 0 ? {} : { projectId: options.project },
|
|
34268
|
+
...options.workItem === void 0 ? {} : { workItemId: options.workItem }
|
|
34269
|
+
})
|
|
33328
34270
|
)
|
|
33329
34271
|
);
|
|
33330
|
-
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(
|
|
33331
34273
|
async (options) => runAction(
|
|
33332
34274
|
context,
|
|
33333
34275
|
options.json === true,
|
|
33334
34276
|
() => new WorkflowCli({
|
|
33335
34277
|
currentDirectory: context.currentDirectory,
|
|
33336
34278
|
homeDirectory: context.homeDirectory
|
|
33337
|
-
}).complete(options.
|
|
34279
|
+
}).complete(options.workItem, options.confirm === true)
|
|
33338
34280
|
)
|
|
33339
34281
|
);
|
|
33340
34282
|
const deliveryAction = async (json, action) => runAction(context, json, () => {
|
|
@@ -33350,24 +34292,21 @@ function createProgram(context) {
|
|
|
33350
34292
|
})
|
|
33351
34293
|
);
|
|
33352
34294
|
});
|
|
33353
|
-
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(
|
|
33354
34296
|
async (options) => deliveryAction(
|
|
33355
34297
|
options.json === true,
|
|
33356
34298
|
(delivery) => delivery.preview({
|
|
33357
|
-
...options.
|
|
33358
|
-
|
|
33359
|
-
...options.directory === void 0 ? {} : { directory: options.directory },
|
|
33360
|
-
...options.project === void 0 ? {} : { projectId: options.project }
|
|
34299
|
+
...options.choice === void 0 ? {} : { choiceId: options.choice },
|
|
34300
|
+
workItemId: options.workItem
|
|
33361
34301
|
})
|
|
33362
34302
|
)
|
|
33363
34303
|
);
|
|
33364
|
-
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(
|
|
33365
34305
|
async (options) => deliveryAction(
|
|
33366
34306
|
options.json === true,
|
|
33367
34307
|
(delivery) => delivery.deliver({
|
|
33368
34308
|
confirmed: options.confirm === true,
|
|
33369
|
-
|
|
33370
|
-
...options.project === void 0 ? {} : { projectId: options.project }
|
|
34309
|
+
workItemId: options.workItem
|
|
33371
34310
|
})
|
|
33372
34311
|
)
|
|
33373
34312
|
);
|
|
@@ -33401,45 +34340,54 @@ function createProgram(context) {
|
|
|
33401
34340
|
})
|
|
33402
34341
|
);
|
|
33403
34342
|
const profile = program2.command("profile").description("\u7BA1\u7406\u672C\u5730\u521B\u4F5C\u753B\u50CF");
|
|
33404
|
-
profile.command("
|
|
34343
|
+
profile.command("begin").description("\u5F00\u59CB\u753B\u50CF\u95EE\u7B54").option("--json", "\u8F93\u51FA JSON").action(
|
|
33405
34344
|
async (options) => runAction(
|
|
33406
34345
|
context,
|
|
33407
34346
|
options.json === true,
|
|
33408
34347
|
() => new ProfileCli({
|
|
33409
34348
|
currentDirectory: context.currentDirectory,
|
|
33410
34349
|
homeDirectory: context.homeDirectory
|
|
33411
|
-
}).
|
|
34350
|
+
}).begin()
|
|
33412
34351
|
)
|
|
33413
34352
|
);
|
|
33414
|
-
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(
|
|
33415
34354
|
async (options) => runAction(
|
|
33416
34355
|
context,
|
|
33417
34356
|
options.json === true,
|
|
33418
34357
|
() => new ProfileCli({
|
|
33419
34358
|
currentDirectory: context.currentDirectory,
|
|
33420
34359
|
homeDirectory: context.homeDirectory
|
|
33421
|
-
}).
|
|
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
|
+
})
|
|
33422
34365
|
)
|
|
33423
34366
|
);
|
|
33424
|
-
profile.command("
|
|
34367
|
+
profile.command("status").description("\u67E5\u770B\u521B\u4F5C\u753B\u50CF").option("--json", "\u8F93\u51FA JSON").action(
|
|
33425
34368
|
async (options) => runAction(
|
|
33426
34369
|
context,
|
|
33427
34370
|
options.json === true,
|
|
33428
34371
|
() => new ProfileCli({
|
|
33429
34372
|
currentDirectory: context.currentDirectory,
|
|
33430
34373
|
homeDirectory: context.homeDirectory
|
|
33431
|
-
}).
|
|
34374
|
+
}).status()
|
|
33432
34375
|
)
|
|
33433
34376
|
);
|
|
33434
34377
|
const memory = program2.command("memory").description("\u7BA1\u7406\u672C\u5730\u5185\u5BB9\u8BB0\u5FC6");
|
|
33435
|
-
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(
|
|
33436
34379
|
async (options) => runAction(
|
|
33437
34380
|
context,
|
|
33438
34381
|
options.json === true,
|
|
33439
34382
|
() => new ContentMemoryCli({
|
|
33440
34383
|
currentDirectory: context.currentDirectory,
|
|
33441
34384
|
homeDirectory: context.homeDirectory
|
|
33442
|
-
}).add(
|
|
34385
|
+
}).add({
|
|
34386
|
+
content: options.content,
|
|
34387
|
+
...options.expiresAt === void 0 ? {} : { expiresAt: options.expiresAt },
|
|
34388
|
+
kind: options.kind,
|
|
34389
|
+
scope: options.scope
|
|
34390
|
+
})
|
|
33443
34391
|
)
|
|
33444
34392
|
);
|
|
33445
34393
|
memory.command("list").description("\u67E5\u770B\u5185\u5BB9\u8BB0\u5FC6").option("--json", "\u8F93\u51FA JSON").action(
|
|
@@ -33452,42 +34400,49 @@ function createProgram(context) {
|
|
|
33452
34400
|
}).list()
|
|
33453
34401
|
)
|
|
33454
34402
|
);
|
|
33455
|
-
memory.command("
|
|
33456
|
-
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(
|
|
33457
34405
|
context,
|
|
33458
34406
|
options.json === true,
|
|
33459
34407
|
() => new ContentMemoryCli({
|
|
33460
34408
|
currentDirectory: context.currentDirectory,
|
|
33461
34409
|
homeDirectory: context.homeDirectory
|
|
33462
|
-
}).
|
|
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
|
+
})
|
|
33463
34416
|
)
|
|
33464
34417
|
);
|
|
33465
|
-
|
|
33466
|
-
|
|
33467
|
-
async (options) => withKnowledge(context, "knowledge.status", options.json === true, (cli) => cli.status())
|
|
33468
|
-
);
|
|
33469
|
-
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(
|
|
33470
|
-
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(
|
|
33471
34420
|
context,
|
|
33472
|
-
"knowledge.import",
|
|
33473
34421
|
options.json === true,
|
|
33474
|
-
(
|
|
34422
|
+
() => new ContentMemoryCli({
|
|
34423
|
+
currentDirectory: context.currentDirectory,
|
|
34424
|
+
homeDirectory: context.homeDirectory
|
|
34425
|
+
}).archive(options.memory)
|
|
33475
34426
|
)
|
|
33476
34427
|
);
|
|
33477
|
-
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(
|
|
33478
34433
|
async (options) => withKnowledge(
|
|
33479
34434
|
context,
|
|
33480
34435
|
"knowledge.import",
|
|
33481
34436
|
options.json === true,
|
|
33482
|
-
(cli) => cli.
|
|
34437
|
+
(cli) => cli.importSource(options.source, options.lexicalOnly === true, options.choice)
|
|
33483
34438
|
)
|
|
33484
34439
|
);
|
|
33485
|
-
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(
|
|
33486
34441
|
async (query, options) => withKnowledge(
|
|
33487
34442
|
context,
|
|
33488
34443
|
"knowledge.search",
|
|
33489
34444
|
options.json === true,
|
|
33490
|
-
(cli) => cli.search(query, options.mode, positiveInteger(options.limit, "limit"))
|
|
34445
|
+
(cli) => cli.search(query, options.mode, positiveInteger(options.limit, "limit"), options.choice)
|
|
33491
34446
|
)
|
|
33492
34447
|
);
|
|
33493
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(
|
|
@@ -33499,14 +34454,6 @@ function createProgram(context) {
|
|
|
33499
34454
|
)
|
|
33500
34455
|
);
|
|
33501
34456
|
const quotes = knowledge.command("quotes").description("\u7BA1\u7406\u672C\u5730\u91D1\u53E5");
|
|
33502
|
-
quotes.command("init").description("\u521D\u59CB\u5316\u91D1\u53E5\u5E93").option("--json", "\u8F93\u51FA JSON").action(
|
|
33503
|
-
async (options) => withKnowledge(
|
|
33504
|
-
context,
|
|
33505
|
-
"knowledge.quotes.init",
|
|
33506
|
-
options.json === true,
|
|
33507
|
-
(cli) => cli.initQuotes()
|
|
33508
|
-
)
|
|
33509
|
-
);
|
|
33510
34457
|
quotes.command("status").description("\u67E5\u770B\u91D1\u53E5\u5E93\u72B6\u6001").option("--json", "\u8F93\u51FA JSON").action(
|
|
33511
34458
|
async (options) => withKnowledge(
|
|
33512
34459
|
context,
|
|
@@ -33561,14 +34508,6 @@ function createProgram(context) {
|
|
|
33561
34508
|
(cli) => cli.archiveQuote(quoteId)
|
|
33562
34509
|
)
|
|
33563
34510
|
);
|
|
33564
|
-
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(
|
|
33565
|
-
async (options) => withKnowledge(
|
|
33566
|
-
context,
|
|
33567
|
-
"knowledge.quotes.sync",
|
|
33568
|
-
options.json === true,
|
|
33569
|
-
(cli) => cli.syncQuotes(options.lexicalOnly === true)
|
|
33570
|
-
)
|
|
33571
|
-
);
|
|
33572
34511
|
const auth = program2.command("auth").description("\u7BA1\u7406\u5F53\u524D\u8BBE\u5907\u767B\u5F55");
|
|
33573
34512
|
const authAction = (options, action) => runAction(
|
|
33574
34513
|
context,
|