@deployxai/dxc 0.1.8 → 0.1.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  import {
7
7
  SourceCli,
8
8
  SourceCliError
9
- } from "./chunks/chunk-QPHUHGHV.js";
9
+ } from "./chunks/chunk-DDKUG5EV.js";
10
10
  import {
11
11
  CONTENT_ARTIFACT_KINDS,
12
12
  CONTENT_STAGE_INPUTS,
@@ -48,6 +48,7 @@ import {
48
48
  contentStageArtifactFrontmatterSchema,
49
49
  createDeviceBindingSessionResponseSchema,
50
50
  createPublishingApprovalRequestSchema,
51
+ createPublishingDraftIntentRequestSchema,
51
52
  createWechatAuthorizationSessionResponseSchema,
52
53
  createWechatLoginSessionResponseSchema,
53
54
  dataTransitSchema,
@@ -63,6 +64,7 @@ import {
63
64
  publishingArticleSchema,
64
65
  publishingDraftIntentResponseSchema,
65
66
  publishingPreviewLinkSchema,
67
+ publishingPreviewSelectionStateSchema,
66
68
  publishingRenderSnapshotSchema,
67
69
  publishingUploadReceiptSchema,
68
70
  publishingUploadSessionSchema,
@@ -81,7 +83,7 @@ import {
81
83
  wechatRenderResultSchema,
82
84
  writePrivateBuffer,
83
85
  writePrivateJson
84
- } from "./chunks/chunk-UQRFCGHR.js";
86
+ } from "./chunks/chunk-RONRJJBC.js";
85
87
 
86
88
  // node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/nodes/identity.js
87
89
  var require_identity = __commonJS({
@@ -160,17 +162,17 @@ var require_visit = __commonJS({
160
162
  visit.BREAK = BREAK;
161
163
  visit.SKIP = SKIP;
162
164
  visit.REMOVE = REMOVE;
163
- function visit_(key, node, visitor, path8) {
164
- const ctrl = callVisitor(key, node, visitor, path8);
165
+ function visit_(key, node, visitor, path9) {
166
+ const ctrl = callVisitor(key, node, visitor, path9);
165
167
  if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
166
- replaceNode(key, path8, ctrl);
167
- return visit_(key, ctrl, visitor, path8);
168
+ replaceNode(key, path9, ctrl);
169
+ return visit_(key, ctrl, visitor, path9);
168
170
  }
169
171
  if (typeof ctrl !== "symbol") {
170
172
  if (identity.isCollection(node)) {
171
- path8 = Object.freeze(path8.concat(node));
173
+ path9 = Object.freeze(path9.concat(node));
172
174
  for (let i = 0; i < node.items.length; ++i) {
173
- const ci = visit_(i, node.items[i], visitor, path8);
175
+ const ci = visit_(i, node.items[i], visitor, path9);
174
176
  if (typeof ci === "number")
175
177
  i = ci - 1;
176
178
  else if (ci === BREAK)
@@ -181,13 +183,13 @@ var require_visit = __commonJS({
181
183
  }
182
184
  }
183
185
  } else if (identity.isPair(node)) {
184
- path8 = Object.freeze(path8.concat(node));
185
- const ck = visit_("key", node.key, visitor, path8);
186
+ path9 = Object.freeze(path9.concat(node));
187
+ const ck = visit_("key", node.key, visitor, path9);
186
188
  if (ck === BREAK)
187
189
  return BREAK;
188
190
  else if (ck === REMOVE)
189
191
  node.key = null;
190
- const cv = visit_("value", node.value, visitor, path8);
192
+ const cv = visit_("value", node.value, visitor, path9);
191
193
  if (cv === BREAK)
192
194
  return BREAK;
193
195
  else if (cv === REMOVE)
@@ -208,17 +210,17 @@ var require_visit = __commonJS({
208
210
  visitAsync.BREAK = BREAK;
209
211
  visitAsync.SKIP = SKIP;
210
212
  visitAsync.REMOVE = REMOVE;
211
- async function visitAsync_(key, node, visitor, path8) {
212
- const ctrl = await callVisitor(key, node, visitor, path8);
213
+ async function visitAsync_(key, node, visitor, path9) {
214
+ const ctrl = await callVisitor(key, node, visitor, path9);
213
215
  if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
214
- replaceNode(key, path8, ctrl);
215
- return visitAsync_(key, ctrl, visitor, path8);
216
+ replaceNode(key, path9, ctrl);
217
+ return visitAsync_(key, ctrl, visitor, path9);
216
218
  }
217
219
  if (typeof ctrl !== "symbol") {
218
220
  if (identity.isCollection(node)) {
219
- path8 = Object.freeze(path8.concat(node));
221
+ path9 = Object.freeze(path9.concat(node));
220
222
  for (let i = 0; i < node.items.length; ++i) {
221
- const ci = await visitAsync_(i, node.items[i], visitor, path8);
223
+ const ci = await visitAsync_(i, node.items[i], visitor, path9);
222
224
  if (typeof ci === "number")
223
225
  i = ci - 1;
224
226
  else if (ci === BREAK)
@@ -229,13 +231,13 @@ var require_visit = __commonJS({
229
231
  }
230
232
  }
231
233
  } else if (identity.isPair(node)) {
232
- path8 = Object.freeze(path8.concat(node));
233
- const ck = await visitAsync_("key", node.key, visitor, path8);
234
+ path9 = Object.freeze(path9.concat(node));
235
+ const ck = await visitAsync_("key", node.key, visitor, path9);
234
236
  if (ck === BREAK)
235
237
  return BREAK;
236
238
  else if (ck === REMOVE)
237
239
  node.key = null;
238
- const cv = await visitAsync_("value", node.value, visitor, path8);
240
+ const cv = await visitAsync_("value", node.value, visitor, path9);
239
241
  if (cv === BREAK)
240
242
  return BREAK;
241
243
  else if (cv === REMOVE)
@@ -262,23 +264,23 @@ var require_visit = __commonJS({
262
264
  }
263
265
  return visitor;
264
266
  }
265
- function callVisitor(key, node, visitor, path8) {
267
+ function callVisitor(key, node, visitor, path9) {
266
268
  if (typeof visitor === "function")
267
- return visitor(key, node, path8);
269
+ return visitor(key, node, path9);
268
270
  if (identity.isMap(node))
269
- return visitor.Map?.(key, node, path8);
271
+ return visitor.Map?.(key, node, path9);
270
272
  if (identity.isSeq(node))
271
- return visitor.Seq?.(key, node, path8);
273
+ return visitor.Seq?.(key, node, path9);
272
274
  if (identity.isPair(node))
273
- return visitor.Pair?.(key, node, path8);
275
+ return visitor.Pair?.(key, node, path9);
274
276
  if (identity.isScalar(node))
275
- return visitor.Scalar?.(key, node, path8);
277
+ return visitor.Scalar?.(key, node, path9);
276
278
  if (identity.isAlias(node))
277
- return visitor.Alias?.(key, node, path8);
279
+ return visitor.Alias?.(key, node, path9);
278
280
  return void 0;
279
281
  }
280
- function replaceNode(key, path8, node) {
281
- const parent = path8[path8.length - 1];
282
+ function replaceNode(key, path9, node) {
283
+ const parent = path9[path9.length - 1];
282
284
  if (identity.isCollection(parent)) {
283
285
  parent.items[key] = node;
284
286
  } else if (identity.isPair(parent)) {
@@ -888,10 +890,10 @@ var require_Collection = __commonJS({
888
890
  var createNode = require_createNode();
889
891
  var identity = require_identity();
890
892
  var Node2 = require_Node();
891
- function collectionFromPath(schema, path8, value) {
893
+ function collectionFromPath(schema, path9, value) {
892
894
  let v2 = value;
893
- for (let i = path8.length - 1; i >= 0; --i) {
894
- const k = path8[i];
895
+ for (let i = path9.length - 1; i >= 0; --i) {
896
+ const k = path9[i];
895
897
  if (typeof k === "number" && Number.isInteger(k) && k >= 0) {
896
898
  const a = [];
897
899
  a[k] = v2;
@@ -910,7 +912,7 @@ var require_Collection = __commonJS({
910
912
  sourceObjects: /* @__PURE__ */ new Map()
911
913
  });
912
914
  }
913
- var isEmptyPath = (path8) => path8 == null || typeof path8 === "object" && !!path8[Symbol.iterator]().next().done;
915
+ var isEmptyPath = (path9) => path9 == null || typeof path9 === "object" && !!path9[Symbol.iterator]().next().done;
914
916
  var Collection = class extends Node2.NodeBase {
915
917
  constructor(type, schema) {
916
918
  super(type);
@@ -940,11 +942,11 @@ var require_Collection = __commonJS({
940
942
  * be a Pair instance or a `{ key, value }` object, which may not have a key
941
943
  * that already exists in the map.
942
944
  */
943
- addIn(path8, value) {
944
- if (isEmptyPath(path8))
945
+ addIn(path9, value) {
946
+ if (isEmptyPath(path9))
945
947
  this.add(value);
946
948
  else {
947
- const [key, ...rest] = path8;
949
+ const [key, ...rest] = path9;
948
950
  const node = this.get(key, true);
949
951
  if (identity.isCollection(node))
950
952
  node.addIn(rest, value);
@@ -958,8 +960,8 @@ var require_Collection = __commonJS({
958
960
  * Removes a value from the collection.
959
961
  * @returns `true` if the item was found and removed.
960
962
  */
961
- deleteIn(path8) {
962
- const [key, ...rest] = path8;
963
+ deleteIn(path9) {
964
+ const [key, ...rest] = path9;
963
965
  if (rest.length === 0)
964
966
  return this.delete(key);
965
967
  const node = this.get(key, true);
@@ -973,8 +975,8 @@ var require_Collection = __commonJS({
973
975
  * scalar values from their surrounding node; to disable set `keepScalar` to
974
976
  * `true` (collections are always returned intact).
975
977
  */
976
- getIn(path8, keepScalar) {
977
- const [key, ...rest] = path8;
978
+ getIn(path9, keepScalar) {
979
+ const [key, ...rest] = path9;
978
980
  const node = this.get(key, true);
979
981
  if (rest.length === 0)
980
982
  return !keepScalar && identity.isScalar(node) ? node.value : node;
@@ -992,8 +994,8 @@ var require_Collection = __commonJS({
992
994
  /**
993
995
  * Checks if the collection includes a value with the key `key`.
994
996
  */
995
- hasIn(path8) {
996
- const [key, ...rest] = path8;
997
+ hasIn(path9) {
998
+ const [key, ...rest] = path9;
997
999
  if (rest.length === 0)
998
1000
  return this.has(key);
999
1001
  const node = this.get(key, true);
@@ -1003,8 +1005,8 @@ var require_Collection = __commonJS({
1003
1005
  * Sets a value in this collection. For `!!set`, `value` needs to be a
1004
1006
  * boolean to add/remove the item from the set.
1005
1007
  */
1006
- setIn(path8, value) {
1007
- const [key, ...rest] = path8;
1008
+ setIn(path9, value) {
1009
+ const [key, ...rest] = path9;
1008
1010
  if (rest.length === 0) {
1009
1011
  this.set(key, value);
1010
1012
  } else {
@@ -3519,9 +3521,9 @@ var require_Document = __commonJS({
3519
3521
  this.contents.add(value);
3520
3522
  }
3521
3523
  /** Adds a value to the document. */
3522
- addIn(path8, value) {
3524
+ addIn(path9, value) {
3523
3525
  if (assertCollection(this.contents))
3524
- this.contents.addIn(path8, value);
3526
+ this.contents.addIn(path9, value);
3525
3527
  }
3526
3528
  /**
3527
3529
  * Create a new `Alias` node, ensuring that the target `node` has the required anchor.
@@ -3596,14 +3598,14 @@ var require_Document = __commonJS({
3596
3598
  * Removes a value from the document.
3597
3599
  * @returns `true` if the item was found and removed.
3598
3600
  */
3599
- deleteIn(path8) {
3600
- if (Collection.isEmptyPath(path8)) {
3601
+ deleteIn(path9) {
3602
+ if (Collection.isEmptyPath(path9)) {
3601
3603
  if (this.contents == null)
3602
3604
  return false;
3603
3605
  this.contents = null;
3604
3606
  return true;
3605
3607
  }
3606
- return assertCollection(this.contents) ? this.contents.deleteIn(path8) : false;
3608
+ return assertCollection(this.contents) ? this.contents.deleteIn(path9) : false;
3607
3609
  }
3608
3610
  /**
3609
3611
  * Returns item at `key`, or `undefined` if not found. By default unwraps
@@ -3618,10 +3620,10 @@ var require_Document = __commonJS({
3618
3620
  * scalar values from their surrounding node; to disable set `keepScalar` to
3619
3621
  * `true` (collections are always returned intact).
3620
3622
  */
3621
- getIn(path8, keepScalar) {
3622
- if (Collection.isEmptyPath(path8))
3623
+ getIn(path9, keepScalar) {
3624
+ if (Collection.isEmptyPath(path9))
3623
3625
  return !keepScalar && identity.isScalar(this.contents) ? this.contents.value : this.contents;
3624
- return identity.isCollection(this.contents) ? this.contents.getIn(path8, keepScalar) : void 0;
3626
+ return identity.isCollection(this.contents) ? this.contents.getIn(path9, keepScalar) : void 0;
3625
3627
  }
3626
3628
  /**
3627
3629
  * Checks if the document includes a value with the key `key`.
@@ -3632,10 +3634,10 @@ var require_Document = __commonJS({
3632
3634
  /**
3633
3635
  * Checks if the document includes a value at `path`.
3634
3636
  */
3635
- hasIn(path8) {
3636
- if (Collection.isEmptyPath(path8))
3637
+ hasIn(path9) {
3638
+ if (Collection.isEmptyPath(path9))
3637
3639
  return this.contents !== void 0;
3638
- return identity.isCollection(this.contents) ? this.contents.hasIn(path8) : false;
3640
+ return identity.isCollection(this.contents) ? this.contents.hasIn(path9) : false;
3639
3641
  }
3640
3642
  /**
3641
3643
  * Sets a value in this document. For `!!set`, `value` needs to be a
@@ -3652,13 +3654,13 @@ var require_Document = __commonJS({
3652
3654
  * Sets a value in this document. For `!!set`, `value` needs to be a
3653
3655
  * boolean to add/remove the item from the set.
3654
3656
  */
3655
- setIn(path8, value) {
3656
- if (Collection.isEmptyPath(path8)) {
3657
+ setIn(path9, value) {
3658
+ if (Collection.isEmptyPath(path9)) {
3657
3659
  this.contents = value;
3658
3660
  } else if (this.contents == null) {
3659
- this.contents = Collection.collectionFromPath(this.schema, Array.from(path8), value);
3661
+ this.contents = Collection.collectionFromPath(this.schema, Array.from(path9), value);
3660
3662
  } else if (assertCollection(this.contents)) {
3661
- this.contents.setIn(path8, value);
3663
+ this.contents.setIn(path9, value);
3662
3664
  }
3663
3665
  }
3664
3666
  /**
@@ -5618,9 +5620,9 @@ var require_cst_visit = __commonJS({
5618
5620
  visit.BREAK = BREAK;
5619
5621
  visit.SKIP = SKIP;
5620
5622
  visit.REMOVE = REMOVE;
5621
- visit.itemAtPath = (cst, path8) => {
5623
+ visit.itemAtPath = (cst, path9) => {
5622
5624
  let item = cst;
5623
- for (const [field, index] of path8) {
5625
+ for (const [field, index] of path9) {
5624
5626
  const tok = item?.[field];
5625
5627
  if (tok && "items" in tok) {
5626
5628
  item = tok.items[index];
@@ -5629,23 +5631,23 @@ var require_cst_visit = __commonJS({
5629
5631
  }
5630
5632
  return item;
5631
5633
  };
5632
- visit.parentCollection = (cst, path8) => {
5633
- const parent = visit.itemAtPath(cst, path8.slice(0, -1));
5634
- const field = path8[path8.length - 1][0];
5634
+ visit.parentCollection = (cst, path9) => {
5635
+ const parent = visit.itemAtPath(cst, path9.slice(0, -1));
5636
+ const field = path9[path9.length - 1][0];
5635
5637
  const coll = parent?.[field];
5636
5638
  if (coll && "items" in coll)
5637
5639
  return coll;
5638
5640
  throw new Error("Parent collection not found");
5639
5641
  };
5640
- function _visit(path8, item, visitor) {
5641
- let ctrl = visitor(item, path8);
5642
+ function _visit(path9, item, visitor) {
5643
+ let ctrl = visitor(item, path9);
5642
5644
  if (typeof ctrl === "symbol")
5643
5645
  return ctrl;
5644
5646
  for (const field of ["key", "value"]) {
5645
5647
  const token = item[field];
5646
5648
  if (token && "items" in token) {
5647
5649
  for (let i = 0; i < token.items.length; ++i) {
5648
- const ci = _visit(Object.freeze(path8.concat([[field, i]])), token.items[i], visitor);
5650
+ const ci = _visit(Object.freeze(path9.concat([[field, i]])), token.items[i], visitor);
5649
5651
  if (typeof ci === "number")
5650
5652
  i = ci - 1;
5651
5653
  else if (ci === BREAK)
@@ -5656,10 +5658,10 @@ var require_cst_visit = __commonJS({
5656
5658
  }
5657
5659
  }
5658
5660
  if (typeof ctrl === "function" && field === "key")
5659
- ctrl = ctrl(item, path8);
5661
+ ctrl = ctrl(item, path9);
5660
5662
  }
5661
5663
  }
5662
- return typeof ctrl === "function" ? ctrl(item, path8) : ctrl;
5664
+ return typeof ctrl === "function" ? ctrl(item, path9) : ctrl;
5663
5665
  }
5664
5666
  exports.visit = visit;
5665
5667
  }
@@ -11059,9 +11061,9 @@ var require_picocolors = __commonJS({
11059
11061
  var argv = p.argv || [];
11060
11062
  var env = p.env || {};
11061
11063
  var isColorSupported = !(!!env.NO_COLOR || argv.includes("--no-color")) && (!!env.FORCE_COLOR || argv.includes("--color") || p.platform === "win32" || (p.stdout || {}).isTTY && env.TERM !== "dumb" || !!env.CI);
11062
- var formatter = (open4, close, replace = open4) => (input) => {
11063
- let string = "" + input, index = string.indexOf(close, open4.length);
11064
- return ~index ? open4 + replaceClose(string, close, replace, index) + close : open4 + string + close;
11064
+ var formatter = (open5, close, replace = open5) => (input) => {
11065
+ let string = "" + input, index = string.indexOf(close, open5.length);
11066
+ return ~index ? open5 + replaceClose(string, close, replace, index) + close : open5 + string + close;
11065
11067
  };
11066
11068
  var replaceClose = (string, close, replace, index) => {
11067
11069
  let result = "", cursor = 0;
@@ -13026,27 +13028,27 @@ var require_util = __commonJS({
13026
13028
  };
13027
13029
  }
13028
13030
  var normalize = lruMemoize(function normalize2(aPath) {
13029
- var path8 = aPath;
13031
+ var path9 = aPath;
13030
13032
  var url = urlParse(aPath);
13031
13033
  if (url) {
13032
13034
  if (!url.path) {
13033
13035
  return aPath;
13034
13036
  }
13035
- path8 = url.path;
13037
+ path9 = url.path;
13036
13038
  }
13037
- var isAbsolute = exports.isAbsolute(path8);
13039
+ var isAbsolute = exports.isAbsolute(path9);
13038
13040
  var parts = [];
13039
13041
  var start = 0;
13040
13042
  var i = 0;
13041
13043
  while (true) {
13042
13044
  start = i;
13043
- i = path8.indexOf("/", start);
13045
+ i = path9.indexOf("/", start);
13044
13046
  if (i === -1) {
13045
- parts.push(path8.slice(start));
13047
+ parts.push(path9.slice(start));
13046
13048
  break;
13047
13049
  } else {
13048
- parts.push(path8.slice(start, i));
13049
- while (i < path8.length && path8[i] === "/") {
13050
+ parts.push(path9.slice(start, i));
13051
+ while (i < path9.length && path9[i] === "/") {
13050
13052
  i++;
13051
13053
  }
13052
13054
  }
@@ -13067,15 +13069,15 @@ var require_util = __commonJS({
13067
13069
  }
13068
13070
  }
13069
13071
  }
13070
- path8 = parts.join("/");
13071
- if (path8 === "") {
13072
- path8 = isAbsolute ? "/" : ".";
13072
+ path9 = parts.join("/");
13073
+ if (path9 === "") {
13074
+ path9 = isAbsolute ? "/" : ".";
13073
13075
  }
13074
13076
  if (url) {
13075
- url.path = path8;
13077
+ url.path = path9;
13076
13078
  return urlGenerate(url);
13077
13079
  }
13078
- return path8;
13080
+ return path9;
13079
13081
  });
13080
13082
  exports.normalize = normalize;
13081
13083
  function join(aRoot, aPath) {
@@ -14827,22 +14829,22 @@ var require_previous_map = __commonJS({
14827
14829
  this.annotation = this.getAnnotationURL(css.substring(start, end));
14828
14830
  }
14829
14831
  }
14830
- loadFile(path8, cssFile, trusted) {
14832
+ loadFile(path9, cssFile, trusted) {
14831
14833
  if (!trusted && !this.unsafeMap) {
14832
- if (!/\.map$/i.test(path8)) {
14834
+ if (!/\.map$/i.test(path9)) {
14833
14835
  return void 0;
14834
14836
  }
14835
14837
  if (cssFile) {
14836
- let relativePath = relative(dirname(cssFile), path8);
14838
+ let relativePath = relative(dirname(cssFile), path9);
14837
14839
  if (relativePath === ".." || relativePath.startsWith(".." + sep) || isAbsolute(relativePath)) {
14838
14840
  return void 0;
14839
14841
  }
14840
14842
  }
14841
14843
  }
14842
- this.root = dirname(path8);
14843
- if (existsSync(path8)) {
14844
- this.mapFile = path8;
14845
- return readFileSync(path8, "utf-8").toString().trim();
14844
+ this.root = dirname(path9);
14845
+ if (existsSync(path9)) {
14846
+ this.mapFile = path9;
14847
+ return readFileSync(path9, "utf-8").toString().trim();
14846
14848
  }
14847
14849
  }
14848
14850
  loadMap(file, prev) {
@@ -15614,9 +15616,9 @@ var require_map_generator = __commonJS({
15614
15616
  if (typeof this.mapOpts.annotation === "string") {
15615
15617
  from = dirname(resolve(from, this.mapOpts.annotation));
15616
15618
  }
15617
- let path8 = relative(from, file);
15618
- this.memoizedPaths.set(file, path8);
15619
- return path8;
15619
+ let path9 = relative(from, file);
15620
+ this.memoizedPaths.set(file, path9);
15621
+ return path9;
15620
15622
  }
15621
15623
  previous() {
15622
15624
  if (!this.previousMaps) {
@@ -15671,12 +15673,12 @@ var require_map_generator = __commonJS({
15671
15673
  return window.btoa(unescape(encodeURIComponent(str)));
15672
15674
  }
15673
15675
  }
15674
- toFileUrl(path8) {
15675
- let cached = this.memoizedFileURLs.get(path8);
15676
+ toFileUrl(path9) {
15677
+ let cached = this.memoizedFileURLs.get(path9);
15676
15678
  if (cached) return cached;
15677
15679
  if (pathToFileURL) {
15678
- let fileURL = pathToFileURL(path8).toString();
15679
- this.memoizedFileURLs.set(path8, fileURL);
15680
+ let fileURL = pathToFileURL(path9).toString();
15681
+ this.memoizedFileURLs.set(path9, fileURL);
15680
15682
  return fileURL;
15681
15683
  } else {
15682
15684
  throw new Error(
@@ -15684,14 +15686,14 @@ var require_map_generator = __commonJS({
15684
15686
  );
15685
15687
  }
15686
15688
  }
15687
- toUrl(path8) {
15688
- let cached = this.memoizedURLs.get(path8);
15689
+ toUrl(path9) {
15690
+ let cached = this.memoizedURLs.get(path9);
15689
15691
  if (cached) return cached;
15690
15692
  if (sep === "\\") {
15691
- path8 = path8.replace(/\\/g, "/");
15693
+ path9 = path9.replace(/\\/g, "/");
15692
15694
  }
15693
- let url = encodeURI(path8).replace(/[#?]/g, encodeURIComponent);
15694
- this.memoizedURLs.set(path8, url);
15695
+ let url = encodeURI(path9).replace(/[#?]/g, encodeURIComponent);
15696
+ this.memoizedURLs.set(path9, url);
15695
15697
  return url;
15696
15698
  }
15697
15699
  };
@@ -15746,7 +15748,7 @@ var require_parser2 = __commonJS({
15746
15748
  let prev;
15747
15749
  let shift;
15748
15750
  let last = false;
15749
- let open4 = false;
15751
+ let open5 = false;
15750
15752
  let params = [];
15751
15753
  let brackets = [];
15752
15754
  while (!this.tokenizer.endOfFile()) {
@@ -15766,7 +15768,7 @@ var require_parser2 = __commonJS({
15766
15768
  this.semicolon = true;
15767
15769
  break;
15768
15770
  } else if (type === "{") {
15769
- open4 = true;
15771
+ open5 = true;
15770
15772
  break;
15771
15773
  } else if (type === "}") {
15772
15774
  if (params.length > 0) {
@@ -15808,7 +15810,7 @@ var require_parser2 = __commonJS({
15808
15810
  node.raws.afterName = "";
15809
15811
  node.params = "";
15810
15812
  }
15811
- if (open4) {
15813
+ if (open5) {
15812
15814
  node.nodes = [];
15813
15815
  this.current = node;
15814
15816
  }
@@ -19072,8 +19074,8 @@ var require_req = __commonJS({
19072
19074
  if (req.originalUrl) {
19073
19075
  _req.url = req.originalUrl;
19074
19076
  } else {
19075
- const path8 = req.path;
19076
- _req.url = typeof path8 === "string" ? path8 : req.url ? req.url.path || req.url : void 0;
19077
+ const path9 = req.path;
19078
+ _req.url = typeof path9 === "string" ? path9 : req.url ? req.url.path || req.url : void 0;
19077
19079
  }
19078
19080
  if (req.query) {
19079
19081
  _req.query = req.query;
@@ -19238,14 +19240,14 @@ var require_redact = __commonJS({
19238
19240
  }
19239
19241
  return obj;
19240
19242
  }
19241
- function parsePath(path8) {
19243
+ function parsePath(path9) {
19242
19244
  const parts = [];
19243
19245
  let current = "";
19244
19246
  let inBrackets = false;
19245
19247
  let inQuotes = false;
19246
19248
  let quoteChar = "";
19247
- for (let i = 0; i < path8.length; i++) {
19248
- const char = path8[i];
19249
+ for (let i = 0; i < path9.length; i++) {
19250
+ const char = path9[i];
19249
19251
  if (!inBrackets && char === ".") {
19250
19252
  if (current) {
19251
19253
  parts.push(current);
@@ -19376,10 +19378,10 @@ var require_redact = __commonJS({
19376
19378
  return current;
19377
19379
  }
19378
19380
  function redactPaths(obj, paths, censor, remove = false) {
19379
- for (const path8 of paths) {
19380
- const parts = parsePath(path8);
19381
+ for (const path9 of paths) {
19382
+ const parts = parsePath(path9);
19381
19383
  if (parts.includes("*")) {
19382
- redactWildcardPath(obj, parts, censor, path8, remove);
19384
+ redactWildcardPath(obj, parts, censor, path9, remove);
19383
19385
  } else {
19384
19386
  if (remove) {
19385
19387
  removeKey(obj, parts);
@@ -19464,8 +19466,8 @@ var require_redact = __commonJS({
19464
19466
  }
19465
19467
  } else {
19466
19468
  if (afterWildcard.includes("*")) {
19467
- const wrappedCensor = typeof censor === "function" ? (value, path8) => {
19468
- const fullPath = [...pathArray.slice(0, pathLength), ...path8];
19469
+ const wrappedCensor = typeof censor === "function" ? (value, path9) => {
19470
+ const fullPath = [...pathArray.slice(0, pathLength), ...path9];
19469
19471
  return censor(value, fullPath);
19470
19472
  } : censor;
19471
19473
  redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
@@ -19500,8 +19502,8 @@ var require_redact = __commonJS({
19500
19502
  return null;
19501
19503
  }
19502
19504
  const pathStructure = /* @__PURE__ */ new Map();
19503
- for (const path8 of pathsToClone) {
19504
- const parts = parsePath(path8);
19505
+ for (const path9 of pathsToClone) {
19506
+ const parts = parsePath(path9);
19505
19507
  let current = pathStructure;
19506
19508
  for (let i = 0; i < parts.length; i++) {
19507
19509
  const part = parts[i];
@@ -19553,24 +19555,24 @@ var require_redact = __commonJS({
19553
19555
  }
19554
19556
  return cloneSelectively(obj, pathStructure);
19555
19557
  }
19556
- function validatePath(path8) {
19557
- if (typeof path8 !== "string") {
19558
+ function validatePath(path9) {
19559
+ if (typeof path9 !== "string") {
19558
19560
  throw new Error("Paths must be (non-empty) strings");
19559
19561
  }
19560
- if (path8 === "") {
19562
+ if (path9 === "") {
19561
19563
  throw new Error("Invalid redaction path ()");
19562
19564
  }
19563
- if (path8.includes("..")) {
19564
- throw new Error(`Invalid redaction path (${path8})`);
19565
+ if (path9.includes("..")) {
19566
+ throw new Error(`Invalid redaction path (${path9})`);
19565
19567
  }
19566
- if (path8.includes(",")) {
19567
- throw new Error(`Invalid redaction path (${path8})`);
19568
+ if (path9.includes(",")) {
19569
+ throw new Error(`Invalid redaction path (${path9})`);
19568
19570
  }
19569
19571
  let bracketCount = 0;
19570
19572
  let inQuotes = false;
19571
19573
  let quoteChar = "";
19572
- for (let i = 0; i < path8.length; i++) {
19573
- const char = path8[i];
19574
+ for (let i = 0; i < path9.length; i++) {
19575
+ const char = path9[i];
19574
19576
  if ((char === '"' || char === "'") && bracketCount > 0) {
19575
19577
  if (!inQuotes) {
19576
19578
  inQuotes = true;
@@ -19584,20 +19586,20 @@ var require_redact = __commonJS({
19584
19586
  } else if (char === "]" && !inQuotes) {
19585
19587
  bracketCount--;
19586
19588
  if (bracketCount < 0) {
19587
- throw new Error(`Invalid redaction path (${path8})`);
19589
+ throw new Error(`Invalid redaction path (${path9})`);
19588
19590
  }
19589
19591
  }
19590
19592
  }
19591
19593
  if (bracketCount !== 0) {
19592
- throw new Error(`Invalid redaction path (${path8})`);
19594
+ throw new Error(`Invalid redaction path (${path9})`);
19593
19595
  }
19594
19596
  }
19595
19597
  function validatePaths(paths) {
19596
19598
  if (!Array.isArray(paths)) {
19597
19599
  throw new TypeError("paths must be an array");
19598
19600
  }
19599
- for (const path8 of paths) {
19600
- validatePath(path8);
19601
+ for (const path9 of paths) {
19602
+ validatePath(path9);
19601
19603
  }
19602
19604
  }
19603
19605
  function slowRedact(options = {}) {
@@ -19765,8 +19767,8 @@ var require_redaction = __commonJS({
19765
19767
  if (shape[k] === null) {
19766
19768
  o[k] = (value) => topCensor(value, [k]);
19767
19769
  } else {
19768
- const wrappedCensor = typeof censor === "function" ? (value, path8) => {
19769
- return censor(value, [k, ...path8]);
19770
+ const wrappedCensor = typeof censor === "function" ? (value, path9) => {
19771
+ return censor(value, [k, ...path9]);
19770
19772
  } : censor;
19771
19773
  o[k] = Redact({
19772
19774
  paths: shape[k],
@@ -19987,7 +19989,7 @@ var require_sonic_boom = __commonJS({
19987
19989
  var fs2 = __require("fs");
19988
19990
  var EventEmitter2 = __require("events");
19989
19991
  var inherits = __require("util").inherits;
19990
- var path8 = __require("path");
19992
+ var path9 = __require("path");
19991
19993
  var sleep = require_atomic_sleep();
19992
19994
  var assert = __require("assert");
19993
19995
  var BUSY_WRITE_TIMEOUT = 100;
@@ -20041,7 +20043,7 @@ var require_sonic_boom = __commonJS({
20041
20043
  const mode = sonic.mode;
20042
20044
  if (sonic.sync) {
20043
20045
  try {
20044
- if (sonic.mkdir) fs2.mkdirSync(path8.dirname(file), { recursive: true });
20046
+ if (sonic.mkdir) fs2.mkdirSync(path9.dirname(file), { recursive: true });
20045
20047
  const fd = fs2.openSync(file, flags, mode);
20046
20048
  fileOpened(null, fd);
20047
20049
  } catch (err) {
@@ -20049,7 +20051,7 @@ var require_sonic_boom = __commonJS({
20049
20051
  throw err;
20050
20052
  }
20051
20053
  } else if (sonic.mkdir) {
20052
- fs2.mkdir(path8.dirname(file), { recursive: true }, (err) => {
20054
+ fs2.mkdir(path9.dirname(file), { recursive: true }, (err) => {
20053
20055
  if (err) return fileOpened(err);
20054
20056
  fs2.open(file, flags, mode, fileOpened);
20055
20057
  });
@@ -20061,7 +20063,7 @@ var require_sonic_boom = __commonJS({
20061
20063
  if (!(this instanceof SonicBoom)) {
20062
20064
  return new SonicBoom(opts);
20063
20065
  }
20064
- let { fd, dest, minLength, maxLength, maxWrite, periodicFlush, sync, append: append2 = true, mkdir: mkdir4, retryEAGAIN, fsync, contentMode, mode } = opts || {};
20066
+ let { fd, dest, minLength, maxLength, maxWrite, periodicFlush, sync, append: append2 = true, mkdir: mkdir5, retryEAGAIN, fsync, contentMode, mode } = opts || {};
20065
20067
  fd = fd || dest;
20066
20068
  this._len = 0;
20067
20069
  this.fd = -1;
@@ -20086,7 +20088,7 @@ var require_sonic_boom = __commonJS({
20086
20088
  this.append = append2 || false;
20087
20089
  this.mode = mode;
20088
20090
  this.retryEAGAIN = retryEAGAIN || (() => true);
20089
- this.mkdir = mkdir4 || false;
20091
+ this.mkdir = mkdir5 || false;
20090
20092
  let fsWriteSync;
20091
20093
  let fsWrite;
20092
20094
  if (contentMode === kContentModeBuffer) {
@@ -21381,15 +21383,15 @@ var require_transport = __commonJS({
21381
21383
  if (!unquoted) {
21382
21384
  return false;
21383
21385
  }
21384
- let path8 = unquoted;
21385
- if (path8.startsWith("file://")) {
21386
+ let path9 = unquoted;
21387
+ if (path9.startsWith("file://")) {
21386
21388
  try {
21387
- path8 = fileURLToPath2(path8);
21389
+ path9 = fileURLToPath2(path9);
21388
21390
  } catch {
21389
21391
  return false;
21390
21392
  }
21391
21393
  }
21392
- return isAbsolute(path8) && !existsSync(path8);
21394
+ return isAbsolute(path9) && !existsSync(path9);
21393
21395
  }
21394
21396
  function stripQuotes(value) {
21395
21397
  const first = value[0];
@@ -23295,7 +23297,7 @@ import os3 from "node:os";
23295
23297
  // apps/cli/package.json
23296
23298
  var package_default = {
23297
23299
  name: "@dxc/cli",
23298
- version: "0.1.8",
23300
+ version: "0.1.13",
23299
23301
  private: true,
23300
23302
  type: "module",
23301
23303
  bin: {
@@ -23318,6 +23320,7 @@ var package_default = {
23318
23320
  commander: "15.0.0",
23319
23321
  "fast-xml-parser": "5.3.3",
23320
23322
  "onnxruntime-web": "1.22.0",
23323
+ sharp: "0.35.3",
23321
23324
  yaml: "2.9.0",
23322
23325
  zod: "4.4.3"
23323
23326
  }
@@ -26434,9 +26437,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
26434
26437
  * @param {string} [path]
26435
26438
  * @return {(string|null|Command)}
26436
26439
  */
26437
- executableDir(path8) {
26438
- if (path8 === void 0) return this._executableDir;
26439
- this._executableDir = path8;
26440
+ executableDir(path9) {
26441
+ if (path9 === void 0) return this._executableDir;
26442
+ this._executableDir = path9;
26440
26443
  return this;
26441
26444
  }
26442
26445
  /**
@@ -28543,7 +28546,7 @@ var ArticleDocumentValidationError = class extends Error {
28543
28546
  }
28544
28547
  };
28545
28548
  function issuePaths(error) {
28546
- return error.issues.map((issue) => issue.path.join(".")).filter((path8) => path8.length > 0);
28549
+ return error.issues.map((issue) => issue.path.join(".")).filter((path9) => path9.length > 0);
28547
28550
  }
28548
28551
  function plainTokenText(tokens) {
28549
28552
  return tokens.map((token) => {
@@ -28994,29 +28997,31 @@ var ALLOWED_STYLE_PROPERTIES = [
28994
28997
  var allowedStyles = Object.fromEntries(
28995
28998
  ALLOWED_STYLE_PROPERTIES.map((property) => [property, [SAFE_STYLE_VALUE]])
28996
28999
  );
29000
+ var ALLOWED_TAGS = [
29001
+ "section",
29002
+ "h1",
29003
+ "h2",
29004
+ "h3",
29005
+ "h4",
29006
+ "p",
29007
+ "blockquote",
29008
+ "ul",
29009
+ "ol",
29010
+ "li",
29011
+ "img",
29012
+ "strong",
29013
+ "span",
29014
+ "code",
29015
+ "br"
29016
+ ];
29017
+ var ALLOWED_ATTRIBUTES = {
29018
+ "*": ["style"],
29019
+ img: ["src", "alt", "style"]
29020
+ };
28997
29021
  function sanitizeWechatHtml(value) {
28998
29022
  return (0, import_sanitize_html.default)(value, {
28999
- allowedTags: [
29000
- "section",
29001
- "h1",
29002
- "h2",
29003
- "h3",
29004
- "h4",
29005
- "p",
29006
- "blockquote",
29007
- "ul",
29008
- "ol",
29009
- "li",
29010
- "img",
29011
- "strong",
29012
- "span",
29013
- "code",
29014
- "br"
29015
- ],
29016
- allowedAttributes: {
29017
- "*": ["style"],
29018
- img: ["src", "alt", "style"]
29019
- },
29023
+ allowedTags: [...ALLOWED_TAGS],
29024
+ allowedAttributes: ALLOWED_ATTRIBUTES,
29020
29025
  allowedSchemes: [],
29021
29026
  allowProtocolRelative: false,
29022
29027
  allowedStyles: {
@@ -29246,8 +29251,8 @@ function withoutManualReferences(tokens) {
29246
29251
  );
29247
29252
  return referenceIndex < 0 ? [...tokens] : tokens.slice(0, referenceIndex);
29248
29253
  }
29249
- function warning(code, message, path8) {
29250
- return path8 === void 0 ? { code, message } : { code, path: path8, message };
29254
+ function warning(code, message, path9) {
29255
+ return path9 === void 0 ? { code, message } : { code, path: path9, message };
29251
29256
  }
29252
29257
  function buildPreflight(article, html, observations) {
29253
29258
  const errors = [];
@@ -29321,6 +29326,19 @@ function renderWechatArticle(article, options = {}) {
29321
29326
  preflight
29322
29327
  });
29323
29328
  }
29329
+ function rewriteWechatAssetSources(html, replacements) {
29330
+ let rewritten = html;
29331
+ for (const [logicalPath, targetUrl] of replacements) {
29332
+ if (!isSafeLogicalAssetPath(logicalPath) || targetUrl.trim().length === 0) {
29333
+ throw new TypeError("Asset source replacement is invalid");
29334
+ }
29335
+ rewritten = rewritten.replaceAll(
29336
+ `src="${escapeHtml(logicalPath)}"`,
29337
+ `src="${escapeHtml(targetUrl)}"`
29338
+ );
29339
+ }
29340
+ return rewritten;
29341
+ }
29324
29342
 
29325
29343
  // apps/cli/src/stage-artifact.ts
29326
29344
  var import_yaml2 = __toESM(require_dist(), 1);
@@ -29351,8 +29369,13 @@ function issuePaths2(issues) {
29351
29369
  if (issue.code === "unrecognized_keys" && issue.keys?.includes("planned")) {
29352
29370
  return "planned: \u8BE5\u5B57\u6BB5\u4E0D\u5C5E\u4E8E\u5DF2\u5B8C\u6210\u89C6\u89C9\u4EA7\u7269\uFF1Bplanned=true \u53EA\u80FD\u4F7F\u7528\u751F\u6210\u524D\u6388\u6743\u5951\u7EA6\uFF0C\u751F\u6210\u7ED3\u675F\u540E\u5FC5\u987B\u79FB\u9664";
29353
29371
  }
29372
+ if (issue.code === "unrecognized_keys" && issue.keys !== void 0) {
29373
+ const unknown = issue.keys.map(String).join("\u3001");
29374
+ const allowed = location === "generation" ? "executionLocation\u3001dataTransit\u3001chargesQuota\u3001maxAttempts\u3001retryPolicy\u3001plannedAssets" : /^inlineAssets\.\d+$/u.test(location) ? "path\u3001placement\u3001placementAnchor\u3001purpose\u3001source\u3001sha256" : "\u5F53\u524D\u9636\u6BB5 Skill \u8F93\u51FA\u6A21\u677F\u4E2D\u7684\u8BED\u4E49\u5B57\u6BB5\uFF0C\u4EE5\u53CA\u7531 CLI \u7EF4\u62A4\u7684 dxc \u5143\u6570\u636E";
29375
+ return `${location.length === 0 ? "frontmatter" : location}: \u672A\u8BC6\u522B\u5B57\u6BB5 ${unknown}\uFF1B\u5141\u8BB8\u5B57\u6BB5\u4E3A ${allowed}`;
29376
+ }
29354
29377
  if (location === "generation") {
29355
- return "generation: planned=true \u65F6\u5FC5\u987B\u58F0\u660E executionLocation\u3001dataTransit\u3001chargesQuota\u3001maxAttempts \u548C plannedAssets\uFF0C\u5E76\u8D70\u751F\u6210\u524D\u6388\u6743\u5951\u7EA6";
29378
+ return "generation: planned=true \u65F6\u5FC5\u987B\u58F0\u660E executionLocation\u3001dataTransit\u3001chargesQuota\u3001maxAttempts\u3001retryPolicy \u548C plannedAssets\uFF0C\u5E76\u8D70\u751F\u6210\u524D\u6388\u6743\u5951\u7EA6";
29356
29379
  }
29357
29380
  return location.length === 0 ? issue.message : `${location}: ${issue.message}`;
29358
29381
  })
@@ -29527,6 +29550,11 @@ async function bindDeliveryApprovalArtifact(options) {
29527
29550
  if (value["rootSnapshotId"] !== options.approval.rootSnapshotId || value["rootSnapshotHash"] !== options.approval.rootSnapshotHash) {
29528
29551
  throw new StageArtifactValidationError(["rootSnapshotId/rootSnapshotHash \u4E0E\u6279\u51C6\u8BF7\u6C42\u4E0D\u4E00\u81F4"]);
29529
29552
  }
29553
+ if (value["selectedSnapshotId"] !== options.approval.selectedSnapshotId || value["selectedSnapshotHash"] !== options.approval.selectedSnapshotHash || value["templateId"] !== options.approval.templateId) {
29554
+ throw new StageArtifactValidationError([
29555
+ "\u6700\u7EC8\u6A21\u677F\u9009\u62E9\u56DE\u6267\u4E0E\u6279\u51C6\u54CD\u5E94\u4E0D\u4E00\u81F4\uFF1B\u8BF7\u91CD\u65B0\u8BFB\u53D6 preview-status\u3001\u66F4\u65B0 delivery \u5E76\u8BA9\u7528\u6237\u6309\u5F53\u524D\u9884\u89C8\u518D\u6B21\u786E\u8BA4"
29556
+ ]);
29557
+ }
29530
29558
  const intentState = options.intent === void 0 ? {} : options.intent.status === "SUCCEEDED" && options.intent.mediaId !== void 0 ? { intentId: options.intent.id, mediaId: options.intent.mediaId, state: "completed" } : options.intent.status === "FAILED" ? { intentId: options.intent.id, state: "failed" } : options.intent.progress.terminal ? { intentId: options.intent.id, state: "requires-attention" } : { intentId: options.intent.id, state: "processing" };
29531
29559
  const nextValue = {
29532
29560
  ...value,
@@ -29558,10 +29586,59 @@ async function readDeliveryDraftIdentity(target) {
29558
29586
  return {
29559
29587
  accountId: parsed.data.accountId,
29560
29588
  idempotencyKey: parsed.data.idempotencyKey,
29589
+ previewSelectionRevision: parsed.data.previewSelectionRevision,
29561
29590
  rootSnapshotHash: parsed.data.rootSnapshotHash,
29562
- rootSnapshotId: parsed.data.rootSnapshotId
29591
+ rootSnapshotId: parsed.data.rootSnapshotId,
29592
+ selectedSnapshotHash: parsed.data.selectedSnapshotHash,
29593
+ selectedSnapshotId: parsed.data.selectedSnapshotId,
29594
+ templateId: parsed.data.templateId
29563
29595
  };
29564
29596
  }
29597
+ async function readDeliveryRetryIdentity(target) {
29598
+ const source = (await readRegularFile(target, MAXIMUM_ARTIFACT_BYTES)).toString("utf8");
29599
+ const parsed = deliveryStageArtifactFrontmatterSchema.safeParse(parseFrontmatter2(source).value);
29600
+ if (!parsed.success) {
29601
+ throw new StageArtifactValidationError(issuePaths2(parsed.error.issues));
29602
+ }
29603
+ return {
29604
+ intentId: parsed.data.intentId,
29605
+ retryAttempt: parsed.data.retryAttempt,
29606
+ selectedSnapshotHash: parsed.data.selectedSnapshotHash,
29607
+ state: parsed.data.state
29608
+ };
29609
+ }
29610
+ async function bindDeliveryRetryIntentArtifact(options) {
29611
+ const source = (await readRegularFile(options.target, MAXIMUM_ARTIFACT_BYTES)).toString("utf8");
29612
+ const frontmatter = parseFrontmatter2(source);
29613
+ const parsed = deliveryStageArtifactFrontmatterSchema.safeParse(frontmatter.value);
29614
+ if (!parsed.success) {
29615
+ throw new StageArtifactValidationError(issuePaths2(parsed.error.issues));
29616
+ }
29617
+ if (parsed.data.state !== "failed" || parsed.data.intentId !== options.previousIntentId || parsed.data.selectedSnapshotHash !== options.intent.snapshotHash) {
29618
+ throw new StageArtifactValidationError([
29619
+ "FAILED \u610F\u56FE\u6216\u6700\u7EC8\u5FEB\u7167\u4E0E\u670D\u52A1\u7AEF\u91CD\u8BD5\u7ED3\u679C\u4E0D\u4E00\u81F4\uFF1B\u672A\u8986\u76D6\u4EA4\u4ED8\u4EA7\u7269"
29620
+ ]);
29621
+ }
29622
+ const state = options.intent.status === "SUCCEEDED" && options.intent.mediaId !== void 0 ? "completed" : options.intent.status === "FAILED" ? "failed" : options.intent.progress.terminal ? "requires-attention" : "processing";
29623
+ const nextValue = deliveryStageArtifactFrontmatterSchema.parse({
29624
+ ...parsed.data,
29625
+ idempotencyKey: options.idempotencyKey,
29626
+ intentId: options.intent.id,
29627
+ ...options.intent.mediaId === void 0 ? {} : { mediaId: options.intent.mediaId },
29628
+ retryAttempt: parsed.data.retryAttempt + 1,
29629
+ retryOfIntentId: options.previousIntentId,
29630
+ state
29631
+ });
29632
+ await writeAtomically(
29633
+ options.target,
29634
+ `---
29635
+ ${(0, import_yaml2.stringify)(nextValue, { lineWidth: 0 }).trimEnd()}
29636
+ ---
29637
+
29638
+ ${frontmatter.body}
29639
+ `
29640
+ );
29641
+ }
29565
29642
  async function normalizeGoldenLines(directory, body, logicalPath) {
29566
29643
  const target = insideProject(directory, logicalPath);
29567
29644
  const snapshot = await captureFile(target, logicalPath);
@@ -29749,6 +29826,7 @@ async function normalizeStageArtifact(options) {
29749
29826
  nextValue["selectedSnapshotId"] ??= legacySnapshotId;
29750
29827
  nextValue["selectedSnapshotHash"] ??= legacySnapshotHash;
29751
29828
  nextValue["templateId"] ??= "wechat-minimal@1";
29829
+ nextValue["previewSelectionRevision"] ??= 0;
29752
29830
  delete nextValue["snapshotId"];
29753
29831
  delete nextValue["snapshotHash"];
29754
29832
  if (typeof nextValue["rootSnapshotId"] === "string") {
@@ -30067,6 +30145,19 @@ async function stageArtifactRequiresUserConfirmation(options) {
30067
30145
  const value = recordValue(parseFrontmatter2(source).value);
30068
30146
  return normalizedOrigin(value?.["origin"]) === "hotspot" && value?.["researchMode"] === "fact-only" && value?.["externalOpinionStatus"] === "user-skipped";
30069
30147
  }
30148
+ async function selectedTitleForLocalPreview(options) {
30149
+ const source = (await readRegularFile(
30150
+ insideProject(options.directory, options.manifest.artifacts.titles),
30151
+ MAXIMUM_ARTIFACT_BYTES
30152
+ )).toString("utf8");
30153
+ const parsed = titlesStageArtifactFrontmatterSchema.safeParse(parseFrontmatter2(source).value);
30154
+ if (!parsed.success || parsed.data.selectedTitle === null) {
30155
+ throw new StageArtifactValidationError(
30156
+ parsed.success ? ["selectedTitle: \u672C\u5730\u9884\u89C8\u9700\u8981\u5DF2\u786E\u8BA4\u6807\u9898"] : issuePaths2(parsed.error.issues)
30157
+ );
30158
+ }
30159
+ return parsed.data.selectedTitle;
30160
+ }
30070
30161
  async function visualPlanArtifactPhase(options) {
30071
30162
  const source = (await readRegularFile(
30072
30163
  insideProject(options.directory, options.manifest.artifacts["visual-plan"]),
@@ -30078,6 +30169,19 @@ async function visualPlanArtifactPhase(options) {
30078
30169
  }
30079
30170
  return "planned" in parsed.data && parsed.data.planned === true ? "generation-proposal" : "materialized";
30080
30171
  }
30172
+ async function visualPlanAssetsDirectory(options) {
30173
+ const source = (await readRegularFile(
30174
+ insideProject(options.directory, options.manifest.artifacts["visual-plan"]),
30175
+ MAXIMUM_ARTIFACT_BYTES
30176
+ )).toString("utf8");
30177
+ const parsed = visualPlanStageArtifactFrontmatterSchema.safeParse(parseFrontmatter2(source).value);
30178
+ if (!parsed.success || !("coverAsset" in parsed.data)) {
30179
+ throw new StageArtifactValidationError(
30180
+ parsed.success ? ["visual-plan: \u56FE\u7247\u4ECD\u5904\u4E8E\u751F\u6210\u8BA1\u5212\u9636\u6BB5"] : issuePaths2(parsed.error.issues)
30181
+ );
30182
+ }
30183
+ return parsed.data.assetsDirectory;
30184
+ }
30081
30185
 
30082
30186
  // apps/cli/src/project.ts
30083
30187
  var MANIFEST_NAME = "dxc.project.json";
@@ -30426,6 +30530,25 @@ async function findNearestProjectDirectory(start) {
30426
30530
  candidate = parent;
30427
30531
  }
30428
30532
  }
30533
+ async function locateProjectDirectory(currentDirectory, homeDirectory, directoryInput) {
30534
+ const start = projectDirectory(currentDirectory, homeDirectory, directoryInput);
30535
+ if (directoryInput !== void 0) {
30536
+ return start;
30537
+ }
30538
+ const nearest = await findNearestProjectDirectory(start);
30539
+ if (nearest === void 0) {
30540
+ throw new ProjectCliError(
30541
+ "DXC_PROJECT_NOT_FOUND",
30542
+ "\u5F53\u524D\u76EE\u5F55\u53CA\u5176\u4E0A\u7EA7\u76EE\u5F55\u4E2D\u6CA1\u6709 dxc.project.json\u3002",
30543
+ {
30544
+ fields: ["directory"],
30545
+ reason: "PROJECT_ROOT_NOT_FOUND",
30546
+ recovery: "\u8FDB\u5165\u5185\u5BB9\u9879\u76EE\u76EE\u5F55\u540E\u91CD\u8BD5\uFF0C\u6216\u663E\u5F0F\u4F20\u5165 --directory <\u9879\u76EE\u6839\u76EE\u5F55>\uFF1B\u4E5F\u53EF\u4EE5\u5148\u8FD0\u884C dxc project resolve --json \u5B9A\u4F4D\u5DF2\u6709\u9879\u76EE\u3002"
30547
+ }
30548
+ );
30549
+ }
30550
+ return nearest;
30551
+ }
30429
30552
  var ProjectCli = class {
30430
30553
  #currentDirectory;
30431
30554
  #homeDirectory;
@@ -30630,6 +30753,7 @@ var ProjectCli = class {
30630
30753
  (inspection) => inspection.state === "stale" ? [
30631
30754
  {
30632
30755
  action: "rerun-stage",
30756
+ command: `dxc project checkpoint ${inspection.stage} --status running --summary "\u91CD\u65B0\u6838\u9A8C ${inspection.stage} \u9636\u6BB5" --execution-location ${inspection.checkpoint.execution.location} --data-transit ${inspection.checkpoint.execution.dataTransit} --json`,
30633
30757
  reason: inspection.reason,
30634
30758
  stage: inspection.stage
30635
30759
  }
@@ -30661,11 +30785,78 @@ var ProjectCli = class {
30661
30785
  });
30662
30786
  }
30663
30787
  async status(directoryInput) {
30664
- const directory = projectDirectory(this.#currentDirectory, this.#homeDirectory, directoryInput);
30788
+ const directory = await locateProjectDirectory(
30789
+ this.#currentDirectory,
30790
+ this.#homeDirectory,
30791
+ directoryInput
30792
+ );
30665
30793
  const result = await this.#statusAtDirectory(directory);
30666
30794
  await this.#rememberProject(directory, result.data.manifest, this.#now().toISOString());
30667
30795
  return result;
30668
30796
  }
30797
+ async localPreviewInputs(directoryInput, outputInput) {
30798
+ const directory = await locateProjectDirectory(
30799
+ this.#currentDirectory,
30800
+ this.#homeDirectory,
30801
+ directoryInput
30802
+ );
30803
+ const status = await this.#statusAtDirectory(directory);
30804
+ for (const stage of ["article", "titles", "visual-plan"]) {
30805
+ const inspection = status.data.checkpoints.find((candidate) => candidate.stage === stage);
30806
+ if (inspection === void 0 || inspection.state !== "valid" || inspection.checkpoint.status !== "completed") {
30807
+ throw new ProjectCliError(
30808
+ "DXC_PROJECT_STAGE_INVALID",
30809
+ `\u672C\u5730\u9884\u89C8\u8981\u6C42 ${stage} \u9636\u6BB5\u5DF2\u5B8C\u6210\u4E14\u672A\u5931\u6548\u3002`,
30810
+ {
30811
+ fields: [stage],
30812
+ reason: "LOCAL_PREVIEW_STAGE_NOT_READY",
30813
+ recovery: `\u5148\u6309 project status \u7684 nextStage/recoveryPlan \u5B8C\u6210\u6216\u91CD\u65B0\u6838\u9A8C ${stage} \u9636\u6BB5\uFF0C\u518D\u751F\u6210\u672C\u5730\u9884\u89C8\u3002`,
30814
+ stage
30815
+ }
30816
+ );
30817
+ }
30818
+ }
30819
+ let title;
30820
+ try {
30821
+ title = await selectedTitleForLocalPreview({ directory, manifest: status.data.manifest });
30822
+ } catch (error) {
30823
+ if (error instanceof StageArtifactValidationError) {
30824
+ throw new ProjectCliError("DXC_PROJECT_STAGE_INVALID", error.message, {
30825
+ fields: error.issues,
30826
+ reason: "LOCAL_PREVIEW_TITLE_INVALID",
30827
+ recovery: "\u91CD\u65B0\u5B8C\u6210 titles \u9636\u6BB5\u5E76\u786E\u8BA4\u6700\u7EC8\u6807\u9898\u540E\u518D\u751F\u6210\u672C\u5730\u9884\u89C8\u3002",
30828
+ stage: "titles"
30829
+ });
30830
+ }
30831
+ throw error;
30832
+ }
30833
+ let assetsDirectory;
30834
+ try {
30835
+ assetsDirectory = insideProject2(
30836
+ directory,
30837
+ await visualPlanAssetsDirectory({ directory, manifest: status.data.manifest })
30838
+ );
30839
+ } catch (error) {
30840
+ if (error instanceof StageArtifactValidationError) {
30841
+ throw new ProjectCliError("DXC_PROJECT_STAGE_INVALID", error.message, {
30842
+ fields: error.issues,
30843
+ reason: "LOCAL_PREVIEW_VISUAL_PLAN_INVALID",
30844
+ recovery: "\u91CD\u65B0\u5B8C\u6210 visual-plan \u9636\u6BB5\u5E76\u786E\u4FDD\u771F\u5B9E PNG/JPEG \u7D20\u6750\u5DF2\u843D\u76D8\u540E\u518D\u751F\u6210\u672C\u5730\u9884\u89C8\u3002",
30845
+ stage: "visual-plan"
30846
+ });
30847
+ }
30848
+ throw error;
30849
+ }
30850
+ const outputFile = outputInput === void 0 ? insideProject2(directory, ".dxc/previews/visual-preview.html") : path4.isAbsolute(outputInput) ? outputInput : path4.resolve(directory, outputInput);
30851
+ return {
30852
+ articleFile: insideProject2(directory, status.data.manifest.artifacts.article),
30853
+ assetsDirectory,
30854
+ outputFile,
30855
+ projectDirectory: directory,
30856
+ title,
30857
+ visualPlanFile: insideProject2(directory, status.data.manifest.artifacts["visual-plan"])
30858
+ };
30859
+ }
30669
30860
  async resolve(queryInput, directoryInput) {
30670
30861
  const query = queryInput?.trim();
30671
30862
  if (query !== void 0 && (query.length === 0 || query.length > 160)) {
@@ -30795,7 +30986,7 @@ var ProjectCli = class {
30795
30986
  `\u9636\u6BB5 ${stage.data} \u5FC5\u987B\u7531 ${expectedSkill.name}@${expectedSkill.version} \u5199\u5165\u68C0\u67E5\u70B9\u3002`
30796
30987
  );
30797
30988
  }
30798
- const directory = projectDirectory(
30989
+ const directory = await locateProjectDirectory(
30799
30990
  this.#currentDirectory,
30800
30991
  this.#homeDirectory,
30801
30992
  options.directory
@@ -30921,7 +31112,13 @@ var ProjectCli = class {
30921
31112
  if (effectiveStatus === "awaiting-user" && (waitingFor === void 0 || waitingFor.length === 0) || effectiveStatus !== "awaiting-user" && waitingFor !== void 0) {
30922
31113
  throw new ProjectCliError(
30923
31114
  "DXC_PROJECT_STAGE_INVALID",
30924
- "Awaiting checkpoint needs one waiting-for prompt"
31115
+ effectiveStatus === "awaiting-user" ? "awaiting-user \u68C0\u67E5\u70B9\u7F3A\u5C11\u7B49\u5F85\u7528\u6237\u56DE\u7B54\u7684\u95EE\u9898\u3002" : "\u53EA\u6709 awaiting-user \u68C0\u67E5\u70B9\u53EF\u4EE5\u643A\u5E26 waiting-for\u3002",
31116
+ {
31117
+ fields: ["waitingFor"],
31118
+ reason: effectiveStatus === "awaiting-user" ? "WAITING_FOR_REQUIRED" : "WAITING_FOR_NOT_ALLOWED",
31119
+ recovery: effectiveStatus === "awaiting-user" ? "\u8865\u5145 --waiting-for <\u9700\u8981\u7528\u6237\u56DE\u7B54\u7684\u95EE\u9898> \u540E\u91CD\u8BD5\uFF1BCLI \u4E0D\u4F1A\u5728\u53C2\u6570\u65E0\u6548\u65F6\u5199\u5165\u68C0\u67E5\u70B9\u3002" : "\u79FB\u9664 --waiting-for\uFF0C\u6216\u628A\u76EE\u6807\u72B6\u6001\u6539\u4E3A awaiting-user\u3002",
31120
+ stage: stage.data
31121
+ }
30925
31122
  );
30926
31123
  }
30927
31124
  const needsArtifact = effectiveStatus === "awaiting-user" || effectiveStatus === "completed" || confirmingExternalAuthorization;
@@ -31043,7 +31240,7 @@ var ProjectCli = class {
31043
31240
  "\u56FE\u7247\u751F\u6210\u6388\u6743\u5FC5\u987B\u7ED1\u5B9A planned=true \u7684\u5B8C\u6574\u751F\u6210\u8BA1\u5212\u3002",
31044
31241
  {
31045
31242
  reason: "VISUAL_GENERATION_PLAN_REQUIRED",
31046
- recovery: "\u8865\u9F50 generation.executionLocation\u3001dataTransit\u3001chargesQuota\u3001maxAttempts \u548C plannedAssets \u540E\u91CD\u65B0\u8BF7\u6C42\u6388\u6743\u3002",
31243
+ recovery: "\u8865\u9F50 generation.executionLocation\u3001dataTransit\u3001chargesQuota\u3001maxAttempts\u3001retryPolicy \u548C plannedAssets \u540E\u91CD\u65B0\u8BF7\u6C42\u6388\u6743\u3002",
31047
31244
  stage: "visual-plan"
31048
31245
  }
31049
31246
  );
@@ -31336,16 +31533,16 @@ var SkillInstaller = class {
31336
31533
  // apps/cli/src/wechat.ts
31337
31534
  import { spawn } from "node:child_process";
31338
31535
  import {
31339
- createHash as createHash7,
31536
+ createHash as createHash8,
31340
31537
  createPrivateKey as createPrivateKey2,
31341
31538
  createPublicKey as createPublicKey2,
31342
31539
  randomBytes,
31343
- randomUUID as randomUUID4
31540
+ randomUUID as randomUUID5
31344
31541
  } from "node:crypto";
31345
- import { constants as fileConstants3 } from "node:fs";
31346
- import { chmod, mkdir as mkdir3, open as open3, rename as rename5, rm as rm2, writeFile as writeFile3 } from "node:fs/promises";
31542
+ import { constants as fileConstants4 } from "node:fs";
31543
+ import { chmod, lstat as lstat7, mkdir as mkdir4, open as open4, rename as rename6, rm as rm2, writeFile as writeFile4 } from "node:fs/promises";
31347
31544
  import os2 from "node:os";
31348
- import path7 from "node:path";
31545
+ import path8 from "node:path";
31349
31546
 
31350
31547
  // packages/security/src/index.ts
31351
31548
  var import_pino = __toESM(require_pino(), 1);
@@ -31496,19 +31693,22 @@ import { constants as fileConstants2 } from "node:fs";
31496
31693
  import { lstat as lstat5, open as open2, readdir as readdir2, realpath } from "node:fs/promises";
31497
31694
  import path6 from "node:path";
31498
31695
  var import_yaml3 = __toESM(require_dist(), 1);
31696
+ import sharp from "sharp";
31499
31697
 
31500
31698
  // apps/cli/src/wechat-error.ts
31501
31699
  var WechatCliError = class extends Error {
31502
- constructor(code, guidance, retryable = false) {
31700
+ constructor(code, guidance, retryable = false, fields) {
31503
31701
  super(guidance ?? code);
31504
31702
  this.code = code;
31505
31703
  this.guidance = guidance;
31506
31704
  this.retryable = retryable;
31705
+ this.fields = fields;
31507
31706
  this.name = "WechatCliError";
31508
31707
  }
31509
31708
  code;
31510
31709
  guidance;
31511
31710
  retryable;
31711
+ fields;
31512
31712
  };
31513
31713
 
31514
31714
  // apps/cli/src/publishing-assets.ts
@@ -31521,6 +31721,25 @@ var VISUAL_PLAN_MAXIMUM_BYTES = 128 * 1024;
31521
31721
  var ARTICLE_FRONTMATTER = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)([\s\S]*)$/u;
31522
31722
  var VISUAL_PLAN_FRONTMATTER = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/u;
31523
31723
  var LOCAL_WORKFLOW_FRONTMATTER_KEYS = ["dxc", "goldenLinesPath", "goldenLinesSha256"];
31724
+ async function validatePublishingImage(bytes, target) {
31725
+ let metadata;
31726
+ try {
31727
+ metadata = await sharp(bytes, { failOn: "error", limitInputPixels: 8e7 }).metadata();
31728
+ } catch {
31729
+ throw new WechatCliError(
31730
+ "DXC_PUBLISHING_INPUT_INVALID",
31731
+ `\u56FE\u7247 ${path6.basename(target)} \u65E0\u6CD5\u88AB\u5B89\u5168\u89E3\u7801\uFF1B\u4EC5\u652F\u6301\u6709\u6548 PNG/JPEG\u3002`
31732
+ );
31733
+ }
31734
+ const extension = path6.extname(target).toLowerCase();
31735
+ const expectedFormat = extension === ".png" ? "png" : extension === ".jpg" || extension === ".jpeg" ? "jpeg" : void 0;
31736
+ if (expectedFormat === void 0 || metadata.format !== expectedFormat || metadata.width === void 0 || metadata.height === void 0) {
31737
+ throw new WechatCliError(
31738
+ "DXC_PUBLISHING_INPUT_INVALID",
31739
+ `\u56FE\u7247 ${path6.basename(target)} \u7684\u6269\u5C55\u540D\u4E0E\u771F\u5B9E PNG/JPEG \u683C\u5F0F\u4E0D\u4E00\u81F4\u3002`
31740
+ );
31741
+ }
31742
+ }
31524
31743
  async function readPublishingInput(inputPath, maximumBytes, role = "article") {
31525
31744
  const target = path6.resolve(inputPath);
31526
31745
  let handle;
@@ -31552,10 +31771,11 @@ async function readPublishingInput(inputPath, maximumBytes, role = "article") {
31552
31771
  `\u6587\u4EF6 ${path6.basename(target)} \u4E0D\u662F\u53EF\u8BFB\u53D6\u7684\u975E\u7A7A\u666E\u901A\u6587\u4EF6\u3002`
31553
31772
  );
31554
31773
  }
31555
- return {
31556
- bytes: await handle.readFile(),
31557
- path: target
31558
- };
31774
+ const bytes = await handle.readFile();
31775
+ if (role === "cover" || role === "inline-image") {
31776
+ await validatePublishingImage(bytes, target);
31777
+ }
31778
+ return { bytes, path: target };
31559
31779
  } catch (error) {
31560
31780
  if (error instanceof WechatCliError) {
31561
31781
  throw error;
@@ -31693,7 +31913,8 @@ function injectCollectedImages(source, images) {
31693
31913
  let headingLine = headingLines[index];
31694
31914
  if (image.placementAnchor !== void 0) {
31695
31915
  const match = /^after-heading:(.+)$/u.exec(image.placementAnchor);
31696
- const matches = match === null ? void 0 : headingLineByText.get(match[1]?.trim() ?? "");
31916
+ const requestedHeading = match?.[1]?.trim().replace(/^##\s+/u, "").replace(/\s+#+\s*$/u, "").trim();
31917
+ const matches = requestedHeading === void 0 ? void 0 : headingLineByText.get(requestedHeading);
31697
31918
  if (matches === void 0 || matches.length !== 1) {
31698
31919
  const matchCount = matches?.length ?? 0;
31699
31920
  const availableHeadings = [...headingLineByText.keys()].slice(0, 10).map((heading) => diagnosticText(heading)).join("\u3001").slice(0, 600);
@@ -31719,7 +31940,7 @@ function injectCollectedImages(source, images) {
31719
31940
  }
31720
31941
  return output.join("\n");
31721
31942
  }
31722
- async function plannedInlineImages(visualPlanFile, availableByFileName) {
31943
+ async function plannedVisualAssets(visualPlanFile, assetsDirectoryInput) {
31723
31944
  let source;
31724
31945
  try {
31725
31946
  source = (await readPublishingInput(visualPlanFile, VISUAL_PLAN_MAXIMUM_BYTES, "visual-plan")).bytes.toString("utf8");
@@ -31746,41 +31967,83 @@ async function plannedInlineImages(visualPlanFile, availableByFileName) {
31746
31967
  "\u89C6\u89C9\u8BA1\u5212\u4ECD\u5904\u4E8E\u751F\u6210\u524D\u6388\u6743\u9636\u6BB5\uFF1B\u8BF7\u5148\u5B8C\u6210\u56FE\u7247\u751F\u6210\u5E76\u5199\u5165 coverAsset/inlineAssets \u540E\u518D\u9884\u89C8\u3002"
31747
31968
  );
31748
31969
  }
31749
- return Promise.all(
31750
- parsed.data.inlineAssets.map(async (asset) => {
31751
- const absolutePath = availableByFileName.get(path6.posix.basename(asset.path));
31752
- if (absolutePath === void 0) {
31753
- throw new WechatCliError(
31754
- "DXC_PUBLISHING_VISUAL_PLAN_INVALID",
31755
- `\u89C6\u89C9\u8BA1\u5212\u58F0\u660E\u7684\u7D20\u6750 ${path6.posix.basename(asset.path)} \u4E0D\u5728\u6307\u5B9A\u7D20\u6750\u76EE\u5F55\u4E2D\u3002`
31756
- );
31757
- }
31758
- const input = await readPublishingInput(
31759
- absolutePath,
31760
- MAXIMUM_INLINE_IMAGE_BYTES2,
31761
- "inline-image"
31762
- );
31763
- if (createHash6("sha256").update(input.bytes).digest("hex") !== asset.sha256) {
31764
- throw new WechatCliError(
31765
- "DXC_PUBLISHING_VISUAL_PLAN_INVALID",
31766
- `\u89C6\u89C9\u8BA1\u5212\u58F0\u660E\u7684\u7D20\u6750 ${path6.posix.basename(asset.path)} \u4E0E\u8BB0\u5F55\u7684\u54C8\u5E0C\u4E0D\u4E00\u81F4\u3002`
31767
- );
31768
- }
31769
- const digest = createHash6("sha256").update(absolutePath).digest("hex").slice(0, 12);
31770
- const fileName = safeFileName(path6.basename(absolutePath)) || `visual-${digest}.png`;
31771
- return {
31772
- absolutePath,
31773
- alt: asset.purpose,
31774
- logicalPath: `assets/dxc-visuals/${digest}-${fileName}`,
31775
- placementAnchor: asset.placementAnchor
31776
- };
31777
- })
31970
+ if (assetsDirectoryInput === void 0) {
31971
+ throw new WechatCliError(
31972
+ "DXC_PUBLISHING_VISUAL_PLAN_INVALID",
31973
+ "\u4F7F\u7528\u89C6\u89C9\u8BA1\u5212\u65F6\u5FC5\u987B\u663E\u5F0F\u63D0\u4F9B\u5176\u58F0\u660E\u7684\u7D20\u6750\u76EE\u5F55\u3002"
31974
+ );
31975
+ }
31976
+ const assetsDirectory = path6.resolve(assetsDirectoryInput);
31977
+ const projectDirectory2 = commonDirectory(
31978
+ path6.dirname(path6.resolve(visualPlanFile)),
31979
+ assetsDirectory
31980
+ );
31981
+ const declaredAssetsDirectory = path6.resolve(projectDirectory2, parsed.data.assetsDirectory);
31982
+ if (!isWithinDirectory(assetsDirectory, declaredAssetsDirectory)) {
31983
+ throw new WechatCliError(
31984
+ "DXC_PUBLISHING_VISUAL_PLAN_INVALID",
31985
+ "\u663E\u5F0F\u7D20\u6750\u76EE\u5F55\u4E0D\u5728\u89C6\u89C9\u8BA1\u5212\u58F0\u660E\u7684\u9879\u76EE\u7D20\u6750\u76EE\u5F55\u4E2D\u3002"
31986
+ );
31987
+ }
31988
+ const resolvePlannedAsset = (assetPath) => {
31989
+ const target = path6.resolve(projectDirectory2, assetPath);
31990
+ if (!isWithinDirectory(target, declaredAssetsDirectory) || !isWithinDirectory(target, assetsDirectory)) {
31991
+ throw new WechatCliError("DXC_PUBLISHING_VISUAL_PLAN_INVALID");
31992
+ }
31993
+ return target;
31994
+ };
31995
+ const coverAbsolutePath = resolvePlannedAsset(parsed.data.coverAsset);
31996
+ const cover = await readContainedPublishingInput(
31997
+ coverAbsolutePath,
31998
+ MAXIMUM_IMAGE_BYTES,
31999
+ [assetsDirectory],
32000
+ "cover"
31778
32001
  );
32002
+ if (createHash6("sha256").update(cover.bytes).digest("hex") !== parsed.data.coverSha256) {
32003
+ throw new WechatCliError(
32004
+ "DXC_PUBLISHING_VISUAL_PLAN_INVALID",
32005
+ `\u89C6\u89C9\u8BA1\u5212\u58F0\u660E\u7684\u5C01\u9762 ${path6.posix.basename(parsed.data.coverAsset)} \u4E0E\u8BB0\u5F55\u7684\u54C8\u5E0C\u4E0D\u4E00\u81F4\u3002`
32006
+ );
32007
+ }
32008
+ return {
32009
+ coverAbsolutePath,
32010
+ inline: await Promise.all(
32011
+ parsed.data.inlineAssets.map(async (asset) => {
32012
+ const absolutePath = resolvePlannedAsset(asset.path);
32013
+ if (!isWithinDirectory(absolutePath, assetsDirectory)) {
32014
+ throw new WechatCliError(
32015
+ "DXC_PUBLISHING_VISUAL_PLAN_INVALID",
32016
+ `\u89C6\u89C9\u8BA1\u5212\u58F0\u660E\u7684\u7D20\u6750 ${path6.posix.basename(asset.path)} \u4E0D\u5728\u6307\u5B9A\u7D20\u6750\u76EE\u5F55\u4E2D\u3002`
32017
+ );
32018
+ }
32019
+ const input = await readContainedPublishingInput(
32020
+ absolutePath,
32021
+ MAXIMUM_INLINE_IMAGE_BYTES2,
32022
+ [assetsDirectory],
32023
+ "inline-image"
32024
+ );
32025
+ if (createHash6("sha256").update(input.bytes).digest("hex") !== asset.sha256) {
32026
+ throw new WechatCliError(
32027
+ "DXC_PUBLISHING_VISUAL_PLAN_INVALID",
32028
+ `\u89C6\u89C9\u8BA1\u5212\u58F0\u660E\u7684\u7D20\u6750 ${path6.posix.basename(asset.path)} \u4E0E\u8BB0\u5F55\u7684\u54C8\u5E0C\u4E0D\u4E00\u81F4\u3002`
32029
+ );
32030
+ }
32031
+ const digest = createHash6("sha256").update(absolutePath).digest("hex").slice(0, 12);
32032
+ const fileName = safeFileName(path6.basename(absolutePath)) || `visual-${digest}.png`;
32033
+ return {
32034
+ absolutePath,
32035
+ alt: asset.purpose,
32036
+ logicalPath: `assets/dxc-visuals/${digest}-${fileName}`,
32037
+ placementAnchor: asset.placementAnchor
32038
+ };
32039
+ })
32040
+ )
32041
+ };
31779
32042
  }
31780
32043
  function logicalInlinePaths(bundle) {
31781
32044
  return bundle.assets.filter((asset) => asset.role === "inline").map((asset) => asset.logicalPath);
31782
32045
  }
31783
- function publishingArticleSource(source) {
32046
+ function publishingArticleSource(source, digestOverride) {
31784
32047
  const match = ARTICLE_FRONTMATTER.exec(source);
31785
32048
  const yamlSource = match?.[1];
31786
32049
  const body = match?.[2];
@@ -31794,6 +32057,10 @@ function publishingArticleSource(source) {
31794
32057
  for (const key of LOCAL_WORKFLOW_FRONTMATTER_KEYS) {
31795
32058
  document.delete(key);
31796
32059
  }
32060
+ if (digestOverride !== void 0) {
32061
+ document.set("digest", digestOverride.trim());
32062
+ document.delete("wechat_digest");
32063
+ }
31797
32064
  return `---
31798
32065
  ${document.toString().trimEnd()}
31799
32066
  ---
@@ -31828,14 +32095,15 @@ async function preparePublishingDraft(input) {
31828
32095
  (candidate) => /^cover(?:[._-]|$)/iu.test(path6.basename(candidate))
31829
32096
  );
31830
32097
  const explicitCover = input.coverFile !== void 0 && input.coverFile !== "auto" ? input.coverFile : void 0;
31831
- const coverCandidate = explicitCover ?? articleCoverCandidate ?? namedCoverCandidate;
31832
- const coverMode = explicitCover !== void 0 ? "explicit-file" : articleCoverCandidate !== void 0 ? "article-frontmatter" : namedCoverCandidate !== void 0 ? "assets-directory" : void 0;
31833
- const planned = input.visualPlanFile === void 0 ? [] : await plannedInlineImages(input.visualPlanFile, availableByFileName);
32098
+ const planned = input.visualPlanFile === void 0 ? void 0 : await plannedVisualAssets(input.visualPlanFile, input.assetsDirectory);
32099
+ const coverCandidate = explicitCover ?? planned?.coverAbsolutePath ?? articleCoverCandidate ?? namedCoverCandidate;
32100
+ 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;
32101
+ const plannedInline = planned?.inline ?? [];
31834
32102
  const pickupCandidates = availableImages.filter(
31835
32103
  (candidate) => candidate !== namedCoverCandidate && candidate !== articleCoverCandidate && !referencedFiles.has(path6.resolve(candidate)) && input.visualPlanFile === void 0
31836
32104
  );
31837
32105
  const injected = [
31838
- ...planned,
32106
+ ...plannedInline,
31839
32107
  ...pickupCandidates.slice(0, Math.max(0, MAXIMUM_INLINE_IMAGES - referenced.size)).map((candidate) => {
31840
32108
  const digest = createHash6("sha256").update(candidate).digest("hex").slice(0, 12);
31841
32109
  const fileName = safeFileName(path6.basename(candidate)) || `visual-${digest}.png`;
@@ -31851,7 +32119,7 @@ async function preparePublishingDraft(input) {
31851
32119
  let bundle;
31852
32120
  try {
31853
32121
  parseArticleDocument(materializedSource);
31854
- finalSource = publishingArticleSource(materializedSource);
32122
+ finalSource = publishingArticleSource(materializedSource, input.digest);
31855
32123
  bundle = parseArticleDocument(finalSource);
31856
32124
  } catch (error) {
31857
32125
  if (error instanceof WechatCliError) {
@@ -31862,7 +32130,20 @@ async function preparePublishingDraft(input) {
31862
32130
  bundle = input.title === void 0 ? bundle : { ...bundle, title: input.title.trim() };
31863
32131
  const localRender = renderWechatArticle(bundle);
31864
32132
  if (!localRender.preflight.ok) {
31865
- throw new WechatCliError("DXC_PUBLISHING_PREFLIGHT_FAILED");
32133
+ const digestTooLong = localRender.preflight.errors.some(
32134
+ (error) => error.code === "DIGEST_TOO_LONG"
32135
+ );
32136
+ const guidance = digestTooLong ? `\u6458\u8981\u4E3A ${localRender.preflight.metrics.digestCharacters}/${LEGACY_DIGEST_CHARACTER_LIMIT} \u4E2A Unicode \u5B57\u7B26\uFF1B\u8BF7\u7F29\u77ED article frontmatter \u4E2D\u7684 digest \u540E\u91CD\u65B0\u9884\u89C8\u3002` : `\u672C\u5730\u9884\u68C0\u672A\u901A\u8FC7\uFF1A${localRender.preflight.errors.map((error) => `${error.code}\uFF08${error.message}\uFF09`).join("\uFF1B")}`;
32137
+ throw new WechatCliError(
32138
+ "DXC_PUBLISHING_PREFLIGHT_FAILED",
32139
+ guidance,
32140
+ false,
32141
+ digestTooLong ? {
32142
+ currentLength: localRender.preflight.metrics.digestCharacters,
32143
+ max: LEGACY_DIGEST_CHARACTER_LIMIT,
32144
+ metadataField: "digest"
32145
+ } : void 0
32146
+ );
31866
32147
  }
31867
32148
  if (localRender.preflight.metrics.imageCount > MAXIMUM_INLINE_IMAGES) {
31868
32149
  throw new WechatCliError("DXC_PUBLISHING_TOO_MANY_INLINE_IMAGES");
@@ -31913,9 +32194,356 @@ async function preparePublishingDraft(input) {
31913
32194
  };
31914
32195
  }
31915
32196
 
32197
+ // apps/cli/src/publishing-image-optimization.ts
32198
+ var import_yaml4 = __toESM(require_dist(), 1);
32199
+ import { createHash as createHash7, randomUUID as randomUUID4 } from "node:crypto";
32200
+ import { constants as fileConstants3 } from "node:fs";
32201
+ import {
32202
+ lstat as lstat6,
32203
+ mkdir as mkdir3,
32204
+ open as open3,
32205
+ readFile as readFile4,
32206
+ realpath as realpath2,
32207
+ rename as rename5,
32208
+ unlink as unlink3,
32209
+ writeFile as writeFile3
32210
+ } from "node:fs/promises";
32211
+ import path7 from "node:path";
32212
+ import sharp2 from "sharp";
32213
+ var MAXIMUM_INPUT_BYTES = 32 * 1024 * 1024;
32214
+ var INLINE_IMAGE_LIMIT = 1024 * 1024 - 1;
32215
+ var INLINE_IMAGE_TARGET = 950 * 1024;
32216
+ var COVER_IMAGE_LIMIT = 5 * 1024 * 1024;
32217
+ var COVER_IMAGE_TARGET = 4500 * 1024;
32218
+ var VISUAL_PLAN_MAXIMUM_BYTES2 = 128 * 1024;
32219
+ var VISUAL_PLAN_FRONTMATTER2 = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)([\s\S]*)$/u;
32220
+ function sha2562(value) {
32221
+ return createHash7("sha256").update(value).digest("hex");
32222
+ }
32223
+ function safeDerivativeBase(value) {
32224
+ return value.normalize("NFKC").replaceAll(/[^A-Za-z0-9._-]+/gu, "-").replaceAll(/^-+|-+$/gu, "").slice(0, 80) || "image";
32225
+ }
32226
+ function recordValue2(value) {
32227
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
32228
+ }
32229
+ function portablePath(value, label) {
32230
+ if (typeof value !== "string" || value.trim().length === 0 || path7.isAbsolute(value) || value.includes("\\") || value.split("/").some((segment) => segment === "" || segment === "." || segment === "..")) {
32231
+ throw new WechatCliError(
32232
+ "DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
32233
+ `${label} \u5FC5\u987B\u662F\u9879\u76EE\u5185\u4F7F\u7528 / \u5206\u9694\u7684\u5B89\u5168\u76F8\u5BF9\u8DEF\u5F84\u3002`
32234
+ );
32235
+ }
32236
+ return value;
32237
+ }
32238
+ function isWithin(target, directory) {
32239
+ const relative = path7.relative(directory, target);
32240
+ return relative === "" || !relative.startsWith(`..${path7.sep}`) && relative !== "..";
32241
+ }
32242
+ async function regularImage(target) {
32243
+ let handle;
32244
+ try {
32245
+ handle = await open3(target, fileConstants3.O_RDONLY | fileConstants3.O_NOFOLLOW);
32246
+ const metadata = await handle.stat();
32247
+ if (!metadata.isFile() || metadata.size <= 0 || metadata.size > MAXIMUM_INPUT_BYTES) {
32248
+ throw new Error("invalid image");
32249
+ }
32250
+ return await handle.readFile();
32251
+ } catch {
32252
+ throw new WechatCliError(
32253
+ "DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
32254
+ `\u65E0\u6CD5\u5B89\u5168\u8BFB\u53D6\u56FE\u7247 ${path7.basename(target)}\uFF1B\u6587\u4EF6\u5FC5\u987B\u662F\u5C0F\u4E8E ${MAXIMUM_INPUT_BYTES} bytes \u7684\u666E\u901A\u6587\u4EF6\u3002`
32255
+ );
32256
+ } finally {
32257
+ await handle?.close();
32258
+ }
32259
+ }
32260
+ async function requirePreservedAlpha(bytes) {
32261
+ const metadata = await sharp2(bytes, {
32262
+ failOn: "error",
32263
+ limitInputPixels: 8e7
32264
+ }).metadata();
32265
+ if (metadata.format !== "png" || metadata.hasAlpha !== true) {
32266
+ throw new WechatCliError(
32267
+ "DXC_PUBLISHING_IMAGE_ALPHA_LOST",
32268
+ "\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"
32269
+ );
32270
+ }
32271
+ }
32272
+ async function decodedImageMetadata(source, sourcePath) {
32273
+ let metadata;
32274
+ try {
32275
+ metadata = await sharp2(source, { failOn: "error", limitInputPixels: 8e7 }).metadata();
32276
+ } catch {
32277
+ throw new WechatCliError(
32278
+ "DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
32279
+ "\u56FE\u7247\u65E0\u6CD5\u88AB\u5B89\u5168\u89E3\u7801\uFF1B\u4EC5\u652F\u6301\u6709\u6548 PNG/JPEG\u3002"
32280
+ );
32281
+ }
32282
+ const extension = path7.extname(sourcePath).toLowerCase();
32283
+ const expectedFormat = extension === ".png" ? "png" : extension === ".jpg" || extension === ".jpeg" ? "jpeg" : void 0;
32284
+ if (expectedFormat === void 0 || metadata.format !== expectedFormat || metadata.width === void 0 || metadata.height === void 0) {
32285
+ throw new WechatCliError(
32286
+ "DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
32287
+ "\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"
32288
+ );
32289
+ }
32290
+ return {
32291
+ format: expectedFormat,
32292
+ hasAlpha: metadata.hasAlpha === true,
32293
+ height: metadata.height,
32294
+ width: metadata.width
32295
+ };
32296
+ }
32297
+ async function writeExclusiveOrVerify(target, bytes) {
32298
+ await mkdir3(path7.dirname(target), { recursive: true, mode: 448 });
32299
+ try {
32300
+ await writeFile3(target, bytes, { flag: "wx", mode: 384 });
32301
+ return true;
32302
+ } catch (error) {
32303
+ if (error.code !== "EEXIST") {
32304
+ throw error;
32305
+ }
32306
+ const existing = await regularImage(target);
32307
+ if (sha2562(existing) !== sha2562(bytes)) {
32308
+ throw new WechatCliError(
32309
+ "DXC_PUBLISHING_IMAGE_OPTIMIZATION_CONFLICT",
32310
+ `\u4F18\u5316\u76EE\u6807 ${path7.basename(target)} \u5DF2\u5B58\u5728\u4F46\u5185\u5BB9\u4E0D\u540C\uFF1B\u672A\u8986\u76D6\u4EFB\u4F55\u6587\u4EF6\u3002`
32311
+ );
32312
+ }
32313
+ return false;
32314
+ }
32315
+ }
32316
+ async function safeRealPathWithin(target, directory, label) {
32317
+ const resolved = await realpath2(target).catch(() => void 0);
32318
+ if (resolved === void 0 || !isWithin(resolved, directory)) {
32319
+ throw new WechatCliError(
32320
+ "DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
32321
+ `${label} \u7684\u771F\u5B9E\u8DEF\u5F84\u4E0D\u5728\u5141\u8BB8\u7684\u9879\u76EE\u76EE\u5F55\u5185\u3002`
32322
+ );
32323
+ }
32324
+ return resolved;
32325
+ }
32326
+ async function ensureSafeOptimizedDirectory(assetsDirectory, realAssetsDirectory) {
32327
+ const optimizedDirectory = path7.join(assetsDirectory, "optimized");
32328
+ await mkdir3(optimizedDirectory, { recursive: true, mode: 448 });
32329
+ const metadata = await lstat6(optimizedDirectory).catch(() => void 0);
32330
+ if (metadata === void 0 || !metadata.isDirectory() || metadata.isSymbolicLink()) {
32331
+ throw new WechatCliError(
32332
+ "DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
32333
+ "\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"
32334
+ );
32335
+ }
32336
+ await safeRealPathWithin(optimizedDirectory, realAssetsDirectory, "\u4F18\u5316\u76EE\u5F55");
32337
+ return optimizedDirectory;
32338
+ }
32339
+ async function writePlanAtomically(target, expectedSource, source) {
32340
+ const temporary = `${target}.${randomUUID4()}.tmp`;
32341
+ try {
32342
+ await writeFile3(temporary, source, { encoding: "utf8", flag: "wx", mode: 384 });
32343
+ if (await readFile4(target, "utf8") !== expectedSource) {
32344
+ throw new WechatCliError(
32345
+ "DXC_PUBLISHING_IMAGE_OPTIMIZATION_CONFLICT",
32346
+ "\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"
32347
+ );
32348
+ }
32349
+ await rename5(temporary, target);
32350
+ } finally {
32351
+ await unlink3(temporary).catch(() => void 0);
32352
+ }
32353
+ }
32354
+ function candidateWidths(width) {
32355
+ return [.../* @__PURE__ */ new Set([width, 2400, 2e3, 1600, 1280, 1080, 900, 720])].filter((candidate) => candidate > 0 && candidate <= width).sort((left, right) => right - left);
32356
+ }
32357
+ async function optimizedImage(source, targetBytes, metadata) {
32358
+ const hasAlpha = metadata.hasAlpha;
32359
+ for (const width of candidateWidths(metadata.width)) {
32360
+ if (hasAlpha) {
32361
+ const lossless = await sharp2(source, { failOn: "error", limitInputPixels: 8e7 }).rotate().resize({ fit: "inside", width, withoutEnlargement: true }).png({ compressionLevel: 9, effort: 10 }).toBuffer();
32362
+ if (lossless.byteLength <= targetBytes) {
32363
+ await requirePreservedAlpha(lossless);
32364
+ return { alphaPreserved: true, bytes: lossless, extension: ".png" };
32365
+ }
32366
+ for (const colours of [256, 192, 128, 96, 64]) {
32367
+ const quantized = await sharp2(source, {
32368
+ failOn: "error",
32369
+ limitInputPixels: 8e7
32370
+ }).rotate().resize({ fit: "inside", width, withoutEnlargement: true }).png({ colours, compressionLevel: 9, effort: 10, palette: true }).toBuffer();
32371
+ if (quantized.byteLength <= targetBytes) {
32372
+ await requirePreservedAlpha(quantized);
32373
+ return { alphaPreserved: true, bytes: quantized, extension: ".png" };
32374
+ }
32375
+ }
32376
+ continue;
32377
+ }
32378
+ for (const quality of [88, 82, 76, 70, 64, 58]) {
32379
+ 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();
32380
+ if (jpeg.byteLength <= targetBytes) {
32381
+ return { alphaPreserved: true, bytes: jpeg, extension: ".jpg" };
32382
+ }
32383
+ }
32384
+ }
32385
+ throw new WechatCliError(
32386
+ "DXC_PUBLISHING_IMAGE_OPTIMIZATION_LIMIT_UNREACHABLE",
32387
+ `\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`
32388
+ );
32389
+ }
32390
+ async function optimizePublishingImages(input) {
32391
+ const projectDirectory2 = path7.resolve(input.projectDirectory);
32392
+ const visualPlanPath = path7.resolve(input.visualPlanFile);
32393
+ if (!isWithin(visualPlanPath, projectDirectory2)) {
32394
+ throw new WechatCliError(
32395
+ "DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
32396
+ "\u89C6\u89C9\u8BA1\u5212\u5FC5\u987B\u4F4D\u4E8E\u5F53\u524D\u5185\u5BB9\u9879\u76EE\u5185\u3002"
32397
+ );
32398
+ }
32399
+ const projectMetadata = await lstat6(projectDirectory2).catch(() => void 0);
32400
+ const visualPlanMetadata = await lstat6(visualPlanPath).catch(() => void 0);
32401
+ if (projectMetadata === void 0 || !projectMetadata.isDirectory() || projectMetadata.isSymbolicLink() || visualPlanMetadata === void 0 || !visualPlanMetadata.isFile() || visualPlanMetadata.isSymbolicLink() || visualPlanMetadata.size > VISUAL_PLAN_MAXIMUM_BYTES2) {
32402
+ throw new WechatCliError(
32403
+ "DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
32404
+ "\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"
32405
+ );
32406
+ }
32407
+ const realProjectDirectory = await realpath2(projectDirectory2);
32408
+ await safeRealPathWithin(visualPlanPath, realProjectDirectory, "\u89C6\u89C9\u8BA1\u5212");
32409
+ const source = await readFile4(visualPlanPath, "utf8").catch(() => "");
32410
+ if (Buffer.byteLength(source, "utf8") > VISUAL_PLAN_MAXIMUM_BYTES2) {
32411
+ throw new WechatCliError("DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID");
32412
+ }
32413
+ const match = VISUAL_PLAN_FRONTMATTER2.exec(source);
32414
+ if (match?.[1] === void 0 || match[2] === void 0) {
32415
+ throw new WechatCliError("DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID");
32416
+ }
32417
+ let frontmatter;
32418
+ try {
32419
+ frontmatter = recordValue2((0, import_yaml4.parse)(match[1], { maxAliasCount: 10, uniqueKeys: true }));
32420
+ } catch {
32421
+ throw new WechatCliError("DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID");
32422
+ }
32423
+ if (frontmatter === void 0 || Object.hasOwn(frontmatter, "planned")) {
32424
+ throw new WechatCliError(
32425
+ "DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
32426
+ "\u89C6\u89C9\u8BA1\u5212\u5FC5\u987B\u5DF2\u7ECF\u5F15\u7528\u5B9E\u9645\u843D\u76D8\u56FE\u7247\uFF0C\u4E0D\u80FD\u4ECD\u5904\u4E8E\u751F\u6210\u6388\u6743\u9636\u6BB5\u3002"
32427
+ );
32428
+ }
32429
+ const assetsRelative = portablePath(frontmatter["assetsDirectory"], "assetsDirectory");
32430
+ const assetsDirectory = path7.resolve(projectDirectory2, assetsRelative);
32431
+ if (!isWithin(assetsDirectory, projectDirectory2)) {
32432
+ throw new WechatCliError("DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID");
32433
+ }
32434
+ const assetsMetadata = await lstat6(assetsDirectory).catch(() => void 0);
32435
+ if (assetsMetadata === void 0 || !assetsMetadata.isDirectory() || assetsMetadata.isSymbolicLink()) {
32436
+ throw new WechatCliError("DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID");
32437
+ }
32438
+ const realAssetsDirectory = await safeRealPathWithin(
32439
+ assetsDirectory,
32440
+ realProjectDirectory,
32441
+ "\u7D20\u6750\u76EE\u5F55"
32442
+ );
32443
+ const inlineAssets = Array.isArray(frontmatter["inlineAssets"]) ? frontmatter["inlineAssets"] : [];
32444
+ const entries = [
32445
+ {
32446
+ limit: COVER_IMAGE_LIMIT,
32447
+ record: { path: frontmatter["coverAsset"] },
32448
+ role: "cover",
32449
+ target: COVER_IMAGE_TARGET
32450
+ },
32451
+ ...inlineAssets.map((asset) => ({
32452
+ limit: INLINE_IMAGE_LIMIT,
32453
+ record: recordValue2(asset),
32454
+ role: "inline",
32455
+ target: INLINE_IMAGE_TARGET
32456
+ }))
32457
+ ];
32458
+ const createdFiles = [];
32459
+ const mutations = [];
32460
+ let unchangedCount = 0;
32461
+ let optimizedDirectory;
32462
+ try {
32463
+ for (const entry of entries) {
32464
+ const assetPath = portablePath(entry.record?.["path"], `${entry.role} \u56FE\u7247\u8DEF\u5F84`);
32465
+ const absolutePath = path7.resolve(projectDirectory2, assetPath);
32466
+ if (!isWithin(absolutePath, assetsDirectory)) {
32467
+ throw new WechatCliError(
32468
+ "DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
32469
+ `${assetPath} \u4E0D\u5728\u89C6\u89C9\u8BA1\u5212\u58F0\u660E\u7684\u7D20\u6750\u76EE\u5F55\u5185\u3002`
32470
+ );
32471
+ }
32472
+ await safeRealPathWithin(absolutePath, realAssetsDirectory, `${assetPath} \u56FE\u7247`);
32473
+ const bytes = await regularImage(absolutePath);
32474
+ const metadata = await decodedImageMetadata(bytes, assetPath);
32475
+ const beforeSha256 = sha2562(bytes);
32476
+ let finalPath = assetPath;
32477
+ let finalBytes = bytes;
32478
+ let alphaPreserved = true;
32479
+ if (bytes.byteLength > entry.limit) {
32480
+ const optimized = await optimizedImage(bytes, entry.target, metadata);
32481
+ optimizedDirectory ??= await ensureSafeOptimizedDirectory(
32482
+ assetsDirectory,
32483
+ realAssetsDirectory
32484
+ );
32485
+ const baseName = safeDerivativeBase(path7.basename(assetPath, path7.extname(assetPath)));
32486
+ const optimizedSha256 = sha2562(optimized.bytes);
32487
+ const optimizedName = `${baseName}-${entry.role}-${beforeSha256.slice(0, 12)}-${optimizedSha256.slice(0, 12)}${optimized.extension}`;
32488
+ const optimizedAbsolute = path7.join(optimizedDirectory, optimizedName);
32489
+ const created = await writeExclusiveOrVerify(optimizedAbsolute, optimized.bytes);
32490
+ if (created) {
32491
+ createdFiles.push(optimizedAbsolute);
32492
+ }
32493
+ finalPath = path7.relative(projectDirectory2, optimizedAbsolute).split(path7.sep).join("/");
32494
+ finalBytes = optimized.bytes;
32495
+ alphaPreserved = optimized.alphaPreserved;
32496
+ mutations.push({
32497
+ alphaPreserved,
32498
+ afterBytes: finalBytes.byteLength,
32499
+ afterSha256: sha2562(finalBytes),
32500
+ beforeBytes: bytes.byteLength,
32501
+ beforeSha256,
32502
+ from: assetPath,
32503
+ role: entry.role,
32504
+ to: finalPath
32505
+ });
32506
+ } else {
32507
+ unchangedCount += 1;
32508
+ }
32509
+ if (entry.role === "cover") {
32510
+ frontmatter["coverAsset"] = finalPath;
32511
+ frontmatter["coverSha256"] = sha2562(finalBytes);
32512
+ } else if (entry.record !== void 0) {
32513
+ entry.record["path"] = finalPath;
32514
+ entry.record["sha256"] = sha2562(finalBytes);
32515
+ }
32516
+ }
32517
+ frontmatter["inlineAssets"] = inlineAssets;
32518
+ const normalizedSource = `---
32519
+ ${(0, import_yaml4.stringify)(frontmatter, { lineWidth: 0 }).trimEnd()}
32520
+ ---
32521
+ ${match[2]}`;
32522
+ await writePlanAtomically(visualPlanPath, source, normalizedSource);
32523
+ } catch (error) {
32524
+ await Promise.all(createdFiles.map((target) => unlink3(target).catch(() => void 0)));
32525
+ if (error instanceof WechatCliError) {
32526
+ throw error;
32527
+ }
32528
+ throw new WechatCliError(
32529
+ "DXC_PUBLISHING_IMAGE_OPTIMIZATION_FAILED",
32530
+ "\u56FE\u7247\u4F18\u5316\u672A\u5B8C\u6210\uFF1B\u539F\u56FE\u548C\u89C6\u89C9\u8BA1\u5212\u5747\u672A\u88AB\u8986\u76D6\u3002"
32531
+ );
32532
+ }
32533
+ return {
32534
+ command: "wechat.draft.optimize-images",
32535
+ data: { mutations, unchangedCount, visualPlanPath },
32536
+ ok: true
32537
+ };
32538
+ }
32539
+
31916
32540
  // apps/cli/src/wechat.ts
31917
32541
  var DEFAULT_API_BASE_URL = "https://content.deployxai.com";
31918
32542
  var DEFAULT_POLL_INTERVAL_MS = 2e3;
32543
+ var MAXIMUM_LOCAL_PREVIEW_BYTES = 40 * 1024 * 1024;
32544
+ var WECHAT_AUTHOR_CHARACTER_LIMIT = 16;
32545
+ var WECHAT_DIGEST_CHARACTER_LIMIT = 120;
32546
+ var WECHAT_TITLE_CHARACTER_LIMIT = 32;
31919
32547
  function userFacingDraftIntent(intent) {
31920
32548
  const { status, ...userFacing } = intent;
31921
32549
  void status;
@@ -31931,6 +32559,158 @@ function writeAgentBrowserEvent(output, event) {
31931
32559
  `
31932
32560
  );
31933
32561
  }
32562
+ function escapeLocalPreviewText(value) {
32563
+ return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
32564
+ }
32565
+ function localPreviewImageSource(asset) {
32566
+ return `data:${publishingImageMediaType(asset.path)};base64,${asset.bytes.toString("base64")}`;
32567
+ }
32568
+ function localVisualPreviewHtml(prepared) {
32569
+ const replacements = new Map(
32570
+ prepared.inlineAssets.map((asset) => [asset.logicalPath, localPreviewImageSource(asset)])
32571
+ );
32572
+ const renderedArticle = rewriteWechatAssetSources(prepared.localRender.html, replacements);
32573
+ for (const asset of prepared.inlineAssets) {
32574
+ const originalSource = `src="${escapeLocalPreviewText(asset.logicalPath)}"`;
32575
+ if (!prepared.localRender.html.includes(originalSource) || renderedArticle.includes(originalSource)) {
32576
+ throw new WechatCliError(
32577
+ "DXC_PUBLISHING_LOCAL_PREVIEW_ASSET_MISMATCH",
32578
+ `\u672C\u5730\u9884\u89C8\u672A\u80FD\u5B8C\u6574\u5185\u8054\u6B63\u6587\u56FE\u7247 ${path8.basename(asset.path)}\uFF1B\u5DF2\u963B\u65AD\u8F93\u51FA\u3002`
32579
+ );
32580
+ }
32581
+ }
32582
+ const title = escapeLocalPreviewText(prepared.bundle.title);
32583
+ const coverSource = localPreviewImageSource(prepared.cover);
32584
+ const html = `<!doctype html>
32585
+ <html lang="zh-CN">
32586
+ <head>
32587
+ <meta charset="utf-8">
32588
+ <meta name="viewport" content="width=device-width, initial-scale=1">
32589
+ <meta name="referrer" content="no-referrer">
32590
+ <meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src data:; style-src 'unsafe-inline'; base-uri 'none'; form-action 'none'; object-src 'none'">
32591
+ <title>${title} \xB7 \u672C\u5730\u5E26\u56FE\u9884\u89C8</title>
32592
+ <style>
32593
+ :root { color-scheme: light; background: #f5f5f4; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; }
32594
+ body { margin: 0; color: #292524; }
32595
+ .dxc-shell { box-sizing: border-box; margin: 0 auto; max-width: 780px; min-height: 100vh; padding: 24px 16px 64px; }
32596
+ .dxc-notice { background: #fff7ed; border: 1px solid #fed7aa; border-radius: 12px; color: #9a3412; font-size: 13px; line-height: 1.6; margin-bottom: 16px; padding: 12px 14px; }
32597
+ .dxc-card { background: white; border: 1px solid #e7e5e4; border-radius: 16px; box-shadow: 0 12px 36px rgb(41 37 36 / 8%); overflow: hidden; }
32598
+ .dxc-cover { background: #e7e5e4; display: block; max-height: 360px; object-fit: cover; width: 100%; }
32599
+ .dxc-meta { border-bottom: 1px solid #f5f5f4; padding: 22px 24px 14px; }
32600
+ .dxc-meta h1 { font-size: 24px; line-height: 1.35; margin: 0 0 6px; }
32601
+ .dxc-meta p { color: #78716c; font-size: 13px; margin: 0; }
32602
+ .dxc-article { overflow-wrap: anywhere; padding: 8px 24px 32px; }
32603
+ .dxc-article img { height: auto; max-width: 100%; }
32604
+ .dxc-article a { pointer-events: none; }
32605
+ @media (max-width: 560px) { .dxc-shell { padding: 0 0 32px; } .dxc-card { border-radius: 0; border-width: 0; } .dxc-notice { border-radius: 0; margin: 0; } .dxc-meta, .dxc-article { padding-left: 18px; padding-right: 18px; } }
32606
+ </style>
32607
+ </head>
32608
+ <body>
32609
+ <main class="dxc-shell">
32610
+ <aside class="dxc-notice">\u672C\u5730\u5185\u5BB9\u4E0E\u914D\u56FE\u9884\u89C8\u3002\u5B83\u7528\u4E8E\u786E\u8BA4\u56FE\u7247\u3001\u951A\u70B9\u548C\u9605\u8BFB\u6548\u679C\uFF0C\u4E0D\u4EE3\u8868\u6700\u7EC8\u5FAE\u4FE1\u6A21\u677F\uFF1B\u521B\u5EFA\u8349\u7A3F\u524D\u4ECD\u987B\u67E5\u770B\u5E76\u786E\u8BA4\u4E91\u7AEF\u4E0D\u53EF\u53D8\u9884\u89C8\u3002</aside>
32611
+ <article class="dxc-card">
32612
+ <img class="dxc-cover" src="${coverSource}" alt="${title}\u5C01\u9762">
32613
+ <header class="dxc-meta"><h1>${title}</h1><p>${prepared.inlineAssets.length} \u5F20\u6B63\u6587\u914D\u56FE \xB7 \u672C\u5730\u6D3E\u751F\u9884\u89C8</p></header>
32614
+ <div class="dxc-article">${renderedArticle}</div>
32615
+ </article>
32616
+ </main>
32617
+ </body>
32618
+ </html>`;
32619
+ const bytes = Buffer.byteLength(html, "utf8");
32620
+ if (bytes > MAXIMUM_LOCAL_PREVIEW_BYTES) {
32621
+ throw new WechatCliError(
32622
+ "DXC_PUBLISHING_LOCAL_PREVIEW_TOO_LARGE",
32623
+ `\u672C\u5730\u5E26\u56FE\u9884\u89C8\u4E3A ${bytes} bytes\uFF0C\u8D85\u8FC7 ${MAXIMUM_LOCAL_PREVIEW_BYTES} bytes \u4E0A\u9650\u3002\u8BF7\u5148\u4F18\u5316\u56FE\u7247\u540E\u91CD\u8BD5\u3002`
32624
+ );
32625
+ }
32626
+ return {
32627
+ hash: createHash8("sha256").update(html, "utf8").digest("hex"),
32628
+ html
32629
+ };
32630
+ }
32631
+ function writeLocalPreviewBrowserEvent(output, event) {
32632
+ output.writeStderr(
32633
+ `DXC_BROWSER_EVENT ${JSON.stringify({
32634
+ action: "open-file",
32635
+ contentHash: event.contentHash,
32636
+ kind: "content-local-preview",
32637
+ path: event.path,
32638
+ replaceExisting: true,
32639
+ surface: "agent-side-panel"
32640
+ })}
32641
+ `
32642
+ );
32643
+ }
32644
+ function fileSystemErrorCode(error) {
32645
+ return typeof error === "object" && error !== null && "code" in error ? String(error.code) : void 0;
32646
+ }
32647
+ function localPreviewOutputConflict() {
32648
+ return new WechatCliError(
32649
+ "DXC_PUBLISHING_LOCAL_PREVIEW_OUTPUT_CONFLICT",
32650
+ "\u672C\u5730\u9884\u89C8\u8F93\u51FA\u53EA\u80FD\u4F4D\u4E8E\u5F53\u524D\u9879\u76EE\u7684 .dxc/previews \u76EE\u5F55\uFF0C\u4E14\u76EE\u5F55\u548C\u6587\u4EF6\u4E0D\u80FD\u662F\u7B26\u53F7\u94FE\u63A5\u3002"
32651
+ );
32652
+ }
32653
+ async function ensureLocalPreviewDirectory(directory) {
32654
+ let metadata;
32655
+ try {
32656
+ metadata = await lstat7(directory);
32657
+ } catch (error) {
32658
+ if (fileSystemErrorCode(error) !== "ENOENT") {
32659
+ throw error;
32660
+ }
32661
+ try {
32662
+ await mkdir4(directory, { mode: 448 });
32663
+ } catch (mkdirError) {
32664
+ if (fileSystemErrorCode(mkdirError) !== "EEXIST") {
32665
+ throw mkdirError;
32666
+ }
32667
+ }
32668
+ metadata = await lstat7(directory);
32669
+ }
32670
+ if (!metadata.isDirectory() || metadata.isSymbolicLink()) {
32671
+ throw localPreviewOutputConflict();
32672
+ }
32673
+ }
32674
+ async function safeLocalPreviewOutput(options) {
32675
+ const projectDirectory2 = path8.resolve(options.projectDirectory);
32676
+ const previewDirectory = path8.join(projectDirectory2, ".dxc", "previews");
32677
+ const outputFile = path8.resolve(options.outputFile);
32678
+ const relativeOutput = path8.relative(previewDirectory, outputFile);
32679
+ if (relativeOutput.length === 0 || relativeOutput === ".." || relativeOutput.startsWith(`..${path8.sep}`) || path8.isAbsolute(relativeOutput)) {
32680
+ throw localPreviewOutputConflict();
32681
+ }
32682
+ try {
32683
+ const projectMetadata = await lstat7(projectDirectory2);
32684
+ if (!projectMetadata.isDirectory() || projectMetadata.isSymbolicLink()) {
32685
+ throw localPreviewOutputConflict();
32686
+ }
32687
+ let directory = projectDirectory2;
32688
+ const relativeParent = path8.relative(projectDirectory2, path8.dirname(outputFile));
32689
+ for (const segment of relativeParent.split(path8.sep).filter((value) => value.length > 0)) {
32690
+ directory = path8.join(directory, segment);
32691
+ await ensureLocalPreviewDirectory(directory);
32692
+ }
32693
+ try {
32694
+ const outputMetadata = await lstat7(outputFile);
32695
+ if (!outputMetadata.isFile() || outputMetadata.isSymbolicLink()) {
32696
+ throw localPreviewOutputConflict();
32697
+ }
32698
+ } catch (error) {
32699
+ if (fileSystemErrorCode(error) !== "ENOENT") {
32700
+ throw error;
32701
+ }
32702
+ }
32703
+ } catch (error) {
32704
+ if (error instanceof WechatCliError) {
32705
+ throw error;
32706
+ }
32707
+ throw new WechatCliError(
32708
+ "DXC_PUBLISHING_LOCAL_PREVIEW_WRITE_FAILED",
32709
+ "\u65E0\u6CD5\u5B89\u5168\u5199\u5165\u672C\u5730\u5E26\u56FE\u9884\u89C8\uFF0C\u8BF7\u786E\u8BA4\u5F53\u524D\u9879\u76EE\u548C .dxc/previews \u76EE\u5F55\u53EF\u5199\u3002"
32710
+ );
32711
+ }
32712
+ return outputFile;
32713
+ }
31934
32714
  async function presentDraftPreview(output, openExternal, preview, browserMode) {
31935
32715
  if (browserMode === "agent") {
31936
32716
  writeAgentBrowserEvent(output, {
@@ -32012,13 +32792,13 @@ async function retryExpiredBrowserFlow(action, output) {
32012
32792
  }
32013
32793
  }
32014
32794
  function sessionPath(stateDirectory) {
32015
- return path7.join(stateDirectory, "wechat-session.json");
32795
+ return path8.join(stateDirectory, "wechat-session.json");
32016
32796
  }
32017
32797
  function deviceIdentityPath(stateDirectory) {
32018
- return path7.join(stateDirectory, "device-identity.json");
32798
+ return path8.join(stateDirectory, "device-identity.json");
32019
32799
  }
32020
32800
  function publishingMediaType(inputPath, kind) {
32021
- const extension = path7.extname(inputPath).toLowerCase();
32801
+ const extension = path8.extname(inputPath).toLowerCase();
32022
32802
  if (kind === "article-source" && (extension === ".md" || extension === ".markdown")) {
32023
32803
  return "text/markdown";
32024
32804
  }
@@ -32030,7 +32810,7 @@ function publishingMediaType(inputPath, kind) {
32030
32810
  async function readProtectedStateFile(target, invalidCode) {
32031
32811
  let handle;
32032
32812
  try {
32033
- handle = await open3(target, fileConstants3.O_RDONLY | fileConstants3.O_NOFOLLOW);
32813
+ handle = await open4(target, fileConstants4.O_RDONLY | fileConstants4.O_NOFOLLOW);
32034
32814
  } catch (error) {
32035
32815
  if (error instanceof WechatCliError) {
32036
32816
  throw error;
@@ -32052,17 +32832,17 @@ async function readProtectedStateFile(target, invalidCode) {
32052
32832
  }
32053
32833
  }
32054
32834
  async function saveSession(stateDirectory, session) {
32055
- await mkdir3(stateDirectory, { mode: 448, recursive: true });
32835
+ await mkdir4(stateDirectory, { mode: 448, recursive: true });
32056
32836
  await chmod(stateDirectory, 448);
32057
32837
  const target = sessionPath(stateDirectory);
32058
32838
  const temporary = `${target}.${process.pid}.tmp`;
32059
- await writeFile3(temporary, `${JSON.stringify(session)}
32839
+ await writeFile4(temporary, `${JSON.stringify(session)}
32060
32840
  `, {
32061
32841
  encoding: "utf8",
32062
32842
  mode: 384
32063
32843
  });
32064
32844
  await chmod(temporary, 384);
32065
- await rename5(temporary, target);
32845
+ await rename6(temporary, target);
32066
32846
  await chmod(target, 384);
32067
32847
  }
32068
32848
  async function readSessionValue(stateDirectory) {
@@ -32180,22 +32960,22 @@ async function loadOrCreateDeviceIdentity(stateDirectory) {
32180
32960
  const keyPair = generateDeviceKeyPair();
32181
32961
  const identity = {
32182
32962
  deviceName: os2.hostname().trim().slice(0, 80) || "DxC \u8BBE\u5907",
32183
- installationId: randomUUID4(),
32963
+ installationId: randomUUID5(),
32184
32964
  privateKeyPem: keyPair.privateKeyPem,
32185
32965
  publicKeyFingerprint: keyPair.publicKeyFingerprint,
32186
32966
  publicKeyPem: keyPair.publicKeyPem
32187
32967
  };
32188
- await mkdir3(stateDirectory, { mode: 448, recursive: true });
32968
+ await mkdir4(stateDirectory, { mode: 448, recursive: true });
32189
32969
  await chmod(stateDirectory, 448);
32190
32970
  const target = deviceIdentityPath(stateDirectory);
32191
32971
  const temporary = `${target}.${process.pid}.tmp`;
32192
- await writeFile3(temporary, `${JSON.stringify(identity)}
32972
+ await writeFile4(temporary, `${JSON.stringify(identity)}
32193
32973
  `, {
32194
32974
  encoding: "utf8",
32195
32975
  mode: 384
32196
32976
  });
32197
32977
  await chmod(temporary, 384);
32198
- await rename5(temporary, target);
32978
+ await rename6(temporary, target);
32199
32979
  await chmod(target, 384);
32200
32980
  return { created: true, identity };
32201
32981
  }
@@ -32207,14 +32987,32 @@ async function responseJson(response) {
32207
32987
  }
32208
32988
  }
32209
32989
  async function checkedJson(response) {
32210
- const value = await responseJson(response);
32990
+ let value;
32991
+ try {
32992
+ value = await responseJson(response);
32993
+ } catch (error) {
32994
+ if (!response.ok && error instanceof WechatCliError && error.code === "DXC_API_RESPONSE_INVALID") {
32995
+ throw new WechatCliError(
32996
+ "DXC_API_REQUEST_FAILED",
32997
+ `DxC API \u8FD4\u56DE HTTP ${response.status}\uFF0C\u4E14\u54CD\u5E94\u4E0D\u662F\u53EF\u8BC6\u522B\u7684 JSON \u9519\u8BEF\u3002\u8BF7\u4FDD\u7559\u8BE5\u72B6\u6001\u7801\uFF0C\u5E76\u6838\u5BF9 CLI \u4E0E\u670D\u52A1\u7AEF\u662F\u5426\u5DF2\u90E8\u7F72\u540C\u4E00\u53D1\u5E03\u7248\u672C\uFF1B\u5728\u8349\u7A3F\u521B\u5EFA\u94FE\u8DEF\u4E2D\u4E0D\u8981\u6539\u7528\u65B0\u7684\u5E42\u7B49\u952E\u91CD\u8BD5\u3002`,
32998
+ response.status === 429 || response.status >= 500,
32999
+ { httpStatus: response.status }
33000
+ );
33001
+ }
33002
+ throw error;
33003
+ }
32211
33004
  if (!response.ok) {
32212
33005
  const apiError = apiErrorResponseSchema.safeParse(value);
32213
33006
  if (apiError.success) {
32214
33007
  const guidance = apiError.data.error.code === "PUBLISHING_PREVIEW_REQUIRED" ? "\u670D\u52A1\u7AEF\u5C1A\u672A\u8BB0\u5F55\u4F60\u5B9E\u9645\u67E5\u770B\u8FC7\u6700\u7EC8\u9884\u89C8\u3002\u8BF7\u5BF9\u540C\u4E00 root \u5FEB\u7167\u8FD0\u884C preview-refresh --browser system\uFF0C\u786E\u8BA4\u7CFB\u7EDF\u6D4F\u89C8\u5668\u5DF2\u6253\u5F00\u9875\u9762\u540E\u518D\u521B\u5EFA\u8349\u7A3F\u3002" : apiError.data.error.message;
32215
33008
  throw new WechatCliError(apiError.data.error.code, guidance, apiError.data.error.retryable);
32216
33009
  }
32217
- throw new WechatCliError("DXC_API_REQUEST_FAILED");
33010
+ throw new WechatCliError(
33011
+ "DXC_API_REQUEST_FAILED",
33012
+ `DxC API \u8FD4\u56DE HTTP ${response.status}\uFF0C\u4F46\u54CD\u5E94\u4E0D\u7B26\u5408\u7EA6\u5B9A\u9519\u8BEF\u683C\u5F0F\u3002\u8BF7\u4FDD\u7559\u8BE5\u72B6\u6001\u7801\uFF0C\u5E76\u6838\u5BF9 CLI \u4E0E\u670D\u52A1\u7AEF\u662F\u5426\u5DF2\u90E8\u7F72\u540C\u4E00\u53D1\u5E03\u7248\u672C\uFF1B\u5728\u8349\u7A3F\u521B\u5EFA\u94FE\u8DEF\u4E2D\u4E0D\u8981\u6539\u7528\u65B0\u7684\u5E42\u7B49\u952E\u91CD\u8BD5\u3002`,
33013
+ response.status === 429 || response.status >= 500,
33014
+ { httpStatus: response.status }
33015
+ );
32218
33016
  }
32219
33017
  return value;
32220
33018
  }
@@ -32224,10 +33022,10 @@ function authorizationHeaders(clientToken) {
32224
33022
  };
32225
33023
  }
32226
33024
  function secretHash(value) {
32227
- return createHash7("sha256").update(value, "utf8").digest("hex");
33025
+ return createHash8("sha256").update(value, "utf8").digest("hex");
32228
33026
  }
32229
33027
  function bytesHash(value) {
32230
- return createHash7("sha256").update(value).digest("hex");
33028
+ return createHash8("sha256").update(value).digest("hex");
32231
33029
  }
32232
33030
  function assertCompleteInlineAssets(expected, actual) {
32233
33031
  const expectedRecords = expected.map((asset) => ({
@@ -32256,7 +33054,7 @@ var WechatCli = class {
32256
33054
  this.#openExternal = dependencies.openExternal ?? defaultOpenExternal;
32257
33055
  this.#pollIntervalMilliseconds = dependencies.pollIntervalMilliseconds ?? DEFAULT_POLL_INTERVAL_MS;
32258
33056
  this.#sleep = dependencies.sleep ?? defaultSleep;
32259
- this.#stateDirectory = dependencies.stateDirectory ?? process.env["DXC_CLI_STATE_DIR"] ?? path7.join(os2.homedir(), ".dxc");
33057
+ this.#stateDirectory = dependencies.stateDirectory ?? process.env["DXC_CLI_STATE_DIR"] ?? path8.join(os2.homedir(), ".dxc");
32260
33058
  }
32261
33059
  async #authenticatedFetch(session, url, init = {}, timeoutMilliseconds = 8e3) {
32262
33060
  const request = async (current) => {
@@ -32339,7 +33137,7 @@ var WechatCli = class {
32339
33137
  const pending = session.pendingRefresh ?? {
32340
33138
  nextDeviceRefreshToken: randomBytes(32).toString("base64url"),
32341
33139
  nextDeviceToken: randomBytes(32).toString("base64url"),
32342
- rotationId: randomUUID4()
33140
+ rotationId: randomUUID5()
32343
33141
  };
32344
33142
  const pendingSession = {
32345
33143
  apiBaseUrl: session.apiBaseUrl,
@@ -32473,8 +33271,7 @@ var WechatCli = class {
32473
33271
  `);
32474
33272
  return result;
32475
33273
  }
32476
- async previewDraft(options, output) {
32477
- let session = await loadSession(this.#stateDirectory);
33274
+ async previewLocalDraft(options, output) {
32478
33275
  const prepared = await preparePublishingDraft({
32479
33276
  articleFile: options.articleFile,
32480
33277
  ...options.assetsDirectory === void 0 ? {} : { assetsDirectory: options.assetsDirectory },
@@ -32482,9 +33279,123 @@ var WechatCli = class {
32482
33279
  ...options.title === void 0 ? {} : { title: options.title },
32483
33280
  ...options.visualPlanFile === void 0 ? {} : { visualPlanFile: options.visualPlanFile }
32484
33281
  });
33282
+ const preview = localVisualPreviewHtml(prepared);
33283
+ const outputFile = await safeLocalPreviewOutput({
33284
+ outputFile: options.outputFile,
33285
+ projectDirectory: options.projectDirectory
33286
+ });
33287
+ const protectedInputs = /* @__PURE__ */ new Set([
33288
+ path8.resolve(prepared.article.path),
33289
+ path8.resolve(prepared.cover.path),
33290
+ ...prepared.inlineAssets.map((asset) => path8.resolve(asset.path)),
33291
+ ...options.visualPlanFile === void 0 ? [] : [path8.resolve(options.visualPlanFile)]
33292
+ ]);
33293
+ if (protectedInputs.has(outputFile)) {
33294
+ throw new WechatCliError(
33295
+ "DXC_PUBLISHING_LOCAL_PREVIEW_OUTPUT_CONFLICT",
33296
+ "\u672C\u5730\u9884\u89C8\u8F93\u51FA\u4E0D\u80FD\u8986\u76D6\u6B63\u6587\u3001\u89C6\u89C9\u8BA1\u5212\u3001\u5C01\u9762\u6216\u6B63\u6587\u56FE\u7247\uFF1B\u8BF7\u4F7F\u7528\u9879\u76EE\u7684 .dxc/previews \u76EE\u5F55\u3002"
33297
+ );
33298
+ }
33299
+ try {
33300
+ await writePrivateBuffer(outputFile, Buffer.from(preview.html, "utf8"));
33301
+ } catch {
33302
+ throw new WechatCliError(
33303
+ "DXC_PUBLISHING_LOCAL_PREVIEW_WRITE_FAILED",
33304
+ "\u65E0\u6CD5\u5B89\u5168\u5199\u5165\u672C\u5730\u5E26\u56FE\u9884\u89C8\uFF0C\u8BF7\u786E\u8BA4\u8F93\u51FA\u76EE\u5F55\u4F4D\u4E8E\u5F53\u524D\u5185\u5BB9\u9879\u76EE\u4E14\u53EF\u5199\u3002"
33305
+ );
33306
+ }
33307
+ const result = {
33308
+ command: options.resultCommand ?? "wechat.draft.preview-local",
33309
+ data: {
33310
+ contentHash: preview.hash,
33311
+ inlineImageCount: prepared.inlineAssets.length,
33312
+ path: outputFile,
33313
+ presentation: {
33314
+ action: "open-file",
33315
+ replaceExisting: true,
33316
+ surface: "agent-side-panel"
33317
+ },
33318
+ templateId: prepared.localRender.templateId
33319
+ },
33320
+ ok: true
33321
+ };
33322
+ output.writeStdout(`${JSON.stringify(result)}
33323
+ `);
33324
+ writeLocalPreviewBrowserEvent(output, { contentHash: preview.hash, path: outputFile });
33325
+ output.writeStderr(
33326
+ "\u672C\u5730\u5E26\u56FE\u9884\u89C8\u5DF2\u66F4\u65B0\uFF1B\u8BF7\u5728 Agent \u53F3\u4FA7\u66FF\u6362\u5F53\u524D\u6587\u7AE0\u9884\u89C8\u3002\u6700\u7EC8\u5FAE\u4FE1\u6A21\u677F\u4ECD\u4EE5\u4E91\u7AEF\u4E0D\u53EF\u53D8\u9884\u89C8\u4E3A\u51C6\u3002\n"
33327
+ );
33328
+ return result;
33329
+ }
33330
+ async optimizeDraftImages(options, output) {
33331
+ const result = await optimizePublishingImages(options);
33332
+ output.writeStdout(`${JSON.stringify(result)}
33333
+ `);
33334
+ output.writeStderr(
33335
+ result.data.mutations.length === 0 ? `\u56FE\u7247\u5747\u5DF2\u7B26\u5408\u5FAE\u4FE1\u4EA4\u4ED8\u4F53\u79EF\u8981\u6C42\uFF1B\u5DF2\u590D\u7B97 ${result.data.unchangedCount} \u5F20\u56FE\u7247\u54C8\u5E0C\u3002
33336
+ ` : `\u5DF2\u751F\u6210 ${result.data.mutations.length} \u5F20\u4F18\u5316\u6D3E\u751F\u56FE\u5E76\u66F4\u65B0\u89C6\u89C9\u8BA1\u5212\uFF1B\u539F\u56FE\u672A\u88AB\u8986\u76D6\uFF0C\u5FC5\u987B\u91CD\u65B0\u5199 visual-plan checkpoint \u548C\u5E26\u56FE\u9884\u89C8\u3002
33337
+ `
33338
+ );
33339
+ return result;
33340
+ }
33341
+ async previewDraft(options, output) {
33342
+ let session = await loadSession(this.#stateDirectory);
33343
+ if (options.title !== void 0 && options.title.trim().length === 0) {
33344
+ throw new WechatCliError(
33345
+ "DXC_PUBLISHING_TITLE_TOO_LONG",
33346
+ `\u6807\u9898\u4E0D\u80FD\u4E3A\u7A7A\uFF1B\u8BF7\u901A\u8FC7 article frontmatter \u6216 --title \u63D0\u4F9B\u4E0D\u8D85\u8FC7 ${WECHAT_TITLE_CHARACTER_LIMIT} \u4E2A Unicode \u5B57\u7B26\u7684\u6807\u9898\u3002`,
33347
+ false,
33348
+ { currentLength: 0, empty: true, max: WECHAT_TITLE_CHARACTER_LIMIT }
33349
+ );
33350
+ }
33351
+ let prepared;
33352
+ try {
33353
+ prepared = await preparePublishingDraft({
33354
+ articleFile: options.articleFile,
33355
+ ...options.assetsDirectory === void 0 ? {} : { assetsDirectory: options.assetsDirectory },
33356
+ ...options.coverFile === void 0 ? {} : { coverFile: options.coverFile },
33357
+ ...options.digest === void 0 ? {} : { digest: options.digest },
33358
+ ...options.title === void 0 ? {} : { title: options.title },
33359
+ ...options.visualPlanFile === void 0 ? {} : { visualPlanFile: options.visualPlanFile }
33360
+ });
33361
+ } catch (error) {
33362
+ if (error instanceof WechatCliError && error.code === "DXC_PUBLISHING_PREFLIGHT_FAILED" && error.fields?.["metadataField"] === "digest") {
33363
+ const currentLength = error.fields["currentLength"];
33364
+ const max = error.fields["max"];
33365
+ throw new WechatCliError("DXC_PUBLISHING_DIGEST_TOO_LONG", error.guidance, false, {
33366
+ ...typeof currentLength === "number" ? { currentLength } : {},
33367
+ ...typeof max === "number" ? { max } : {}
33368
+ });
33369
+ }
33370
+ throw error;
33371
+ }
32485
33372
  const finalBundle = prepared.bundle;
32486
- if (finalBundle.title.length === 0 || [...finalBundle.title].length > 32 || [...finalBundle.author].length > 16 || [...finalBundle.digest].length > 120) {
32487
- throw new WechatCliError("DXC_PUBLISHING_WECHAT_METADATA_INVALID");
33373
+ const titleLength = [...finalBundle.title].length;
33374
+ if (titleLength === 0 || titleLength > WECHAT_TITLE_CHARACTER_LIMIT) {
33375
+ throw new WechatCliError(
33376
+ "DXC_PUBLISHING_TITLE_TOO_LONG",
33377
+ titleLength === 0 ? `\u6807\u9898\u4E0D\u80FD\u4E3A\u7A7A\uFF1B\u8BF7\u901A\u8FC7 article frontmatter \u6216 --title \u63D0\u4F9B\u4E0D\u8D85\u8FC7 ${WECHAT_TITLE_CHARACTER_LIMIT} \u4E2A Unicode \u5B57\u7B26\u7684\u6807\u9898\u3002` : `\u6807\u9898\u4E3A ${titleLength}/${WECHAT_TITLE_CHARACTER_LIMIT} \u4E2A Unicode \u5B57\u7B26\uFF1B\u8BF7\u7F29\u77ED article frontmatter \u4E2D\u7684 title\uFF0C\u6216\u4F7F\u7528 --title \u8986\u76D6\u540E\u91CD\u65B0\u9884\u89C8\u3002`,
33378
+ false,
33379
+ { currentLength: titleLength, empty: titleLength === 0, max: WECHAT_TITLE_CHARACTER_LIMIT }
33380
+ );
33381
+ }
33382
+ const authorLength = [...finalBundle.author].length;
33383
+ if (authorLength > WECHAT_AUTHOR_CHARACTER_LIMIT) {
33384
+ throw new WechatCliError(
33385
+ "DXC_PUBLISHING_AUTHOR_TOO_LONG",
33386
+ `\u4F5C\u8005\u4E3A ${authorLength}/${WECHAT_AUTHOR_CHARACTER_LIMIT} \u4E2A Unicode \u5B57\u7B26\uFF1B\u8BF7\u7F29\u77ED article frontmatter \u4E2D\u7684 author \u540E\u91CD\u65B0\u9884\u89C8\u3002`,
33387
+ false,
33388
+ { currentLength: authorLength, max: WECHAT_AUTHOR_CHARACTER_LIMIT }
33389
+ );
33390
+ }
33391
+ const digestLength = [...finalBundle.digest].length;
33392
+ if (digestLength > WECHAT_DIGEST_CHARACTER_LIMIT) {
33393
+ throw new WechatCliError(
33394
+ "DXC_PUBLISHING_DIGEST_TOO_LONG",
33395
+ `\u6458\u8981\u4E3A ${digestLength}/${WECHAT_DIGEST_CHARACTER_LIMIT} \u4E2A Unicode \u5B57\u7B26\uFF1B\u8BF7\u7F29\u77ED article frontmatter \u4E2D\u7684 digest\uFF0C\u6216\u4F7F\u7528 --digest \u8986\u76D6\u540E\u91CD\u65B0\u9884\u89C8\u3002`,
33396
+ false,
33397
+ { currentLength: digestLength, max: WECHAT_DIGEST_CHARACTER_LIMIT }
33398
+ );
32488
33399
  }
32489
33400
  const accountsResult = await this.#authenticatedFetch(
32490
33401
  session,
@@ -32557,6 +33468,13 @@ var WechatCli = class {
32557
33468
  );
32558
33469
  const preview = publishingPreviewLinkSchema.parse(await checkedJson(previewResponse.response));
32559
33470
  const browserMode = options.browserMode ?? "system";
33471
+ const templateWarnings = prepared.bundle.templateHint !== void 0 && prepared.bundle.templateHint !== snapshot.templateId ? [
33472
+ {
33473
+ code: "DXC_PUBLISHING_TEMPLATE_HINT_MISMATCH",
33474
+ effectiveTemplateId: snapshot.templateId,
33475
+ requestedHintTemplateId: prepared.bundle.templateHint
33476
+ }
33477
+ ] : [];
32560
33478
  const result = {
32561
33479
  account,
32562
33480
  presentation: {
@@ -32564,10 +33482,17 @@ var WechatCli = class {
32564
33482
  surface: browserMode === "agent" ? "agent-side-panel" : "system-browser"
32565
33483
  },
32566
33484
  preview,
32567
- snapshot
33485
+ snapshot,
33486
+ ...templateWarnings.length === 0 ? {} : { warnings: templateWarnings }
32568
33487
  };
32569
33488
  output.writeStdout(`${JSON.stringify(result)}
32570
33489
  `);
33490
+ if (templateWarnings[0] !== void 0) {
33491
+ output.writeStderr(
33492
+ `${templateWarnings[0].code}: \u6587\u7AE0\u63D0\u793A\u6A21\u677F\u4E3A ${templateWarnings[0].requestedHintTemplateId}\uFF0C\u4E91\u7AEF\u5FEB\u7167\u5B9E\u9645\u4F7F\u7528 ${templateWarnings[0].effectiveTemplateId}\uFF1B\u8BF7\u4EE5\u9884\u89C8\u9875\u4E2D\u7684\u5F53\u524D\u6A21\u677F\u4E3A\u51C6\uFF0C\u786E\u8BA4\u524D\u4E0D\u8981\u5047\u5B9A\u63D0\u793A\u6A21\u677F\u5DF2\u751F\u6548\u3002
33493
+ `
33494
+ );
33495
+ }
32571
33496
  const previewSecondsRemaining = preview.expiresInSeconds ?? Math.max(0, Math.floor((Date.parse(preview.expiresAt) - Date.now()) / 1e3));
32572
33497
  output.writeStderr(
32573
33498
  `\u9884\u89C8\u5C06\u5728 ${previewSecondsRemaining} \u79D2\u540E\u5931\u6548\uFF1B\u5FEB\u7167\u672C\u8EAB\u4E0D\u53D8\uFF0C\u8FC7\u671F\u540E\u53EF\u91CD\u5EFA\u77ED\u65F6\u94FE\u63A5\u3002
@@ -32576,7 +33501,8 @@ var WechatCli = class {
32576
33501
  const coverDescription = {
32577
33502
  "article-frontmatter": "\u6587\u7AE0\u58F0\u660E\u7684\u5185\u5BB9\u5C01\u9762",
32578
33503
  "assets-directory": "\u89C6\u89C9\u9636\u6BB5\u51C6\u5907\u7684\u5185\u5BB9\u5C01\u9762",
32579
- "explicit-file": "\u663E\u5F0F\u6307\u5B9A\u7684\u5185\u5BB9\u5C01\u9762"
33504
+ "explicit-file": "\u663E\u5F0F\u6307\u5B9A\u7684\u5185\u5BB9\u5C01\u9762",
33505
+ "visual-plan": "\u89C6\u89C9\u8BA1\u5212\u786E\u8BA4\u7684\u5185\u5BB9\u5C01\u9762"
32580
33506
  }[prepared.coverMode];
32581
33507
  output.writeStderr(
32582
33508
  `\u5C01\u9762\uFF1A${coverDescription}\uFF1B\u6B63\u6587\u56FE\u7247\uFF1A${prepared.inlineAssets.length} \u5F20\uFF08\u5176\u4E2D\u4ECE\u6307\u5B9A\u7D20\u6750\u76EE\u5F55\u91C7\u96C6 ${prepared.collectedInlineCount} \u5F20\uFF09\u3002
@@ -32606,6 +33532,22 @@ var WechatCli = class {
32606
33532
  await presentDraftPreview(output, this.#openExternal, preview, options.browserMode ?? "system");
32607
33533
  return preview;
32608
33534
  }
33535
+ async draftPreviewStatus(options, output) {
33536
+ const session = await loadSession(this.#stateDirectory);
33537
+ const { response } = await this.#authenticatedFetch(
33538
+ session,
33539
+ `${session.apiBaseUrl}/api/v1/render-snapshots/${encodeURIComponent(options.snapshotId)}/preview-state?snapshotHash=${encodeURIComponent(options.snapshotHash)}`
33540
+ );
33541
+ const state = publishingPreviewSelectionStateSchema.parse(await checkedJson(response));
33542
+ output.writeStdout(`${JSON.stringify({ previewState: state })}
33543
+ `);
33544
+ output.writeStderr(
33545
+ state.viewed ? `\u5F53\u524D\u6700\u7EC8\u6A21\u677F\uFF1A${state.templateId}\uFF1B\u9009\u62E9\u4FEE\u8BA2 ${state.selectionRevision} \u5DF2\u6210\u529F\u6253\u5F00\u3002
33546
+ ` : `\u5F53\u524D\u6700\u7EC8\u6A21\u677F\uFF1A${state.templateId}\uFF1B\u9009\u62E9\u4FEE\u8BA2 ${state.selectionRevision} \u5C1A\u672A\u6210\u529F\u6253\u5F00\uFF0C\u4E0D\u80FD\u786E\u8BA4\u521B\u5EFA\u8349\u7A3F\u3002
33547
+ `
33548
+ );
33549
+ return state;
33550
+ }
32609
33551
  async createDraft(options, output) {
32610
33552
  if (!options.confirmed) {
32611
33553
  throw new WechatCliError(
@@ -32666,6 +33608,84 @@ var WechatCli = class {
32666
33608
  );
32667
33609
  return result;
32668
33610
  }
33611
+ async retryDraft(options, output) {
33612
+ if (!options.confirmed) {
33613
+ throw new WechatCliError(
33614
+ "DXC_DRAFT_RETRY_CONFIRMATION_REQUIRED",
33615
+ "\u5B89\u5168\u91CD\u8BD5\u4F1A\u521B\u5EFA\u4E00\u4E2A\u65B0\u7684\u8349\u7A3F\u610F\u56FE\uFF1B\u8BF7\u786E\u8BA4\u539F\u610F\u56FE\u660E\u786E\u5931\u8D25\u540E\u589E\u52A0 --confirm\u3002"
33616
+ );
33617
+ }
33618
+ let delivery;
33619
+ try {
33620
+ delivery = await readDeliveryRetryIdentity(options.deliveryFile);
33621
+ } catch (error) {
33622
+ throw new WechatCliError(
33623
+ "DXC_DRAFT_DELIVERY_INVALID",
33624
+ error instanceof StageArtifactValidationError ? error.message : "\u65E0\u6CD5\u8BFB\u53D6 delivery \u9636\u6BB5\u4EA7\u7269\u3002"
33625
+ );
33626
+ }
33627
+ if (delivery.state !== "failed" || delivery.intentId !== options.previousIntentId) {
33628
+ throw new WechatCliError(
33629
+ "DXC_DRAFT_RETRY_NOT_SAFE",
33630
+ "delivery \u5FC5\u987B\u660E\u786E\u8BB0\u5F55\u5F53\u524D\u610F\u56FE\u4E3A failed\uFF1B\u7ED3\u679C\u672A\u77E5\u3001\u9700\u4EBA\u5DE5\u6838\u5BF9\u6216\u4ECD\u5728\u5904\u7406\u7684\u610F\u56FE\u7981\u6B62\u91CD\u8BD5\u3002"
33631
+ );
33632
+ }
33633
+ let session = await loadSession(this.#stateDirectory);
33634
+ const previousResponse = await this.#authenticatedFetch(
33635
+ session,
33636
+ `${session.apiBaseUrl}/api/v1/draft-intents/${encodeURIComponent(options.previousIntentId)}`
33637
+ );
33638
+ session = previousResponse.session;
33639
+ const previous = publishingDraftIntentResponseSchema.parse(
33640
+ await checkedJson(previousResponse.response)
33641
+ ).intent;
33642
+ if (previous.status !== "FAILED" || previous.snapshotHash !== delivery.selectedSnapshotHash) {
33643
+ throw new WechatCliError(
33644
+ "DXC_DRAFT_RETRY_NOT_SAFE",
33645
+ "\u670D\u52A1\u7AEF\u672A\u8BC1\u660E\u539F\u610F\u56FE\u5728\u5916\u90E8\u526F\u4F5C\u7528\u53D1\u751F\u524D\u5931\u8D25\uFF0C\u6216\u5FEB\u7167\u4E0E delivery \u4E0D\u4E00\u81F4\uFF1B\u7981\u6B62\u521B\u5EFA\u65B0\u610F\u56FE\u3002"
33646
+ );
33647
+ }
33648
+ const idempotencyKey = `dxc:retry:${previous.id}:${delivery.retryAttempt + 1}`;
33649
+ const retryRequest = createPublishingDraftIntentRequestSchema.parse({
33650
+ approvalId: previous.approvalId,
33651
+ previousIntentId: previous.id
33652
+ });
33653
+ const retryResponse = await this.#authenticatedFetch(
33654
+ session,
33655
+ `${session.apiBaseUrl}/api/v1/draft-intents`,
33656
+ {
33657
+ body: JSON.stringify(retryRequest),
33658
+ headers: {
33659
+ "content-type": "application/json",
33660
+ "idempotency-key": idempotencyKey
33661
+ },
33662
+ method: "POST"
33663
+ }
33664
+ );
33665
+ const result = publishingDraftIntentResponseSchema.parse(
33666
+ await checkedJson(retryResponse.response)
33667
+ );
33668
+ try {
33669
+ await bindDeliveryRetryIntentArtifact({
33670
+ idempotencyKey,
33671
+ intent: result.intent,
33672
+ previousIntentId: previous.id,
33673
+ target: options.deliveryFile
33674
+ });
33675
+ } catch (error) {
33676
+ throw new WechatCliError(
33677
+ "DXC_DRAFT_RETRY_DELIVERY_WRITE_FAILED",
33678
+ error instanceof StageArtifactValidationError ? error.message : "\u65B0\u91CD\u8BD5\u610F\u56FE\u5DF2\u521B\u5EFA\uFF0C\u4F46 delivery \u5199\u56DE\u5931\u8D25\uFF1B\u4E0D\u8981\u518D\u6B21\u91CD\u8BD5\uFF0C\u8BF7\u5148\u67E5\u8BE2\u5F53\u524D\u610F\u56FE\u3002"
33679
+ );
33680
+ }
33681
+ output.writeStdout(`${JSON.stringify({ intent: userFacingDraftIntent(result.intent) })}
33682
+ `);
33683
+ output.writeStderr(
33684
+ `${result.intent.progress.label}\uFF1A\u5DF2\u4ECE\u660E\u786E\u5931\u8D25\u7684\u610F\u56FE\u521B\u5EFA\u7B2C ${delivery.retryAttempt + 1} \u6B21\u663E\u5F0F\u91CD\u8BD5\uFF1B\u4E0D\u8981\u91CD\u590D\u63D0\u4EA4\u3002
33685
+ `
33686
+ );
33687
+ return result;
33688
+ }
32669
33689
  async publishingDraftStatus(intentId, output) {
32670
33690
  const session = await loadSession(this.#stateDirectory);
32671
33691
  const { response } = await this.#authenticatedFetch(
@@ -32776,7 +33796,7 @@ var WechatCli = class {
32776
33796
  `${session.apiBaseUrl}/api/v1/uploads`,
32777
33797
  {
32778
33798
  body: JSON.stringify({
32779
- fileName: path7.basename(input.path),
33799
+ fileName: path8.basename(input.path),
32780
33800
  kind,
32781
33801
  mediaType,
32782
33802
  sha256: bytesHash(input.bytes),
@@ -33021,8 +34041,8 @@ ${session.authorizationUrl}
33021
34041
  );
33022
34042
  const deviceSessionToken = randomBytes(32).toString("base64url");
33023
34043
  const deviceRefreshToken = randomBytes(32).toString("base64url");
33024
- const deviceSessionTokenHash = createHash7("sha256").update(deviceSessionToken, "utf8").digest("hex");
33025
- const deviceRefreshTokenHash = createHash7("sha256").update(deviceRefreshToken, "utf8").digest("hex");
34044
+ const deviceSessionTokenHash = createHash8("sha256").update(deviceSessionToken, "utf8").digest("hex");
34045
+ const deviceRefreshTokenHash = createHash8("sha256").update(deviceRefreshToken, "utf8").digest("hex");
33026
34046
  const message = createDeviceProofMessage({
33027
34047
  bindingSessionId: binding.id,
33028
34048
  challenge: binding.challenge,
@@ -33164,10 +34184,12 @@ async function runWechatAction(context, action, json = false) {
33164
34184
  const code = error instanceof WechatCliError ? error.code : "DXC_WECHAT_FAILED";
33165
34185
  const guidance = error instanceof WechatCliError ? error.guidance : void 0;
33166
34186
  const retryable = error instanceof WechatCliError ? error.retryable : false;
34187
+ const fields = error instanceof WechatCliError ? error.fields : void 0;
33167
34188
  if (json) {
33168
34189
  writeJson(context, {
33169
34190
  error: {
33170
34191
  code,
34192
+ ...fields === void 0 ? {} : { fields },
33171
34193
  message: guidance ?? code,
33172
34194
  retryable
33173
34195
  }
@@ -33200,7 +34222,7 @@ async function loadKnowledgeModule() {
33200
34222
  Reflect.apply(emitWarning, process, [warning2, ...arguments_]);
33201
34223
  });
33202
34224
  try {
33203
- return await import("./chunks/knowledge-5Y22MFAV.js");
34225
+ return await import("./chunks/knowledge-MNDWLVLM.js");
33204
34226
  } finally {
33205
34227
  process.emitWarning = emitWarning;
33206
34228
  }
@@ -33214,7 +34236,7 @@ async function loadMonitorModule() {
33214
34236
  Reflect.apply(emitWarning, process, [warning2, ...arguments_]);
33215
34237
  });
33216
34238
  try {
33217
- return await import("./chunks/monitor-MZPF73LC.js");
34239
+ return await import("./chunks/monitor-ACOHQYOE.js");
33218
34240
  } finally {
33219
34241
  process.emitWarning = emitWarning;
33220
34242
  }
@@ -33331,6 +34353,47 @@ async function runProjectAction(context, command, json, action) {
33331
34353
  );
33332
34354
  }
33333
34355
  }
34356
+ async function runProjectLocalPreviewAction(context, options) {
34357
+ try {
34358
+ const projectCli = new ProjectCli({
34359
+ currentDirectory: context.currentDirectory,
34360
+ homeDirectory: context.homeDirectory
34361
+ });
34362
+ const inputs = await projectCli.localPreviewInputs(options.directory, options.output);
34363
+ await runWechatAction(
34364
+ context,
34365
+ async (wechatCli) => {
34366
+ await wechatCli.previewLocalDraft(
34367
+ {
34368
+ ...inputs,
34369
+ resultCommand: "project.preview"
34370
+ },
34371
+ context
34372
+ );
34373
+ },
34374
+ options.json === true
34375
+ );
34376
+ } catch (error) {
34377
+ const code = error instanceof ProjectCliError ? error.code : "DXC_PROJECT_IO_FAILED";
34378
+ const message = error instanceof ProjectCliError ? error.message : "Project preview could not complete";
34379
+ writeActionError(
34380
+ context,
34381
+ options.json === true,
34382
+ contentProjectErrorResultSchema.parse({
34383
+ command: "project.preview",
34384
+ error: {
34385
+ code,
34386
+ message,
34387
+ ...error instanceof ProjectCliError ? error.details : {}
34388
+ },
34389
+ ok: false
34390
+ }),
34391
+ code,
34392
+ message,
34393
+ error instanceof ProjectCliError ? error.details.recovery : void 0
34394
+ );
34395
+ }
34396
+ }
33334
34397
  async function runKnowledgeAction(context, command, json, action) {
33335
34398
  const { KnowledgeCli, KnowledgeCliError } = await loadKnowledgeModule();
33336
34399
  try {
@@ -33373,15 +34436,18 @@ async function runSourceAction(context, json, action) {
33373
34436
  } catch (error) {
33374
34437
  const code = error instanceof SourceCliError ? error.code : "DXC_SOURCE_FAILED";
33375
34438
  const message = error instanceof SourceCliError ? error.message : "\u6765\u6E90\u91C7\u96C6\u65E0\u6CD5\u5B8C\u6210\u3002";
34439
+ const recovery = error instanceof SourceCliError ? error.recovery : void 0;
33376
34440
  writeActionError(
33377
34441
  context,
33378
34442
  json,
33379
34443
  sourceFetchErrorResultSchema.parse({
33380
34444
  command: "source.fetch",
33381
- error: { code, message },
34445
+ error: { code, message, ...recovery === void 0 ? {} : { recovery } },
33382
34446
  ok: false
33383
34447
  }),
33384
- code
34448
+ code,
34449
+ message,
34450
+ recovery
33385
34451
  );
33386
34452
  }
33387
34453
  }
@@ -33692,7 +34758,7 @@ ${hint}
33692
34758
  async (projectCli) => projectCli.resolve(query, options.directory)
33693
34759
  )
33694
34760
  );
33695
- project.command("status").description("\u8BFB\u53D6\u5185\u5BB9\u9879\u76EE\u3001\u4EA7\u7269\u548C\u68C0\u67E5\u70B9\u72B6\u6001").option("--directory <path>", "\u9879\u76EE\u76EE\u5F55", ".").option("--json", "\u8F93\u51FA JSON").action(
34761
+ project.command("status").description("\u8BFB\u53D6\u5185\u5BB9\u9879\u76EE\u3001\u4EA7\u7269\u548C\u68C0\u67E5\u70B9\u72B6\u6001").option("--directory <path>", "\u9879\u76EE\u6839\u76EE\u5F55\uFF1B\u7701\u7565\u65F6\u4ECE\u5F53\u524D\u76EE\u5F55\u5411\u4E0A\u67E5\u627E").option("--json", "\u8F93\u51FA JSON").action(
33696
34762
  async (options) => runProjectAction(
33697
34763
  context,
33698
34764
  "project.status",
@@ -33703,14 +34769,28 @@ ${hint}
33703
34769
  project.command("checkpoint").description("\u5199\u5165\u7EDF\u4E00\u7684\u9636\u6BB5 contract").argument("<stage>", "\u6B65\u9AA4\u540D\u79F0").requiredOption("--status <status>", "running / awaiting-user / completed / failed / skipped").option("--skill <name>", "\u7279\u6B8A\u63A5\u7BA1\u6D41\u7A0B\u4F7F\u7528\u7684 dxc-* Skill\uFF1B\u5E38\u89C4\u9636\u6BB5\u7531 catalog \u81EA\u52A8\u786E\u5B9A").option(
33704
34770
  "--skill-version <version>",
33705
34771
  "\u7279\u6B8A\u63A5\u7BA1\u6D41\u7A0B\u4F7F\u7528\u7684 Skill \u7248\u672C\uFF1B\u5E38\u89C4\u9636\u6BB5\u7531 catalog \u81EA\u52A8\u786E\u5B9A"
33706
- ).option("--summary <text>", "\u672C\u6B21\u9636\u6BB5\u72B6\u6001\u7684\u7B80\u77ED\u8BF4\u660E").option("--directory <path>", "\u9879\u76EE\u76EE\u5F55", ".").option("--inputs <stages>", "\u672C\u6B21\u989D\u5916\u8BFB\u53D6\u7684\u53EF\u9009\u8F93\u5165\uFF1B\u5FC5\u9700\u8F93\u5165\u7531 catalog \u81EA\u52A8\u8865\u9F50").option("--execution-location <location>", "local-device / agent-hosted / unknown", "unknown").option(
34772
+ ).option("--summary <text>", "\u672C\u6B21\u9636\u6BB5\u72B6\u6001\u7684\u7B80\u77ED\u8BF4\u660E").option("--directory <path>", "\u9879\u76EE\u6839\u76EE\u5F55\uFF1B\u7701\u7565\u65F6\u4ECE\u5F53\u524D\u76EE\u5F55\u5411\u4E0A\u67E5\u627E").option("--inputs <stages>", "\u672C\u6B21\u989D\u5916\u8BFB\u53D6\u7684\u53EF\u9009\u8F93\u5165\uFF1B\u5FC5\u9700\u8F93\u5165\u7531 catalog \u81EA\u52A8\u8865\u9F50").option("--execution-location <location>", "local-device / agent-hosted / unknown", "unknown").option(
33707
34773
  "--data-transit <transit>",
33708
34774
  "local-only / agent-provider / dxc-cloud / unknown",
33709
34775
  "unknown"
33710
34776
  ).option("--error-code <code>", "\u5931\u8D25\u65F6\u7684\u7A33\u5B9A\u9519\u8BEF\u7801").option("--waiting-for <prompt>", "awaiting-user \u72B6\u6001\u7B49\u5F85\u7528\u6237\u56DE\u7B54\u7684\u95EE\u9898").option("--confirm", "\u8BB0\u5F55\u7528\u6237\u5DF2\u786E\u8BA4\u8BE5\u6B65\u9AA4\u4EA7\u7269").option(
33711
34777
  "--authorization-purpose <purpose>",
33712
34778
  "\u9636\u6BB5\u5185\u5916\u90E8\u52A8\u4F5C\u6388\u6743\uFF1B\u5F53\u524D\u4EC5 visual-plan \u652F\u6301 image-generation"
33713
- ).option("--confirmed-by <actor>", "\u786E\u8BA4\u4EBA\u6216\u7A33\u5B9A\u8EAB\u4EFD\u6807\u8BC6", "local-interactive-user").option("--confirmation-snapshot <sha256>", "\u786E\u8BA4\u6240\u7ED1\u5B9A\u7684\u5FEB\u7167 SHA-256").option("--json", "\u8F93\u51FA JSON").action(
34779
+ ).option("--confirmed-by <actor>", "\u786E\u8BA4\u4EBA\u6216\u7A33\u5B9A\u8EAB\u4EFD\u6807\u8BC6", "local-interactive-user").option(
34780
+ "--confirmation-snapshot <sha256>",
34781
+ "\u4EC5 delivery \u9636\u6BB5\u4F20\u4E91\u7AEF renderSnapshot SHA-256\uFF1B\u5176\u4ED6\u9636\u6BB5\u7531 CLI \u4ECE\u8BED\u4E49\u4EA7\u7269\u81EA\u52A8\u8BA1\u7B97"
34782
+ ).option("--json", "\u8F93\u51FA JSON").addHelpText(
34783
+ "after",
34784
+ `
34785
+ \u72B6\u6001\u8FC1\u79FB\u4E0E\u5FC5\u586B\u53C2\u6570\uFF1A
34786
+ running --summary
34787
+ awaiting-user --summary --waiting-for
34788
+ completed --summary\uFF1B\u9700\u786E\u8BA4\u7684\u9636\u6BB5\u5148\u5199 awaiting-user\uFF0C\u518D\u4F7F\u7528 --confirm
34789
+ failed --summary --error-code
34790
+ skipped --summary
34791
+
34792
+ \u7701\u7565 --directory \u65F6\uFF0CCLI \u4F1A\u4ECE\u5F53\u524D\u76EE\u5F55\u5411\u4E0A\u67E5\u627E\u6700\u8FD1\u7684 dxc.project.json\u3002`
34793
+ ).action(
33714
34794
  async (stage, options) => runProjectAction(
33715
34795
  context,
33716
34796
  "project.checkpoint",
@@ -33727,7 +34807,7 @@ ${hint}
33727
34807
  )
33728
34808
  },
33729
34809
  dataTransit: options.dataTransit,
33730
- directory: options.directory,
34810
+ ...options.directory === void 0 ? {} : { directory: options.directory },
33731
34811
  ...options.errorCode === void 0 ? {} : { errorCode: options.errorCode },
33732
34812
  executionLocation: options.executionLocation,
33733
34813
  ...options.inputs === void 0 ? {} : {
@@ -33742,6 +34822,13 @@ ${hint}
33742
34822
  })
33743
34823
  )
33744
34824
  );
34825
+ project.command("preview").description("\u4ECE\u5DF2\u5B8C\u6210\u7684\u9879\u76EE\u9636\u6BB5\u751F\u6210\u672C\u5730\u5E26\u56FE\u9884\u89C8").requiredOption("--local", "\u751F\u6210\u672C\u5730\u6D3E\u751F\u9884\u89C8\uFF0C\u4E0D\u66FF\u4EE3\u4E91\u7AEF\u6700\u7EC8\u5FAE\u4FE1\u9884\u89C8").option("--directory <path>", "\u9879\u76EE\u6839\u76EE\u5F55\uFF1B\u7701\u7565\u65F6\u4ECE\u5F53\u524D\u76EE\u5F55\u5411\u4E0A\u67E5\u627E").option(
34826
+ "--output <path>",
34827
+ "\u9879\u76EE\u5185 .dxc/previews \u4E0B\u7684\u8F93\u51FA\u8DEF\u5F84",
34828
+ ".dxc/previews/visual-preview.html"
34829
+ ).option("--json", "\u8F93\u51FA JSON\uFF1B\u540C\u65F6\u53D1\u51FA\u53F3\u4FA7\u9884\u89C8\u66FF\u6362\u4E8B\u4EF6").action(
34830
+ async (options) => runProjectLocalPreviewAction(context, options)
34831
+ );
33745
34832
  knowledge.command("status").description("\u68C0\u67E5\u672C\u5730\u77E5\u8BC6\u5E93\u3001\u8BED\u4E49\u7D22\u5F15\u548C\u6A21\u578B\u7F13\u5B58").option("--json", "\u8F93\u51FA JSON").action(
33746
34833
  async (options) => runKnowledgeAction(
33747
34834
  context,
@@ -33935,7 +35022,76 @@ ${hint}
33935
35022
  )
33936
35023
  );
33937
35024
  const draft = wechat.command("draft").description("\u9884\u89C8\u5E76\u521B\u5EFA\u5FAE\u4FE1\u516C\u4F17\u53F7\u8349\u7A3F");
33938
- draft.command("preview").description("\u91C7\u96C6\u5DF2\u751F\u6210\u6216\u9009\u62E9\u7684\u56FE\u7247\uFF0C\u5E76\u751F\u6210\u4E0D\u53EF\u53D8\u4E91\u7AEF\u9884\u89C8").requiredOption("--article <path>", "Markdown \u6587\u7AE0\u6587\u4EF6").option("--cover <path-or-auto>", "PNG/JPEG \u5185\u5BB9\u5C01\u9762\uFF1Bauto \u4ECE\u6587\u7AE0\u6216\u7D20\u6750\u76EE\u5F55\u89E3\u6790", "auto").option("--assets-directory <path>", "\u91C7\u96C6\u5E76\u5185\u8054\u8BE5\u76EE\u5F55\u4E2D\u5DF2\u51C6\u5907\u597D\u7684 PNG/JPEG").option("--visual-plan <path>", "\u6309\u89C6\u89C9\u8BA1\u5212\u7684\u7CBE\u786E\u7AE0\u8282\u951A\u70B9\u63D2\u5165\u5DF2\u58F0\u660E\u7684\u6B63\u6587\u56FE\u7247").requiredOption("--account <uuid>", "\u76EE\u6807\u516C\u4F17\u53F7\u8D26\u53F7 ID").option("--title <title>", "\u4F7F\u7528\u5DF2\u786E\u8BA4\u6807\u9898\u8986\u76D6\u6587\u7AE0 frontmatter \u6807\u9898").option(
35025
+ draft.command("optimize-images").description("\u4E3A\u5FAE\u4FE1\u9650\u5236\u751F\u6210\u4E0D\u8986\u76D6\u539F\u56FE\u7684\u4F18\u5316\u6D3E\u751F\u56FE\uFF0C\u5E76\u540C\u6B65\u89C6\u89C9\u8BA1\u5212\u8DEF\u5F84\u4E0E\u54C8\u5E0C").requiredOption("--visual-plan <path>", "\u5DF2\u5F15\u7528\u5B9E\u9645\u56FE\u7247\u7684\u89C6\u89C9\u8BA1\u5212\u6587\u4EF6").option("--directory <path>", "\u5185\u5BB9\u9879\u76EE\u76EE\u5F55", ".").option("--json", "\u8F93\u51FA\u56FE\u7247\u53D8\u66F4\u3001\u900F\u660E\u901A\u9053\u548C\u54C8\u5E0C\u7ED3\u679C").action(
35026
+ async (options) => runWechatAction(
35027
+ context,
35028
+ async (wechatCli) => {
35029
+ await wechatCli.optimizeDraftImages(
35030
+ {
35031
+ projectDirectory: resolveUserPath({
35032
+ currentDirectory: context.currentDirectory,
35033
+ homeDirectory: context.homeDirectory,
35034
+ input: options.directory
35035
+ }),
35036
+ visualPlanFile: resolveUserPath({
35037
+ currentDirectory: context.currentDirectory,
35038
+ homeDirectory: context.homeDirectory,
35039
+ input: options.visualPlan
35040
+ })
35041
+ },
35042
+ context
35043
+ );
35044
+ },
35045
+ options.json === true
35046
+ )
35047
+ );
35048
+ draft.command("preview-local").description("\u5728\u672C\u5730\u751F\u6210\u5305\u542B\u5C01\u9762\u548C\u6B63\u6587\u914D\u56FE\u7684\u6D3E\u751F\u9884\u89C8\uFF0C\u5E76\u8BF7\u6C42\u66FF\u6362 Agent \u53F3\u4FA7\u9884\u89C8").requiredOption("--article <path>", "Markdown \u6587\u7AE0\u6587\u4EF6").requiredOption("--assets-directory <path>", "visual-plan \u5DF2\u843D\u76D8\u7684 PNG/JPEG \u7D20\u6750\u76EE\u5F55").requiredOption("--visual-plan <path>", "\u5DF2\u5B8C\u6210\u7684\u89C6\u89C9\u8BA1\u5212\u6587\u4EF6").option("--cover <path-or-auto>", "PNG/JPEG \u5185\u5BB9\u5C01\u9762\uFF1Bauto \u4ECE\u89C6\u89C9\u7D20\u6750\u76EE\u5F55\u89E3\u6790", "auto").option("--title <title>", "\u4F7F\u7528\u5DF2\u786E\u8BA4\u6807\u9898\u8986\u76D6\u6587\u7AE0 frontmatter \u6807\u9898").option(
35049
+ "--output <path>",
35050
+ "\u6D3E\u751F\u9884\u89C8\u6587\u4EF6\uFF1B\u9ED8\u8BA4\u4FDD\u5B58\u5728\u9879\u76EE\u79C1\u6709\u76EE\u5F55",
35051
+ ".dxc/previews/visual-preview.html"
35052
+ ).option("--json", "\u8F93\u51FA JSON\uFF1B\u540C\u65F6\u53D1\u51FA\u53F3\u4FA7\u6D4F\u89C8\u5668\u66FF\u6362\u4E8B\u4EF6").action(
35053
+ async (options) => runWechatAction(
35054
+ context,
35055
+ async (wechatCli) => {
35056
+ await wechatCli.previewLocalDraft(
35057
+ {
35058
+ articleFile: resolveUserPath({
35059
+ currentDirectory: context.currentDirectory,
35060
+ homeDirectory: context.homeDirectory,
35061
+ input: options.article
35062
+ }),
35063
+ assetsDirectory: resolveUserPath({
35064
+ currentDirectory: context.currentDirectory,
35065
+ homeDirectory: context.homeDirectory,
35066
+ input: options.assetsDirectory
35067
+ }),
35068
+ ...options.cover === void 0 ? {} : {
35069
+ coverFile: options.cover === "auto" ? "auto" : resolveUserPath({
35070
+ currentDirectory: context.currentDirectory,
35071
+ homeDirectory: context.homeDirectory,
35072
+ input: options.cover
35073
+ })
35074
+ },
35075
+ outputFile: resolveUserPath({
35076
+ currentDirectory: context.currentDirectory,
35077
+ homeDirectory: context.homeDirectory,
35078
+ input: options.output
35079
+ }),
35080
+ projectDirectory: context.currentDirectory,
35081
+ ...options.title === void 0 ? {} : { title: options.title },
35082
+ visualPlanFile: resolveUserPath({
35083
+ currentDirectory: context.currentDirectory,
35084
+ homeDirectory: context.homeDirectory,
35085
+ input: options.visualPlan
35086
+ })
35087
+ },
35088
+ context
35089
+ );
35090
+ },
35091
+ options.json === true
35092
+ )
35093
+ );
35094
+ draft.command("preview").description("\u91C7\u96C6\u5DF2\u751F\u6210\u6216\u9009\u62E9\u7684\u56FE\u7247\uFF0C\u5E76\u751F\u6210\u4E0D\u53EF\u53D8\u4E91\u7AEF\u9884\u89C8").requiredOption("--article <path>", "Markdown \u6587\u7AE0\u6587\u4EF6").option("--cover <path-or-auto>", "PNG/JPEG \u5185\u5BB9\u5C01\u9762\uFF1Bauto \u4ECE\u6587\u7AE0\u6216\u7D20\u6750\u76EE\u5F55\u89E3\u6790", "auto").option("--assets-directory <path>", "\u91C7\u96C6\u5E76\u5185\u8054\u8BE5\u76EE\u5F55\u4E2D\u5DF2\u51C6\u5907\u597D\u7684 PNG/JPEG").option("--visual-plan <path>", "\u6309\u89C6\u89C9\u8BA1\u5212\u7684\u7CBE\u786E\u7AE0\u8282\u951A\u70B9\u63D2\u5165\u5DF2\u58F0\u660E\u7684\u6B63\u6587\u56FE\u7247").requiredOption("--account <uuid>", "\u76EE\u6807\u516C\u4F17\u53F7\u8D26\u53F7 ID").option("--digest <digest>", "\u4F7F\u7528\u5DF2\u786E\u8BA4\u6458\u8981\u8986\u76D6\u6587\u7AE0 frontmatter \u6458\u8981").option("--title <title>", "\u4F7F\u7528\u5DF2\u786E\u8BA4\u6807\u9898\u8986\u76D6\u6587\u7AE0 frontmatter \u6807\u9898").option(
33939
35095
  "--browser <agent|system>",
33940
35096
  "\u4F7F\u7528\u7CFB\u7EDF\u6D4F\u89C8\u5668\uFF1B\u5BBF\u4E3B\u5DF2\u8BC1\u660E\u652F\u6301\u53F3\u4FA7\u6D4F\u89C8\u5668\u65F6\u53EF\u663E\u5F0F\u4F7F\u7528 agent",
33941
35097
  "system"
@@ -33970,6 +35126,7 @@ ${hint}
33970
35126
  input: options.cover
33971
35127
  })
33972
35128
  },
35129
+ ...options.digest === void 0 ? {} : { digest: options.digest },
33973
35130
  ...options.title === void 0 ? {} : { title: options.title },
33974
35131
  ...options.visualPlan === void 0 ? {} : {
33975
35132
  visualPlanFile: resolveUserPath({
@@ -34026,7 +35183,30 @@ ${hint}
34026
35183
  options.json === true
34027
35184
  )
34028
35185
  );
34029
- draft.command("create").description("\u786E\u8BA4\u4E0D\u53EF\u53D8\u5FEB\u7167\u548C\u76EE\u6807\u516C\u4F17\u53F7\u540E\u521B\u5EFA\u8349\u7A3F\u610F\u56FE").option("--account <uuid>", "\u76EE\u6807\u516C\u4F17\u53F7\u8D26\u53F7 ID").option("--snapshot <uuid>", "\u4E0D\u53EF\u53D8\u5FEB\u7167 ID").option("--snapshot-hash <sha256>", "\u4E0D\u53EF\u53D8\u5FEB\u7167 SHA-256").option("--idempotency-key <key>", "\u672C\u6B21\u8349\u7A3F\u610F\u56FE\u7684\u5E42\u7B49\u952E").option("--delivery <path>", "\u5199\u56DE\u6700\u7EC8\u9009\u4E2D\u5FEB\u7167\u7684 delivery \u9636\u6BB5\u4EA7\u7269").option("--confirm", "\u786E\u8BA4\u9884\u89C8\u5FEB\u7167\u548C\u76EE\u6807\u516C\u4F17\u53F7").option("--json", "\u8F93\u51FA JSON\uFF1B\u5931\u8D25\u65F6\u4E5F\u5728 stdout \u8FD4\u56DE\u7ED3\u6784\u5316\u9519\u8BEF").action(
35186
+ draft.command("preview-status").description("\u8BFB\u53D6\u670D\u52A1\u7AEF\u6700\u7EC8\u6A21\u677F\u9009\u62E9\u56DE\u6267\uFF0C\u5E76\u786E\u8BA4\u8BE5\u4FEE\u8BA2\u662F\u5426\u5DF2\u6210\u529F\u6253\u5F00").requiredOption("--snapshot <uuid>", "\u6700\u521D\u6E32\u67D3\u5FEB\u7167 ID").requiredOption("--snapshot-hash <sha256>", "\u6700\u521D\u6E32\u67D3\u5FEB\u7167 SHA-256").option("--json", "\u8F93\u51FA\u6700\u7EC8\u6A21\u677F\u3001\u9009\u62E9\u4FEE\u8BA2\u548C\u5DF2\u67E5\u770B\u72B6\u6001").action(
35187
+ async (options) => runWechatAction(
35188
+ context,
35189
+ async (wechatCli) => {
35190
+ await wechatCli.draftPreviewStatus(
35191
+ {
35192
+ snapshotHash: validatedOption(
35193
+ options.snapshotHash,
35194
+ /^[a-f0-9]{64}$/u,
35195
+ "snapshot-hash"
35196
+ ),
35197
+ snapshotId: validatedOption(
35198
+ options.snapshot,
35199
+ /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu,
35200
+ "snapshot"
35201
+ )
35202
+ },
35203
+ context
35204
+ );
35205
+ },
35206
+ options.json === true
35207
+ )
35208
+ );
35209
+ draft.command("create").description("\u786E\u8BA4\u4E0D\u53EF\u53D8\u5FEB\u7167\u548C\u76EE\u6807\u516C\u4F17\u53F7\u540E\u521B\u5EFA\u8349\u7A3F\u610F\u56FE").option("--account <uuid>", "\u76EE\u6807\u516C\u4F17\u53F7\u8D26\u53F7 ID").option("--snapshot <uuid>", "\u4E0D\u53EF\u53D8\u5FEB\u7167 ID").option("--snapshot-hash <sha256>", "\u4E0D\u53EF\u53D8\u5FEB\u7167 SHA-256").option("--idempotency-key <key>", "\u672C\u6B21\u8349\u7A3F\u610F\u56FE\u7684\u5E42\u7B49\u952E").option("--delivery <path>", "\u8BFB\u53D6\u5E76\u590D\u7528 delivery \u4E2D\u7684\u5E42\u7B49\u952E\u4E0E\u6700\u7EC8\u6A21\u677F\u56DE\u6267\uFF0C\u5E76\u5199\u56DE\u610F\u56FE\u72B6\u6001").option("--confirm", "\u786E\u8BA4\u9884\u89C8\u5FEB\u7167\u548C\u76EE\u6807\u516C\u4F17\u53F7").option("--json", "\u8F93\u51FA JSON\uFF1B\u5931\u8D25\u65F6\u4E5F\u5728 stdout \u8FD4\u56DE\u7ED3\u6784\u5316\u9519\u8BEF").action(
34030
35210
  async (options) => runWechatAction(
34031
35211
  context,
34032
35212
  async (wechatCli) => {
@@ -34100,6 +35280,30 @@ ${hint}
34100
35280
  options.json === true
34101
35281
  )
34102
35282
  );
35283
+ draft.command("retry").description("\u4EC5\u4ECE\u670D\u52A1\u7AEF\u8BC1\u660E\u5728\u5916\u90E8\u526F\u4F5C\u7528\u524D FAILED \u7684\u610F\u56FE\u521B\u5EFA\u6709\u8C31\u7CFB\u7684\u65B0\u91CD\u8BD5\u610F\u56FE").requiredOption("--intent <uuid>", "\u660E\u786E\u5931\u8D25\u7684\u539F\u8349\u7A3F\u610F\u56FE ID").requiredOption("--delivery <path>", "\u8BB0\u5F55\u539F\u5931\u8D25\u610F\u56FE\u548C\u6700\u7EC8\u5FEB\u7167\u7684 delivery \u9636\u6BB5\u4EA7\u7269").option("--confirm", "\u786E\u8BA4\u53D1\u8D77\u4E00\u6B21\u65B0\u7684\u8349\u7A3F\u610F\u56FE").option("--json", "\u8F93\u51FA JSON\uFF1B\u5931\u8D25\u65F6\u4E5F\u8FD4\u56DE\u7A33\u5B9A\u9519\u8BEF\u7801").action(
35284
+ async (options) => runWechatAction(
35285
+ context,
35286
+ async (wechatCli) => {
35287
+ await wechatCli.retryDraft(
35288
+ {
35289
+ confirmed: options.confirm === true,
35290
+ deliveryFile: resolveUserPath({
35291
+ currentDirectory: context.currentDirectory,
35292
+ homeDirectory: context.homeDirectory,
35293
+ input: options.delivery
35294
+ }),
35295
+ previousIntentId: validatedOption(
35296
+ options.intent,
35297
+ /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu,
35298
+ "intent"
35299
+ )
35300
+ },
35301
+ context
35302
+ );
35303
+ },
35304
+ options.json === true
35305
+ )
35306
+ );
34103
35307
  draft.command("status").description("\u67E5\u8BE2\u8349\u7A3F\u610F\u56FE\u72B6\u6001\u548C\u5FAE\u4FE1\u56DE\u8BFB\u7ED3\u679C").argument("<intent-id>", "\u8349\u7A3F\u610F\u56FE ID").option("--json", "\u8F93\u51FA JSON\uFF1B\u5931\u8D25\u65F6\u4E5F\u5728 stdout \u8FD4\u56DE\u7ED3\u6784\u5316\u9519\u8BEF").action(
34104
35308
  async (intentId, options) => runWechatAction(
34105
35309
  context,