@deployxai/dxc 0.1.7 → 0.1.12

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-NAL5UOUZ.js";
9
+ } from "./chunks/chunk-PX25ABJR.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-N4CMLINP.js";
86
+ } from "./chunks/chunk-BWOC5S2C.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.7",
23300
+ version: "0.1.12",
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
  /**
@@ -27207,13 +27210,13 @@ var ContentMemoryCli = class {
27207
27210
  // apps/cli/src/project.ts
27208
27211
  import { createHash as createHash4, randomUUID as randomUUID3 } from "node:crypto";
27209
27212
  import { createReadStream } from "node:fs";
27210
- import { lstat as lstat2, mkdir, readFile as readFile3, rename as rename3, unlink as unlink2, writeFile as writeFile2 } from "node:fs/promises";
27213
+ import { lstat as lstat3, mkdir, readFile as readFile3, rename as rename3, unlink as unlink2, writeFile as writeFile2 } from "node:fs/promises";
27211
27214
  import path4 from "node:path";
27212
27215
 
27213
27216
  // apps/cli/src/stage-artifact.ts
27214
27217
  import { createHash as createHash3, randomUUID as randomUUID2 } from "node:crypto";
27215
27218
  import { constants as fileConstants } from "node:fs";
27216
- import { open, readFile as readFile2, rename as rename2, unlink, writeFile } from "node:fs/promises";
27219
+ import { lstat as lstat2, open, readFile as readFile2, rename as rename2, unlink, writeFile } from "node:fs/promises";
27217
27220
  import path3 from "node:path";
27218
27221
 
27219
27222
  // packages/renderer-wechat/src/article.ts
@@ -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);
@@ -29338,10 +29356,31 @@ var StageArtifactValidationError = class extends Error {
29338
29356
  issues;
29339
29357
  };
29340
29358
  function issuePaths2(issues) {
29341
- return issues.map((issue) => {
29342
- const location = issue.path.map(String).join(".");
29343
- return location.length === 0 ? issue.message : location;
29344
- });
29359
+ const flattened = issues.flatMap(
29360
+ (issue) => issue.code === "invalid_union" && issue.errors !== void 0 ? [...issue.errors].sort((left, right) => left.length - right.length)[0] ?? [] : [issue]
29361
+ );
29362
+ return [
29363
+ ...new Set(
29364
+ flattened.map((issue) => {
29365
+ const location = issue.path.map(String).join(".");
29366
+ if (location === "coverSource" || /^inlineAssets\.\d+\.source$/u.test(location)) {
29367
+ return `${location}: \u4EC5\u5141\u8BB8 agent-generated\uFF08\u672C\u6B21\u7531 Agent \u751F\u6210\uFF09\u6216 local-material\uFF08\u7528\u6237\u63D0\u4F9B\u7684\u672C\u5730\u7D20\u6750\uFF09\uFF1BSVG \u6216\u56FE\u8868\u7ECF\u5BFC\u51FA\u4E3A PNG/JPEG \u540E\uFF0C\u6309\u771F\u5B9E\u6765\u6E90\u9009\u62E9\u5176\u4E2D\u4E00\u4E2A\u503C`;
29368
+ }
29369
+ if (issue.code === "unrecognized_keys" && issue.keys?.includes("planned")) {
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";
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
+ }
29377
+ if (location === "generation") {
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";
29379
+ }
29380
+ return location.length === 0 ? issue.message : `${location}: ${issue.message}`;
29381
+ })
29382
+ )
29383
+ ];
29345
29384
  }
29346
29385
  function insideProject(directory, relativePath) {
29347
29386
  const target = path3.resolve(directory, relativePath);
@@ -29351,11 +29390,16 @@ function insideProject(directory, relativePath) {
29351
29390
  }
29352
29391
  return target;
29353
29392
  }
29354
- async function readRegularFile(target, maximumBytes) {
29393
+ async function readRegularFile(target, maximumBytes, imageRole) {
29355
29394
  let handle;
29356
29395
  try {
29357
29396
  handle = await open(target, fileConstants.O_RDONLY | fileConstants.O_NOFOLLOW);
29358
29397
  const metadata = await handle.stat();
29398
+ if (metadata.isFile() && metadata.size > maximumBytes && imageRole !== void 0) {
29399
+ throw new StageArtifactValidationError([
29400
+ imageRole === "inline-image" ? `${path3.basename(target)} \u662F\u6B63\u6587\u56FE\u7247\uFF0C\u5B9E\u9645 ${metadata.size} bytes\uFF0C\u5FC5\u987B\u5C0F\u4E8E 1048576 bytes\uFF1B\u8BF7\u5BFC\u51FA JPEG \u6216\u964D\u4F4E\u5C3A\u5BF8/\u8D28\u91CF\u540E\u66F4\u65B0\u89C6\u89C9\u8BA1\u5212` : `${path3.basename(target)} \u662F\u5C01\u9762\uFF0C\u5B9E\u9645 ${metadata.size} bytes\uFF0C\u4E0A\u9650 ${maximumBytes} bytes\uFF1B\u8BF7\u964D\u4F4E\u5C3A\u5BF8\u6216\u8D28\u91CF\u540E\u66F4\u65B0\u89C6\u89C9\u8BA1\u5212`
29401
+ ]);
29402
+ }
29359
29403
  if (!metadata.isFile() || metadata.size <= 0 || metadata.size > maximumBytes) {
29360
29404
  throw new StageArtifactValidationError([path3.basename(target)]);
29361
29405
  }
@@ -29385,8 +29429,12 @@ function isSupportedImage(bytes, filePath) {
29385
29429
  function isInsideDirectory(filePath, directory) {
29386
29430
  return filePath.startsWith(`${directory}/`);
29387
29431
  }
29388
- async function validateImageAsset(directory, logicalPath, expectedSha256, maximumBytes) {
29389
- const bytes = await readRegularFile(insideProject(directory, logicalPath), maximumBytes);
29432
+ async function validateImageAsset(directory, logicalPath, expectedSha256, maximumBytes, imageRole) {
29433
+ const bytes = await readRegularFile(
29434
+ insideProject(directory, logicalPath),
29435
+ maximumBytes,
29436
+ imageRole
29437
+ );
29390
29438
  if (!isSupportedImage(bytes, logicalPath)) {
29391
29439
  throw new StageArtifactValidationError([`${logicalPath} \u4E0D\u662F\u771F\u5B9E PNG/JPEG \u6587\u4EF6`]);
29392
29440
  }
@@ -29468,6 +29516,30 @@ async function writeAtomically(target, bytes) {
29468
29516
  throw error;
29469
29517
  }
29470
29518
  }
29519
+ async function captureFile(target, logicalPath) {
29520
+ try {
29521
+ const metadata = await lstat2(target);
29522
+ if (!metadata.isFile() || metadata.isSymbolicLink()) {
29523
+ throw new StageArtifactValidationError([path3.basename(target)]);
29524
+ }
29525
+ return { bytes: await readFile2(target), logicalPath, target };
29526
+ } catch (error) {
29527
+ if (error.code === "ENOENT") {
29528
+ return { logicalPath, target };
29529
+ }
29530
+ throw error;
29531
+ }
29532
+ }
29533
+ async function assertFileUnchanged(candidate) {
29534
+ const current = await captureFile(candidate.target, candidate.logicalPath);
29535
+ const beforeHash = candidate.bytes === void 0 ? null : sha256(candidate.bytes);
29536
+ const currentHash = current.bytes === void 0 ? null : sha256(current.bytes);
29537
+ if (beforeHash !== currentHash) {
29538
+ throw new StageArtifactValidationError([
29539
+ `NORMALIZATION_CONFLICT: ${candidate.logicalPath} \u5728\u6821\u9A8C\u671F\u95F4\u88AB\u5176\u4ED6\u8FDB\u7A0B\u4FEE\u6539\uFF1BCLI \u672A\u8986\u76D6\u8BE5\u6587\u4EF6\uFF0C\u8BF7\u91CD\u65B0\u8BFB\u53D6\u540E\u91CD\u8BD5`
29540
+ ]);
29541
+ }
29542
+ }
29471
29543
  async function bindDeliveryApprovalArtifact(options) {
29472
29544
  const source = (await readRegularFile(options.target, MAXIMUM_ARTIFACT_BYTES)).toString("utf8");
29473
29545
  const frontmatter = parseFrontmatter2(source);
@@ -29478,6 +29550,11 @@ async function bindDeliveryApprovalArtifact(options) {
29478
29550
  if (value["rootSnapshotId"] !== options.approval.rootSnapshotId || value["rootSnapshotHash"] !== options.approval.rootSnapshotHash) {
29479
29551
  throw new StageArtifactValidationError(["rootSnapshotId/rootSnapshotHash \u4E0E\u6279\u51C6\u8BF7\u6C42\u4E0D\u4E00\u81F4"]);
29480
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
+ }
29481
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" };
29482
29559
  const nextValue = {
29483
29560
  ...value,
@@ -29496,23 +29573,88 @@ async function bindDeliveryApprovalArtifact(options) {
29496
29573
  ${(0, import_yaml2.stringify)(parsed.data, { lineWidth: 0 }).trimEnd()}
29497
29574
  ---
29498
29575
 
29576
+ ${frontmatter.body}
29577
+ `
29578
+ );
29579
+ }
29580
+ async function readDeliveryDraftIdentity(target) {
29581
+ const source = (await readRegularFile(target, MAXIMUM_ARTIFACT_BYTES)).toString("utf8");
29582
+ const parsed = deliveryStageArtifactFrontmatterSchema.safeParse(parseFrontmatter2(source).value);
29583
+ if (!parsed.success) {
29584
+ throw new StageArtifactValidationError(issuePaths2(parsed.error.issues));
29585
+ }
29586
+ return {
29587
+ accountId: parsed.data.accountId,
29588
+ idempotencyKey: parsed.data.idempotencyKey,
29589
+ previewSelectionRevision: parsed.data.previewSelectionRevision,
29590
+ rootSnapshotHash: parsed.data.rootSnapshotHash,
29591
+ rootSnapshotId: parsed.data.rootSnapshotId,
29592
+ selectedSnapshotHash: parsed.data.selectedSnapshotHash,
29593
+ selectedSnapshotId: parsed.data.selectedSnapshotId,
29594
+ templateId: parsed.data.templateId
29595
+ };
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
+
29499
29638
  ${frontmatter.body}
29500
29639
  `
29501
29640
  );
29502
29641
  }
29503
29642
  async function normalizeGoldenLines(directory, body, logicalPath) {
29504
29643
  const target = insideProject(directory, logicalPath);
29644
+ const snapshot = await captureFile(target, logicalPath);
29505
29645
  let parsed;
29506
29646
  try {
29507
- const bytes2 = await readFile2(target);
29508
- if (bytes2.length === 0 || bytes2.length > 64 * 1024) {
29509
- throw new StageArtifactValidationError([`${logicalPath} \u4E0D\u662F\u5408\u6CD5\u91D1\u53E5\u4EA4\u63A5\u6587\u4EF6`]);
29647
+ const bytes2 = snapshot.bytes;
29648
+ if (bytes2 === void 0) {
29649
+ parsed = { lines: [], schemaVersion: "dxc-golden-lines@1" };
29650
+ } else {
29651
+ if (bytes2.length === 0 || bytes2.length > 64 * 1024) {
29652
+ throw new StageArtifactValidationError([`${logicalPath} \u4E0D\u662F\u5408\u6CD5\u91D1\u53E5\u4EA4\u63A5\u6587\u4EF6`]);
29653
+ }
29654
+ parsed = JSON.parse(bytes2.toString("utf8"));
29510
29655
  }
29511
- parsed = JSON.parse(bytes2.toString("utf8"));
29512
29656
  } catch (error) {
29513
- if (error.code === "ENOENT") {
29514
- parsed = { lines: [], schemaVersion: "dxc-golden-lines@1" };
29515
- } else if (error instanceof StageArtifactValidationError) {
29657
+ if (error instanceof StageArtifactValidationError) {
29516
29658
  throw error;
29517
29659
  } else {
29518
29660
  throw new StageArtifactValidationError([`${logicalPath} \u4E0D\u662F\u5408\u6CD5\u91D1\u53E5\u4EA4\u63A5\u6587\u4EF6`]);
@@ -29531,16 +29673,17 @@ async function normalizeGoldenLines(directory, body, logicalPath) {
29531
29673
  };
29532
29674
  const bytes = Buffer.from(`${JSON.stringify(normalized, void 0, 2)}
29533
29675
  `, "utf8");
29534
- await writeAtomically(target, bytes);
29535
- return sha256(bytes);
29676
+ return { bytes, snapshot };
29536
29677
  }
29537
29678
  async function normalizeStageArtifact(options) {
29538
29679
  const artifactPath = options.manifest.artifacts[options.stage];
29539
29680
  const target = insideProject(options.directory, artifactPath);
29540
- const source = (await readRegularFile(
29541
- target,
29542
- options.stage === "article" ? MAXIMUM_ARTICLE_BYTES : MAXIMUM_ARTIFACT_BYTES
29543
- )).toString("utf8");
29681
+ const sourceSnapshot = await captureFile(target, artifactPath);
29682
+ const maximumBytes = options.stage === "article" ? MAXIMUM_ARTICLE_BYTES : MAXIMUM_ARTIFACT_BYTES;
29683
+ if (sourceSnapshot.bytes === void 0 || sourceSnapshot.bytes.length === 0 || sourceSnapshot.bytes.length > maximumBytes) {
29684
+ throw new StageArtifactValidationError([path3.basename(target)]);
29685
+ }
29686
+ const source = sourceSnapshot.bytes.toString("utf8");
29544
29687
  const frontmatter = parseFrontmatter2(source);
29545
29688
  const value = recordValue(frontmatter.value);
29546
29689
  if (value === void 0) {
@@ -29549,6 +29692,8 @@ async function normalizeStageArtifact(options) {
29549
29692
  const previousDxc = recordValue(value["dxc"]) ?? {};
29550
29693
  const nextValue = { ...value };
29551
29694
  const rootQuoteSnapshots = nextValue["quoteSnapshots"];
29695
+ const candidateFiles = [];
29696
+ const sidecars = /* @__PURE__ */ new Map();
29552
29697
  delete nextValue["quoteSnapshots"];
29553
29698
  nextValue["dxc"] = {
29554
29699
  artifactStatus: options.artifactStatus,
@@ -29603,11 +29748,14 @@ async function normalizeStageArtifact(options) {
29603
29748
  const defaultGoldenLinesPath = artifactPath.replace(/\.md$/iu, ".golden-lines.json");
29604
29749
  const goldenLinesPath = typeof nextValue["goldenLinesPath"] === "string" && nextValue["goldenLinesPath"].trim().length > 0 ? nextValue["goldenLinesPath"].trim() : defaultGoldenLinesPath;
29605
29750
  nextValue["goldenLinesPath"] = goldenLinesPath;
29606
- nextValue["goldenLinesSha256"] = await normalizeGoldenLines(
29751
+ const goldenLines = await normalizeGoldenLines(
29607
29752
  options.directory,
29608
29753
  frontmatter.body,
29609
29754
  goldenLinesPath
29610
29755
  );
29756
+ nextValue["goldenLinesSha256"] = sha256(goldenLines.bytes);
29757
+ sidecars.set(goldenLinesPath, goldenLines.bytes);
29758
+ candidateFiles.push({ ...goldenLines.snapshot, afterBytes: goldenLines.bytes });
29611
29759
  }
29612
29760
  if (options.stage === "titles") {
29613
29761
  const articleInput = options.inputs.find((input) => input.kind === "article");
@@ -29618,16 +29766,20 @@ async function normalizeStageArtifact(options) {
29618
29766
  if (options.stage === "visual-plan") {
29619
29767
  nextValue["assetsDirectory"] ??= options.manifest.assetsDirectory;
29620
29768
  nextValue["inlineImagesSupported"] ??= true;
29621
- nextValue["inlineAssets"] ??= [];
29622
- if (typeof nextValue["coverAsset"] === "string") {
29769
+ const isGenerationProposal = nextValue["planned"] === true;
29770
+ if (!isGenerationProposal) {
29771
+ nextValue["inlineAssets"] ??= [];
29772
+ }
29773
+ if (!isGenerationProposal && typeof nextValue["coverAsset"] === "string") {
29623
29774
  nextValue["coverSha256"] = sha256(
29624
29775
  await readRegularFile(
29625
29776
  insideProject(options.directory, nextValue["coverAsset"]),
29626
- MAXIMUM_COVER_BYTES
29777
+ MAXIMUM_COVER_BYTES,
29778
+ "cover"
29627
29779
  )
29628
29780
  );
29629
29781
  }
29630
- if (Array.isArray(nextValue["inlineAssets"])) {
29782
+ if (!isGenerationProposal && Array.isArray(nextValue["inlineAssets"])) {
29631
29783
  nextValue["inlineAssets"] = await Promise.all(
29632
29784
  nextValue["inlineAssets"].map(async (asset) => {
29633
29785
  const value2 = recordValue(asset);
@@ -29639,7 +29791,8 @@ async function normalizeStageArtifact(options) {
29639
29791
  sha256: sha256(
29640
29792
  await readRegularFile(
29641
29793
  insideProject(options.directory, value2["path"]),
29642
- MAXIMUM_INLINE_IMAGE_BYTES
29794
+ MAXIMUM_INLINE_IMAGE_BYTES,
29795
+ "inline-image"
29643
29796
  )
29644
29797
  )
29645
29798
  };
@@ -29673,6 +29826,7 @@ async function normalizeStageArtifact(options) {
29673
29826
  nextValue["selectedSnapshotId"] ??= legacySnapshotId;
29674
29827
  nextValue["selectedSnapshotHash"] ??= legacySnapshotHash;
29675
29828
  nextValue["templateId"] ??= "wechat-minimal@1";
29829
+ nextValue["previewSelectionRevision"] ??= 0;
29676
29830
  delete nextValue["snapshotId"];
29677
29831
  delete nextValue["snapshotHash"];
29678
29832
  if (typeof nextValue["rootSnapshotId"] === "string") {
@@ -29691,12 +29845,58 @@ ${(0, import_yaml2.stringify)(nextValue, { lineWidth: 0 }).trimEnd()}
29691
29845
 
29692
29846
  ${frontmatter.body}
29693
29847
  `;
29694
- if (normalizedSource !== source) {
29695
- await writeAtomically(target, normalizedSource);
29696
- }
29848
+ const normalizedBytes = Buffer.from(normalizedSource, "utf8");
29849
+ candidateFiles.push({ ...sourceSnapshot, afterBytes: normalizedBytes });
29850
+ const changedFiles = candidateFiles.filter(
29851
+ (candidate) => candidate.bytes === void 0 || !candidate.bytes.equals(candidate.afterBytes)
29852
+ );
29853
+ let committedFiles = [];
29854
+ const rollbackCommitted = async () => {
29855
+ for (const candidate of [...committedFiles].reverse()) {
29856
+ const current = await captureFile(candidate.target, candidate.logicalPath);
29857
+ if (current.bytes === void 0 || sha256(current.bytes) !== sha256(candidate.afterBytes)) {
29858
+ continue;
29859
+ }
29860
+ if (candidate.bytes === void 0) {
29861
+ await unlink(candidate.target);
29862
+ } else {
29863
+ await writeAtomically(candidate.target, candidate.bytes);
29864
+ }
29865
+ }
29866
+ committedFiles = [];
29867
+ };
29868
+ return {
29869
+ artifact: {
29870
+ bytes: normalizedBytes.length,
29871
+ path: artifactPath,
29872
+ sha256: sha256(normalizedBytes)
29873
+ },
29874
+ candidate: { sidecars, source: normalizedSource },
29875
+ commit: async () => {
29876
+ for (const candidate of candidateFiles) {
29877
+ await assertFileUnchanged(candidate);
29878
+ }
29879
+ try {
29880
+ for (const candidate of changedFiles) {
29881
+ await assertFileUnchanged(candidate);
29882
+ await writeAtomically(candidate.target, candidate.afterBytes);
29883
+ committedFiles.push(candidate);
29884
+ }
29885
+ } catch (error) {
29886
+ await rollbackCommitted();
29887
+ throw error;
29888
+ }
29889
+ },
29890
+ mutations: changedFiles.map((candidate) => ({
29891
+ afterSha256: sha256(candidate.afterBytes),
29892
+ beforeSha256: candidate.bytes === void 0 ? null : sha256(candidate.bytes),
29893
+ path: candidate.logicalPath
29894
+ })),
29895
+ rollbackCommitted
29896
+ };
29697
29897
  }
29698
- async function validateGoldenLinesSidecar(directory, articleBody, logicalPath, expectedSha256) {
29699
- const bytes = await readRegularFile(insideProject(directory, logicalPath), 64 * 1024);
29898
+ async function validateGoldenLinesSidecar(directory, articleBody, logicalPath, expectedSha256, candidateBytes) {
29899
+ const bytes = candidateBytes ?? await readRegularFile(insideProject(directory, logicalPath), 64 * 1024);
29700
29900
  if (sha256(bytes) !== expectedSha256) {
29701
29901
  throw new StageArtifactValidationError([`${logicalPath} \u54C8\u5E0C\u4E0D\u4E00\u81F4`]);
29702
29902
  }
@@ -29729,13 +29929,27 @@ function compareInputs(declared, actual) {
29729
29929
  }
29730
29930
  return issues;
29731
29931
  }
29932
+ function bindConfirmationInputs(contentHash, inputs) {
29933
+ return sha256(
29934
+ Buffer.from(
29935
+ JSON.stringify({
29936
+ contentHash,
29937
+ inputs: inputs.map((input) => ({
29938
+ kind: input.kind,
29939
+ path: input.path,
29940
+ sha256: input.sha256 ?? null
29941
+ }))
29942
+ }),
29943
+ "utf8"
29944
+ )
29945
+ );
29946
+ }
29732
29947
  async function validateStageArtifact(options) {
29733
29948
  const artifactPath = options.manifest.artifacts[options.stage];
29734
- const bytes = await readRegularFile(
29949
+ const source = options.candidate?.source ?? (await readRegularFile(
29735
29950
  insideProject(options.directory, artifactPath),
29736
29951
  options.stage === "article" ? MAXIMUM_ARTICLE_BYTES : MAXIMUM_ARTIFACT_BYTES
29737
- );
29738
- const source = bytes.toString("utf8");
29952
+ )).toString("utf8");
29739
29953
  const frontmatter = parseFrontmatter2(source);
29740
29954
  const parsed = contentStageArtifactFrontmatterSchema(options.stage).safeParse(frontmatter.value);
29741
29955
  if (!parsed.success) {
@@ -29775,7 +29989,8 @@ async function validateStageArtifact(options) {
29775
29989
  options.directory,
29776
29990
  frontmatter.body,
29777
29991
  article.goldenLinesPath,
29778
- article.goldenLinesSha256
29992
+ article.goldenLinesSha256,
29993
+ options.candidate?.sidecars.get(article.goldenLinesPath)
29779
29994
  );
29780
29995
  }
29781
29996
  }
@@ -29812,6 +30027,39 @@ async function validateStageArtifact(options) {
29812
30027
  }
29813
30028
  if (options.stage === "visual-plan") {
29814
30029
  const visual = visualPlanStageArtifactFrontmatterSchema.parse(frontmatter.value);
30030
+ if (!("coverAsset" in visual)) {
30031
+ if (options.checkpointStatus !== "awaiting-user") {
30032
+ throw new StageArtifactValidationError([
30033
+ "planned: \u751F\u6210\u8BA1\u5212\u53EA\u80FD\u7528\u4E8E\u7B49\u5F85\u56FE\u7247\u751F\u6210\u6388\u6743\uFF0C\u4E0D\u80FD\u4F5C\u4E3A\u5DF2\u5B8C\u6210\u89C6\u89C9\u4EA7\u7269"
30034
+ ]);
30035
+ }
30036
+ const semanticFrontmatter2 = { ...visual };
30037
+ delete semanticFrontmatter2["dxc"];
30038
+ const legacyConfirmationSnapshotHash2 = sha256(
30039
+ Buffer.from(
30040
+ JSON.stringify({ body: frontmatter.body, frontmatter: semanticFrontmatter2 }),
30041
+ "utf8"
30042
+ )
30043
+ );
30044
+ return {
30045
+ artifactPhase: "generation-proposal",
30046
+ authorizationPlan: {
30047
+ ...visual.generation,
30048
+ plannedAssets: visual.generation.plannedAssets.map((asset) => ({
30049
+ purpose: asset.purpose,
30050
+ role: asset.role,
30051
+ source: asset.source,
30052
+ ...asset.placementAnchor === void 0 ? {} : { placementAnchor: asset.placementAnchor }
30053
+ }))
30054
+ },
30055
+ confirmationSnapshotHash: bindConfirmationInputs(
30056
+ legacyConfirmationSnapshotHash2,
30057
+ options.inputs
30058
+ ),
30059
+ legacyConfirmationSnapshotHash: legacyConfirmationSnapshotHash2,
30060
+ snapshotType: "stage-artifact"
30061
+ };
30062
+ }
29815
30063
  if (visual.assetsDirectory !== options.manifest.assetsDirectory && !isInsideDirectory(visual.assetsDirectory, options.manifest.assetsDirectory)) {
29816
30064
  throw new StageArtifactValidationError(["assetsDirectory \u4E0D\u5728\u9879\u76EE\u7D20\u6750\u76EE\u5F55\u4E2D"]);
29817
30065
  }
@@ -29826,11 +30074,18 @@ async function validateStageArtifact(options) {
29826
30074
  options.directory,
29827
30075
  visual.coverAsset,
29828
30076
  visual.coverSha256,
29829
- MAXIMUM_COVER_BYTES
30077
+ MAXIMUM_COVER_BYTES,
30078
+ "cover"
29830
30079
  );
29831
30080
  await Promise.all(
29832
30081
  visual.inlineAssets.map(
29833
- (asset) => validateImageAsset(options.directory, asset.path, asset.sha256, MAXIMUM_INLINE_IMAGE_BYTES)
30082
+ (asset) => validateImageAsset(
30083
+ options.directory,
30084
+ asset.path,
30085
+ asset.sha256,
30086
+ MAXIMUM_INLINE_IMAGE_BYTES,
30087
+ "inline-image"
30088
+ )
29834
30089
  )
29835
30090
  );
29836
30091
  }
@@ -29842,29 +30097,40 @@ async function validateStageArtifact(options) {
29842
30097
  }
29843
30098
  if (options.stage === "titles") {
29844
30099
  const titles = titlesStageArtifactFrontmatterSchema.parse(frontmatter.value);
30100
+ const legacyConfirmationSnapshotHash2 = sha256(
30101
+ Buffer.from(
30102
+ JSON.stringify({
30103
+ articleSha256: titles.articleSha256,
30104
+ body: frontmatter.body,
30105
+ selectedTitle: titles.selectedTitle
30106
+ }),
30107
+ "utf8"
30108
+ )
30109
+ );
29845
30110
  return {
29846
- confirmationSnapshotHash: sha256(
29847
- Buffer.from(
29848
- JSON.stringify({
29849
- articleSha256: titles.articleSha256,
29850
- body: frontmatter.body,
29851
- selectedTitle: titles.selectedTitle
29852
- }),
29853
- "utf8"
29854
- )
30111
+ confirmationSnapshotHash: bindConfirmationInputs(
30112
+ legacyConfirmationSnapshotHash2,
30113
+ options.inputs
29855
30114
  ),
30115
+ legacyConfirmationSnapshotHash: legacyConfirmationSnapshotHash2,
29856
30116
  snapshotType: "stage-artifact"
29857
30117
  };
29858
30118
  }
29859
30119
  const semanticFrontmatter = { ...parsed.data };
29860
30120
  delete semanticFrontmatter["dxc"];
30121
+ const legacyConfirmationSnapshotHash = articleConfirmationSnapshotHash ?? sha256(
30122
+ Buffer.from(
30123
+ JSON.stringify({ body: frontmatter.body, frontmatter: semanticFrontmatter }),
30124
+ "utf8"
30125
+ )
30126
+ );
29861
30127
  return {
29862
- confirmationSnapshotHash: articleConfirmationSnapshotHash ?? sha256(
29863
- Buffer.from(
29864
- JSON.stringify({ body: frontmatter.body, frontmatter: semanticFrontmatter }),
29865
- "utf8"
29866
- )
30128
+ ...options.stage === "visual-plan" ? { artifactPhase: "materialized" } : {},
30129
+ confirmationSnapshotHash: bindConfirmationInputs(
30130
+ legacyConfirmationSnapshotHash,
30131
+ options.inputs
29867
30132
  ),
30133
+ legacyConfirmationSnapshotHash,
29868
30134
  snapshotType: "stage-artifact"
29869
30135
  };
29870
30136
  }
@@ -29879,6 +30145,17 @@ async function stageArtifactRequiresUserConfirmation(options) {
29879
30145
  const value = recordValue(parseFrontmatter2(source).value);
29880
30146
  return normalizedOrigin(value?.["origin"]) === "hotspot" && value?.["researchMode"] === "fact-only" && value?.["externalOpinionStatus"] === "user-skipped";
29881
30147
  }
30148
+ async function visualPlanArtifactPhase(options) {
30149
+ const source = (await readRegularFile(
30150
+ insideProject(options.directory, options.manifest.artifacts["visual-plan"]),
30151
+ MAXIMUM_ARTIFACT_BYTES
30152
+ )).toString("utf8");
30153
+ const parsed = visualPlanStageArtifactFrontmatterSchema.safeParse(parseFrontmatter2(source).value);
30154
+ if (!parsed.success) {
30155
+ throw new StageArtifactValidationError(issuePaths2(parsed.error.issues));
30156
+ }
30157
+ return "planned" in parsed.data && parsed.data.planned === true ? "generation-proposal" : "materialized";
30158
+ }
29882
30159
 
29883
30160
  // apps/cli/src/project.ts
29884
30161
  var MANIFEST_NAME = "dxc.project.json";
@@ -29908,12 +30185,14 @@ var DEFAULT_ARTIFACT_PATHS = {
29908
30185
  "visual-plan": "artifacts/06-visual-plan.md"
29909
30186
  };
29910
30187
  var ProjectCliError = class extends Error {
29911
- constructor(code, message) {
30188
+ constructor(code, message, details = {}) {
29912
30189
  super(message);
29913
30190
  this.code = code;
30191
+ this.details = details;
29914
30192
  this.name = "ProjectCliError";
29915
30193
  }
29916
30194
  code;
30195
+ details;
29917
30196
  };
29918
30197
  function migrateCheckpointInputKinds(required, optional, existing) {
29919
30198
  const allowedOptionalInputs = new Set(optional);
@@ -29938,7 +30217,7 @@ function errorCode(error) {
29938
30217
  }
29939
30218
  async function readJsonFile(target, maximumBytes, missingCode) {
29940
30219
  try {
29941
- const metadata = await lstat2(target);
30220
+ const metadata = await lstat3(target);
29942
30221
  if (!metadata.isFile() || metadata.isSymbolicLink() || metadata.size > maximumBytes) {
29943
30222
  throw new ProjectCliError("DXC_PROJECT_INVALID", "Project state file is invalid");
29944
30223
  }
@@ -30035,7 +30314,7 @@ async function inspectArtifact(directory, manifest, kind) {
30035
30314
  const relativePath = manifest.artifacts[kind];
30036
30315
  const target = insideProject2(directory, relativePath);
30037
30316
  try {
30038
- const metadata = await lstat2(target);
30317
+ const metadata = await lstat3(target);
30039
30318
  if (!metadata.isFile() || metadata.isSymbolicLink()) {
30040
30319
  throw new ProjectCliError("DXC_PROJECT_INVALID", "Project artifact is invalid");
30041
30320
  }
@@ -30119,16 +30398,26 @@ async function inspectCheckpoint(directory, manifest, stage, artifact, artifacts
30119
30398
  };
30120
30399
  }
30121
30400
  if (artifact.sha256 !== checkpoint.artifact.sha256 || artifact.bytes !== checkpoint.artifact.bytes) {
30122
- return {
30123
- checkpoint,
30124
- path: relativePath,
30125
- reason: "artifact-changed",
30126
- stage,
30127
- state: "stale"
30128
- };
30401
+ let authorizedMaterialization = false;
30402
+ if (checkpoint.checkpointVersion === "4" && checkpoint.stage === "visual-plan" && checkpoint.status === "running" && checkpoint.authorizations.length > 0) {
30403
+ try {
30404
+ authorizedMaterialization = await visualPlanArtifactPhase({ directory, manifest }) === "materialized";
30405
+ } catch {
30406
+ authorizedMaterialization = false;
30407
+ }
30408
+ }
30409
+ if (!authorizedMaterialization) {
30410
+ return {
30411
+ checkpoint,
30412
+ path: relativePath,
30413
+ reason: "artifact-changed",
30414
+ stage,
30415
+ state: "stale"
30416
+ };
30417
+ }
30129
30418
  }
30130
30419
  }
30131
- if (checkpoint.checkpointVersion === "2" || checkpoint.checkpointVersion === "3") {
30420
+ if (checkpoint.checkpointVersion === "2" || checkpoint.checkpointVersion === "3" || checkpoint.checkpointVersion === "4") {
30132
30421
  if (checkpoint.inputs.some((input) => input.path !== manifest.artifacts[input.kind]) || checkpoint.outputs.some((output) => output.path !== manifest.artifacts[output.kind])) {
30133
30422
  throw new ProjectCliError("DXC_PROJECT_INVALID", "Project checkpoint paths are invalid");
30134
30423
  }
@@ -30295,12 +30584,18 @@ var ProjectCli = class {
30295
30584
  });
30296
30585
  pendingCheckpoints.push({ checkpoint, stage });
30297
30586
  }
30298
- for (const { checkpoint, stage } of pendingCheckpoints) {
30299
- await writeJsonAtomically(
30300
- insideProject2(directory, checkpointRelativePath(manifest, stage)),
30301
- checkpoint
30302
- );
30587
+ const writtenTargets = [];
30588
+ try {
30589
+ for (const { checkpoint, stage } of pendingCheckpoints) {
30590
+ const target = insideProject2(directory, checkpointRelativePath(manifest, stage));
30591
+ await writeJsonAtomically(target, checkpoint);
30592
+ writtenTargets.push(target);
30593
+ }
30594
+ } catch (error) {
30595
+ await Promise.all(writtenTargets.map((target) => unlink2(target).catch(() => void 0)));
30596
+ throw error;
30303
30597
  }
30598
+ return writtenTargets;
30304
30599
  }
30305
30600
  async #rememberProject(directory, manifest, updatedAt) {
30306
30601
  const index = await loadProjectIndex(this.#projectIndexPath);
@@ -30329,7 +30624,7 @@ var ProjectCli = class {
30329
30624
  const directory = projectDirectory(this.#currentDirectory, this.#homeDirectory, directoryInput);
30330
30625
  const manifestTarget = path4.join(directory, MANIFEST_NAME);
30331
30626
  try {
30332
- await lstat2(manifestTarget);
30627
+ await lstat3(manifestTarget);
30333
30628
  throw new ProjectCliError("DXC_PROJECT_EXISTS", "A DxC project already exists");
30334
30629
  } catch (error) {
30335
30630
  if (error instanceof ProjectCliError) {
@@ -30409,9 +30704,18 @@ var ProjectCli = class {
30409
30704
  )
30410
30705
  );
30411
30706
  const summary = workflowSummary(checkpoints);
30707
+ const recoveryPlan = checkpoints.flatMap(
30708
+ (inspection) => inspection.state === "stale" ? [
30709
+ {
30710
+ action: "rerun-stage",
30711
+ reason: inspection.reason,
30712
+ stage: inspection.stage
30713
+ }
30714
+ ] : []
30715
+ );
30412
30716
  let assetsDirectoryReady = false;
30413
30717
  try {
30414
- const metadata = await lstat2(insideProject2(directory, manifest.assetsDirectory));
30718
+ const metadata = await lstat3(insideProject2(directory, manifest.assetsDirectory));
30415
30719
  assetsDirectoryReady = metadata.isDirectory() && !metadata.isSymbolicLink();
30416
30720
  } catch (error) {
30417
30721
  if (errorCode(error) !== "ENOENT") {
@@ -30428,6 +30732,7 @@ var ProjectCli = class {
30428
30732
  checkpointsDirectory: manifest.checkpointsDirectory,
30429
30733
  manifest,
30430
30734
  manifestPath: MANIFEST_NAME,
30735
+ recoveryPlan,
30431
30736
  ...summary
30432
30737
  },
30433
30738
  ok: true
@@ -30517,10 +30822,46 @@ var ProjectCli = class {
30517
30822
  const status = stepCheckpointStatusSchema.safeParse(options.status);
30518
30823
  const executionLocation = executionLocationSchema.safeParse(options.executionLocation);
30519
30824
  const dataTransit = dataTransitSchema.safeParse(options.dataTransit);
30520
- const summary = options.summary.trim();
30825
+ const summary = options.summary?.trim() ?? "";
30521
30826
  const requestedWaitingFor = options.waitingFor?.trim();
30522
30827
  if (!stage.success || !status.success || !executionLocation.success || !dataTransit.success || summary.length === 0) {
30523
- throw new ProjectCliError("DXC_PROJECT_STAGE_INVALID", "Checkpoint options are invalid");
30828
+ throw new ProjectCliError(
30829
+ "DXC_PROJECT_STAGE_INVALID",
30830
+ summary.length === 0 ? "\u9636\u6BB5\u68C0\u67E5\u70B9\u7F3A\u5C11\u6458\u8981\u3002" : "Checkpoint options are invalid",
30831
+ summary.length === 0 ? {
30832
+ fields: ["summary"],
30833
+ reason: "SUMMARY_REQUIRED",
30834
+ recovery: "\u8865\u5145 --summary <\u672C\u6B21\u9636\u6BB5\u72B6\u6001\u7684\u7B80\u77ED\u8BF4\u660E> \u540E\u91CD\u8BD5\uFF1BCLI \u4E0D\u4F1A\u5728\u7F3A\u5C11\u6458\u8981\u65F6\u4FEE\u6539\u4EFB\u4F55\u4EA7\u7269\u3002",
30835
+ ...stage.success ? { stage: stage.data } : {}
30836
+ } : { reason: "CHECKPOINT_OPTIONS_INVALID" }
30837
+ );
30838
+ }
30839
+ if (options.confirmationSnapshotHash !== void 0 && stage.data !== "delivery") {
30840
+ throw new ProjectCliError(
30841
+ "DXC_PROJECT_STAGE_INVALID",
30842
+ "--confirmation-snapshot \u4EC5\u7528\u4E8E delivery \u7684\u4E91\u7AEF\u6E32\u67D3\u5FEB\u7167\uFF1B\u5185\u5BB9\u9636\u6BB5\u7531 CLI \u81EA\u52A8\u8BA1\u7B97\u8BED\u4E49\u5FEB\u7167\u3002",
30843
+ {
30844
+ fields: ["confirmationSnapshot"],
30845
+ reason: "CONFIRMATION_SNAPSHOT_FLAG_NOT_ALLOWED",
30846
+ recovery: "\u79FB\u9664\u8BE5\u53C2\u6570\uFF1B\u82E5\u6B63\u6587\u6216\u6807\u9898\u5728\u5C55\u793A\u540E\u53D1\u751F\u53D8\u5316\uFF0C\u5148\u91CD\u65B0\u5199 awaiting-user \u68C0\u67E5\u70B9\u5E76\u518D\u6B21\u5C55\u793A\uFF0C\u518D\u4F7F\u7528 --confirm\u3002",
30847
+ stage: stage.data
30848
+ }
30849
+ );
30850
+ }
30851
+ const authorizationPurpose = options.authorizationPurpose?.trim();
30852
+ const requestingExternalAuthorization = authorizationPurpose === "image-generation" && stage.data === "visual-plan" && status.data === "awaiting-user" && options.confirmed !== true;
30853
+ const confirmingExternalAuthorization = authorizationPurpose === "image-generation" && stage.data === "visual-plan" && status.data === "running" && options.confirmed === true;
30854
+ if (authorizationPurpose !== void 0 && !requestingExternalAuthorization && !confirmingExternalAuthorization) {
30855
+ throw new ProjectCliError(
30856
+ "DXC_PROJECT_STAGE_INVALID",
30857
+ "\u56FE\u7247\u751F\u6210\u6388\u6743\u4EC5\u652F\u6301 visual-plan\uFF1A\u5148\u4EE5 awaiting-user \u8BF7\u6C42\uFF0C\u518D\u4EE5 running --confirm \u786E\u8BA4\u540E\u56DE\u5230\u540C\u4E00\u9636\u6BB5\u3002",
30858
+ {
30859
+ fields: ["authorizationPurpose"],
30860
+ reason: "EXTERNAL_AUTHORIZATION_OPTIONS_INVALID",
30861
+ recovery: "\u8BF7\u6C42\u6388\u6743\u65F6\u4F7F\u7528 --status awaiting-user --authorization-purpose image-generation\uFF1B\u7528\u6237\u786E\u8BA4\u540E\u4F7F\u7528 --status running --confirm \u548C\u76F8\u540C purpose\u3002",
30862
+ stage: stage.data
30863
+ }
30864
+ );
30524
30865
  }
30525
30866
  const expectedSkill = CONTENT_STAGE_SKILLS[stage.data];
30526
30867
  const effectiveSkill = options.skill ?? expectedSkill.name;
@@ -30556,12 +30897,12 @@ var ProjectCli = class {
30556
30897
  status: await inspectArtifact(directory, manifest, inputStage)
30557
30898
  }))
30558
30899
  )).filter((input) => input.status.status === "ready").map((input) => input.inputStage) : [];
30559
- const migratedExistingInputs = existing?.checkpointVersion === "2" || existing?.checkpointVersion === "3" ? migrateCheckpointInputKinds(
30900
+ const migratedExistingInputs = existing?.checkpointVersion === "2" || existing?.checkpointVersion === "3" || existing?.checkpointVersion === "4" ? migrateCheckpointInputKinds(
30560
30901
  stageInputs.required,
30561
30902
  stageInputs.optional,
30562
30903
  existing.inputs.map((input) => input.kind)
30563
30904
  ) : [];
30564
- const inputStageValues = options.inputStages !== void 0 ? [...stageInputs.required, ...options.inputStages] : existing?.checkpointVersion === "2" || existing?.checkpointVersion === "3" ? migratedExistingInputs : [...stageInputs.required, ...inferredOptionalInputs];
30905
+ const inputStageValues = options.inputStages !== void 0 ? [...stageInputs.required, ...options.inputStages] : existing?.checkpointVersion === "2" || existing?.checkpointVersion === "3" || existing?.checkpointVersion === "4" ? migratedExistingInputs : [...stageInputs.required, ...inferredOptionalInputs];
30565
30906
  const inputStages = inputStageValues.map(
30566
30907
  (inputStage) => contentArtifactKindSchema.safeParse(inputStage)
30567
30908
  );
@@ -30619,7 +30960,7 @@ var ProjectCli = class {
30619
30960
  );
30620
30961
  }
30621
30962
  const inputs = inputArtifactStatuses.map(artifactReference);
30622
- const requestedNeedsArtifact = status.data === "awaiting-user" || status.data === "completed";
30963
+ const requestedNeedsArtifact = status.data === "awaiting-user" || status.data === "completed" || confirmingExternalAuthorization;
30623
30964
  const artifactStatusBeforeNormalization = await inspectArtifact(
30624
30965
  directory,
30625
30966
  manifest,
@@ -30635,7 +30976,12 @@ var ProjectCli = class {
30635
30976
  });
30636
30977
  } catch (error) {
30637
30978
  if (error instanceof StageArtifactValidationError) {
30638
- throw new ProjectCliError("DXC_PROJECT_STAGE_INVALID", error.message);
30979
+ throw new ProjectCliError("DXC_PROJECT_STAGE_INVALID", error.message, {
30980
+ fields: error.issues.slice(0, 20).map((issue) => issue.slice(0, 200)),
30981
+ reason: "STAGE_ARTIFACT_INVALID",
30982
+ recovery: "\u6309 fields \u4E2D\u7684\u9996\u4E2A\u95EE\u9898\u4FEE\u6B63\u9636\u6BB5\u4EA7\u7269\u540E\u91CD\u8BD5\uFF1B\u5176\u4ED6\u95EE\u9898\u4F5C\u4E3A\u8865\u5145\u8BE6\u60C5\uFF0C\u4E0D\u4F1A\u906E\u4F4F\u4E3B\u539F\u56E0\u3002",
30983
+ stage: stage.data
30984
+ });
30639
30985
  }
30640
30986
  throw error;
30641
30987
  }
@@ -30656,11 +31002,12 @@ var ProjectCli = class {
30656
31002
  "Awaiting checkpoint needs one waiting-for prompt"
30657
31003
  );
30658
31004
  }
30659
- const needsArtifact = effectiveStatus === "awaiting-user" || effectiveStatus === "completed";
31005
+ const needsArtifact = effectiveStatus === "awaiting-user" || effectiveStatus === "completed" || confirmingExternalAuthorization;
31006
+ let artifactNormalization;
30660
31007
  if (needsArtifact) {
30661
31008
  try {
30662
- await normalizeStageArtifact({
30663
- artifactStatus: effectiveStatus === "completed" ? "complete" : "awaiting-user",
31009
+ artifactNormalization = await normalizeStageArtifact({
31010
+ artifactStatus: effectiveStatus === "completed" && !confirmingExternalAuthorization ? "complete" : "awaiting-user",
30664
31011
  createdAt: timestamp,
30665
31012
  directory,
30666
31013
  inputs,
@@ -30671,138 +31018,251 @@ var ProjectCli = class {
30671
31018
  });
30672
31019
  } catch (error) {
30673
31020
  if (error instanceof StageArtifactValidationError) {
30674
- throw new ProjectCliError("DXC_PROJECT_STAGE_INVALID", error.message);
31021
+ throw new ProjectCliError("DXC_PROJECT_STAGE_INVALID", error.message, {
31022
+ fields: error.issues.slice(0, 20).map((issue) => issue.slice(0, 200)),
31023
+ reason: "STAGE_ARTIFACT_INVALID",
31024
+ recovery: "\u6309 fields \u4E2D\u7684\u9996\u4E2A\u95EE\u9898\u4FEE\u6B63\u9636\u6BB5\u4EA7\u7269\u540E\u91CD\u8BD5\uFF1B\u6821\u9A8C\u5931\u8D25\u4E0D\u4F1A\u4FDD\u7559 CLI \u89C4\u8303\u5316\u6539\u5199\u3002",
31025
+ stage: stage.data
31026
+ });
30675
31027
  }
30676
31028
  throw error;
30677
31029
  }
30678
31030
  }
30679
- const artifactStatus = await inspectArtifact(directory, manifest, stage.data);
30680
- if (needsArtifact && artifactStatus.status !== "ready") {
30681
- throw new ProjectCliError(
30682
- "DXC_PROJECT_STAGE_INVALID",
30683
- "Checkpoint artifact must exist and be non-empty"
30684
- );
30685
- }
30686
- let artifactValidation;
30687
- if (needsArtifact) {
31031
+ {
31032
+ const artifactStatus = artifactNormalization === void 0 ? await inspectArtifact(directory, manifest, stage.data) : {
31033
+ ...artifactNormalization.artifact,
31034
+ kind: stage.data,
31035
+ status: "ready"
31036
+ };
31037
+ if (needsArtifact && artifactStatus.status !== "ready") {
31038
+ throw new ProjectCliError(
31039
+ "DXC_PROJECT_STAGE_INVALID",
31040
+ "Checkpoint artifact must exist and be non-empty"
31041
+ );
31042
+ }
31043
+ let artifactValidation;
31044
+ if (needsArtifact) {
31045
+ try {
31046
+ artifactValidation = await validateStageArtifact({
31047
+ ...artifactNormalization === void 0 ? {} : { candidate: artifactNormalization.candidate },
31048
+ checkpointStatus: confirmingExternalAuthorization ? "awaiting-user" : effectiveStatus,
31049
+ directory,
31050
+ inputs,
31051
+ manifest,
31052
+ skill: effectiveSkill,
31053
+ skillVersion: effectiveSkillVersion,
31054
+ stage: stage.data
31055
+ });
31056
+ } catch (error) {
31057
+ if (error instanceof StageArtifactValidationError) {
31058
+ throw new ProjectCliError("DXC_PROJECT_STAGE_INVALID", error.message, {
31059
+ fields: error.issues.slice(0, 20).map((issue) => issue.slice(0, 200)),
31060
+ reason: "STAGE_ARTIFACT_INVALID",
31061
+ recovery: "\u6309 fields \u4E2D\u7684\u9996\u4E2A\u95EE\u9898\u4FEE\u6B63\u9636\u6BB5\u4EA7\u7269\u540E\u91CD\u8BD5\uFF1B\u9700\u8981\u786E\u8BA4\u65F6\u5148\u91CD\u65B0\u5C55\u793A\u5F53\u524D\u8BED\u4E49\u5FEB\u7167\u3002",
31062
+ stage: stage.data
31063
+ });
31064
+ }
31065
+ throw error;
31066
+ }
31067
+ }
31068
+ if (artifactValidation?.artifactPhase === "generation-proposal" && !requestingExternalAuthorization && !confirmingExternalAuthorization) {
31069
+ throw new ProjectCliError(
31070
+ "DXC_PROJECT_STAGE_INVALID",
31071
+ "\u89C6\u89C9\u4EA7\u7269\u4ECD\u662F\u56FE\u7247\u751F\u6210\u8BA1\u5212\uFF0C\u5FC5\u987B\u5148\u5B8C\u6210\u751F\u6210\u524D\u6388\u6743\uFF0C\u4E0D\u80FD\u76F4\u63A5\u5B8C\u6210\u9636\u6BB5\u3002",
31072
+ {
31073
+ reason: "VISUAL_GENERATION_AUTHORIZATION_REQUIRED",
31074
+ recovery: "\u5148\u4EE5 awaiting-user --authorization-purpose image-generation \u4FDD\u5B58\u8BA1\u5212\uFF1B\u7528\u6237\u786E\u8BA4\u540E\u4EE5 running --confirm \u8FD4\u56DE\u540C\u4E00 visual-plan \u9636\u6BB5\u3002",
31075
+ stage: "visual-plan"
31076
+ }
31077
+ );
31078
+ }
31079
+ const output = artifactReference(artifactStatus);
31080
+ const confirmationSnapshotHash = options.confirmationSnapshotHash?.trim() ?? artifactValidation?.confirmationSnapshotHash;
31081
+ if (needsArtifact && (confirmationSnapshotHash === void 0 || !/^[a-f0-9]{64}$/u.test(confirmationSnapshotHash))) {
31082
+ throw new ProjectCliError(
31083
+ "DXC_PROJECT_STAGE_INVALID",
31084
+ "Confirmation snapshot hash is invalid"
31085
+ );
31086
+ }
31087
+ if (options.confirmationSnapshotHash !== void 0 && artifactValidation !== void 0 && options.confirmationSnapshotHash.trim() !== artifactValidation.confirmationSnapshotHash) {
31088
+ throw new ProjectCliError(
31089
+ "DXC_PROJECT_STAGE_INVALID",
31090
+ "\u786E\u8BA4\u5FEB\u7167\u4E0E\u5F53\u524D\u9636\u6BB5\u7ECF\u8FC7\u6821\u9A8C\u7684\u5185\u5BB9\u6216\u6E32\u67D3\u5FEB\u7167\u4E0D\u4E00\u81F4\u3002"
31091
+ );
31092
+ }
31093
+ const confirmationRelevant = effectiveStatus === "awaiting-user" || effectiveStatus === "completed" && requiresUserConfirmation && options.confirmed;
31094
+ const previousBinding = existing?.checkpointVersion === "3" || existing?.checkpointVersion === "4" ? existing.confirmationBinding : null;
31095
+ const confirmationSnapshotType = artifactValidation?.snapshotType ?? "stage-artifact";
31096
+ const previousInputsMatch = (existing?.checkpointVersion === "2" || existing?.checkpointVersion === "3" || existing?.checkpointVersion === "4") && existing.inputs.length === inputs.length && existing.inputs.every((input, index) => {
31097
+ const current = inputs[index];
31098
+ return current !== void 0 && input.kind === current.kind && input.path === current.path && input.sha256 === current.sha256 && input.bytes === current.bytes;
31099
+ });
31100
+ const legacyPendingSnapshotMatches = options.confirmed && previousInputsMatch && previousBinding?.snapshotType === "stage-artifact" && artifactStatusBeforeNormalization.status === "ready" && previousBinding.snapshotHash === artifactStatusBeforeNormalization.sha256;
31101
+ const legacySemanticSnapshotMatches = options.confirmed && previousInputsMatch && previousBinding?.snapshotType === "stage-artifact" && artifactValidation?.legacyConfirmationSnapshotHash !== void 0 && previousBinding.snapshotHash === artifactValidation.legacyConfirmationSnapshotHash;
31102
+ const previousSnapshotMatches = previousBinding?.snapshotHash === confirmationSnapshotHash || legacySemanticSnapshotMatches || legacyPendingSnapshotMatches;
31103
+ const completingConfirmedStage = effectiveStatus === "completed" && requiresUserConfirmation && options.confirmed;
31104
+ if ((completingConfirmedStage || confirmingExternalAuthorization) && (existing?.status !== "awaiting-user" || existing.confirmation !== "pending" || previousBinding?.status !== "pending" || !previousSnapshotMatches || previousBinding.snapshotType !== confirmationSnapshotType || confirmingExternalAuthorization && (existing.checkpointVersion !== "4" || existing.confirmationPurpose !== "external-action"))) {
31105
+ throw new ProjectCliError(
31106
+ "DXC_PROJECT_STAGE_INVALID",
31107
+ confirmingExternalAuthorization ? "\u5F53\u524D\u56FE\u7247\u751F\u6210\u8BA1\u5212\u4E0D\u662F\u521A\u624D\u7B49\u5F85\u6388\u6743\u7684\u7248\u672C\uFF1B\u8BF7\u91CD\u65B0\u5C55\u793A\u5F53\u524D\u8BA1\u5212\u5E76\u8BF7\u6C42\u6388\u6743\u3002" : "\u5F53\u524D\u5185\u5BB9\u6216\u6E32\u67D3\u5FEB\u7167\u4E0D\u662F\u521A\u624D\u7B49\u5F85\u786E\u8BA4\u7684\u7248\u672C\uFF1B\u8BF7\u5148\u91CD\u65B0\u5C55\u793A\u5E76\u5199\u5165 awaiting-user \u68C0\u67E5\u70B9\uFF0C\u518D\u6839\u636E\u7528\u6237\u660E\u786E\u56DE\u7B54\u786E\u8BA4\u3002",
31108
+ {
31109
+ reason: confirmingExternalAuthorization ? "EXTERNAL_AUTHORIZATION_STALE" : "CONFIRMATION_STALE",
31110
+ recovery: confirmingExternalAuthorization ? "\u7528\u5F53\u524D\u5F20\u6570\u3001\u7528\u9014\u3001\u6570\u636E\u53BB\u5411\u548C\u5C1D\u8BD5\u4E0A\u9650\u91CD\u5199\u751F\u6210\u8BA1\u5212\uFF0C\u5199 awaiting-user \u540E\u91CD\u65B0\u53D6\u5F97\u7528\u6237\u6388\u6743\u3002" : "\u91CD\u65B0\u751F\u6210\u6216\u89C4\u8303\u5316\u5F53\u524D\u4EA7\u7269\uFF0C\u5199 awaiting-user \u68C0\u67E5\u70B9\uFF0C\u5411\u7528\u6237\u5C55\u793A\u8BE5\u8BED\u4E49\u5FEB\u7167\u540E\u518D\u786E\u8BA4\u3002",
31111
+ stage: stage.data
31112
+ }
31113
+ );
31114
+ }
31115
+ const requestedAt = previousBinding !== null && previousSnapshotMatches && previousBinding.snapshotType === confirmationSnapshotType ? previousBinding.requestedAt : timestamp;
31116
+ const confirmedBy = options.confirmedBy?.trim() || "local-interactive-user";
31117
+ const authorizationPlan = artifactValidation?.authorizationPlan;
31118
+ if ((requestingExternalAuthorization || confirmingExternalAuthorization) && authorizationPlan === void 0) {
31119
+ throw new ProjectCliError(
31120
+ "DXC_PROJECT_STAGE_INVALID",
31121
+ "\u56FE\u7247\u751F\u6210\u6388\u6743\u5FC5\u987B\u7ED1\u5B9A planned=true \u7684\u5B8C\u6574\u751F\u6210\u8BA1\u5212\u3002",
31122
+ {
31123
+ reason: "VISUAL_GENERATION_PLAN_REQUIRED",
31124
+ recovery: "\u8865\u9F50 generation.executionLocation\u3001dataTransit\u3001chargesQuota\u3001maxAttempts\u3001retryPolicy \u548C plannedAssets \u540E\u91CD\u65B0\u8BF7\u6C42\u6388\u6743\u3002",
31125
+ stage: "visual-plan"
31126
+ }
31127
+ );
31128
+ }
31129
+ if (authorizationPlan !== void 0 && (authorizationPlan.dataTransit !== dataTransit.data || authorizationPlan.executionLocation !== executionLocation.data || confirmingExternalAuthorization && (existing?.execution.dataTransit !== dataTransit.data || existing.execution.location !== executionLocation.data))) {
31130
+ throw new ProjectCliError(
31131
+ "DXC_PROJECT_STAGE_INVALID",
31132
+ "\u56FE\u7247\u751F\u6210\u8BA1\u5212\u3001\u7B49\u5F85\u6388\u6743\u68C0\u67E5\u70B9\u548C\u672C\u6B21\u6267\u884C\u58F0\u660E\u7684\u6570\u636E\u53BB\u5411\u6216\u6267\u884C\u4F4D\u7F6E\u4E0D\u4E00\u81F4\u3002",
31133
+ {
31134
+ fields: ["generation.dataTransit", "generation.executionLocation", "execution"],
31135
+ reason: "EXTERNAL_AUTHORIZATION_EXECUTION_MISMATCH",
31136
+ recovery: "\u4FDD\u6301\u8BF7\u6C42\u6388\u6743\u4E0E\u786E\u8BA4\u547D\u4EE4\u7684 --data-transit\u3001--execution-location \u5B8C\u5168\u4E00\u81F4\uFF1B\u82E5\u6267\u884C\u73AF\u5883\u53D8\u5316\uFF0C\u91CD\u5199\u8BA1\u5212\u5E76\u91CD\u65B0\u53D6\u5F97\u6388\u6743\u3002",
31137
+ stage: "visual-plan"
31138
+ }
31139
+ );
31140
+ }
31141
+ const useCheckpointV4 = authorizationPurpose !== void 0 || existing?.checkpointVersion === "4";
31142
+ const existingAuthorizations = existing?.checkpointVersion === "4" ? existing.authorizations : [];
31143
+ const authorizations = confirmingExternalAuthorization ? [
31144
+ ...existingAuthorizations,
31145
+ {
31146
+ action: "image-generation",
31147
+ confirmedAt: timestamp,
31148
+ confirmedBy,
31149
+ plan: authorizationPlan,
31150
+ planSnapshotHash: confirmationSnapshotHash,
31151
+ requestedAt
31152
+ }
31153
+ ] : existingAuthorizations;
31154
+ const checkpointResult = stepCheckpointSchema.safeParse({
31155
+ ...(effectiveStatus === "awaiting-user" || effectiveStatus === "completed") && artifactStatus.status === "ready" ? {
31156
+ artifact: {
31157
+ bytes: artifactStatus.bytes,
31158
+ kind: stage.data,
31159
+ path: artifactStatus.path,
31160
+ sha256: artifactStatus.sha256
31161
+ }
31162
+ } : confirmingExternalAuthorization && artifactStatus.status === "ready" ? {
31163
+ artifact: {
31164
+ bytes: artifactStatus.bytes,
31165
+ kind: stage.data,
31166
+ path: artifactStatus.path,
31167
+ sha256: artifactStatus.sha256
31168
+ }
31169
+ } : {},
31170
+ ...useCheckpointV4 ? {
31171
+ authorizations,
31172
+ checkpointVersion: "4",
31173
+ confirmationPurpose: confirmationRelevant ? requestingExternalAuthorization ? "external-action" : "stage-completion" : null
31174
+ } : { checkpointVersion: "3" },
31175
+ ...TERMINAL_CHECKPOINT_STATUSES.has(effectiveStatus) ? { completedAt: timestamp } : {},
31176
+ confirmation: effectiveStatus === "awaiting-user" ? "pending" : effectiveStatus === "completed" && requiresUserConfirmation && options.confirmed ? "confirmed" : "not-required",
31177
+ confirmationBinding: confirmationRelevant && confirmationSnapshotHash !== void 0 ? {
31178
+ confirmedAt: effectiveStatus === "completed" ? timestamp : null,
31179
+ confirmedBy: effectiveStatus === "completed" ? confirmedBy : null,
31180
+ requestedAt,
31181
+ snapshotHash: confirmationSnapshotHash,
31182
+ snapshotType: confirmationSnapshotType,
31183
+ status: effectiveStatus === "completed" ? "confirmed" : "pending"
31184
+ } : null,
31185
+ ...effectiveStatus === "failed" ? { errorCode: options.errorCode } : {},
31186
+ execution: {
31187
+ dataTransit: dataTransit.data,
31188
+ location: executionLocation.data
31189
+ },
31190
+ inputs,
31191
+ metadata: {
31192
+ summary
31193
+ },
31194
+ outputs: [output],
31195
+ projectId: manifest.projectId,
31196
+ revision: (existing?.revision ?? 0) + 1,
31197
+ skill: {
31198
+ name: effectiveSkill,
31199
+ version: effectiveSkillVersion
31200
+ },
31201
+ stage: stage.data,
31202
+ startedAt: status.data === "running" && existing !== void 0 && TERMINAL_CHECKPOINT_STATUSES.has(existing.status) ? timestamp : existing?.startedAt ?? timestamp,
31203
+ status: effectiveStatus,
31204
+ updatedAt: timestamp,
31205
+ waitingFor: waitingFor ?? null,
31206
+ workflowId: manifest.workflowId
31207
+ });
31208
+ if (!checkpointResult.success) {
31209
+ throw new ProjectCliError("DXC_PROJECT_STAGE_INVALID", "Checkpoint options are invalid");
31210
+ }
31211
+ const checkpoint = checkpointResult.data;
31212
+ const relativePath = checkpointRelativePath(manifest, stage.data);
30688
31213
  try {
30689
- artifactValidation = await validateStageArtifact({
30690
- checkpointStatus: effectiveStatus,
30691
- directory,
30692
- inputs,
30693
- manifest,
30694
- skill: effectiveSkill,
30695
- skillVersion: effectiveSkillVersion,
30696
- stage: stage.data
30697
- });
31214
+ await artifactNormalization?.commit();
30698
31215
  } catch (error) {
30699
31216
  if (error instanceof StageArtifactValidationError) {
30700
- throw new ProjectCliError("DXC_PROJECT_STAGE_INVALID", error.message);
31217
+ throw new ProjectCliError("DXC_PROJECT_STAGE_INVALID", error.message, {
31218
+ fields: error.issues.slice(0, 20).map((issue) => issue.slice(0, 200)),
31219
+ reason: error.issues.some((issue) => issue.startsWith("NORMALIZATION_CONFLICT:")) ? "NORMALIZATION_CONFLICT" : "STAGE_ARTIFACT_INVALID",
31220
+ recovery: "\u91CD\u65B0\u8BFB\u53D6\u5F53\u524D\u9636\u6BB5\u4EA7\u7269\u53CA sidecar \u540E\u91CD\u8BD5\uFF1BCLI \u68C0\u6D4B\u5230\u5E76\u53D1\u6539\u52A8\u65F6\u4E0D\u4F1A\u8986\u76D6\u8F83\u65B0\u7684\u6587\u4EF6\u3002",
31221
+ stage: stage.data
31222
+ });
30701
31223
  }
30702
31224
  throw error;
30703
31225
  }
30704
- }
30705
- const output = artifactReference(artifactStatus);
30706
- const confirmationSnapshotHash = options.confirmationSnapshotHash?.trim() ?? artifactValidation?.confirmationSnapshotHash;
30707
- if (needsArtifact && (confirmationSnapshotHash === void 0 || !/^[a-f0-9]{64}$/u.test(confirmationSnapshotHash))) {
30708
- throw new ProjectCliError(
30709
- "DXC_PROJECT_STAGE_INVALID",
30710
- "Confirmation snapshot hash is invalid"
30711
- );
30712
- }
30713
- if (options.confirmationSnapshotHash !== void 0 && artifactValidation !== void 0 && options.confirmationSnapshotHash.trim() !== artifactValidation.confirmationSnapshotHash) {
30714
- throw new ProjectCliError(
30715
- "DXC_PROJECT_STAGE_INVALID",
30716
- "\u786E\u8BA4\u5FEB\u7167\u4E0E\u5F53\u524D\u9636\u6BB5\u7ECF\u8FC7\u6821\u9A8C\u7684\u5185\u5BB9\u6216\u6E32\u67D3\u5FEB\u7167\u4E0D\u4E00\u81F4\u3002"
30717
- );
30718
- }
30719
- const confirmationRelevant = effectiveStatus === "awaiting-user" || effectiveStatus === "completed" && requiresUserConfirmation && options.confirmed;
30720
- const previousBinding = existing?.checkpointVersion === "3" ? existing.confirmationBinding : null;
30721
- const confirmationSnapshotType = artifactValidation?.snapshotType ?? "stage-artifact";
30722
- const legacyPendingSnapshotMatches = options.confirmed && previousBinding?.snapshotType === "stage-artifact" && artifactStatusBeforeNormalization.status === "ready" && previousBinding.snapshotHash === artifactStatusBeforeNormalization.sha256;
30723
- const previousSnapshotMatches = previousBinding?.snapshotHash === confirmationSnapshotHash || legacyPendingSnapshotMatches;
30724
- if (effectiveStatus === "completed" && requiresUserConfirmation && options.confirmed && (existing?.status !== "awaiting-user" || existing.confirmation !== "pending" || previousBinding?.status !== "pending" || !previousSnapshotMatches || previousBinding.snapshotType !== confirmationSnapshotType)) {
30725
- throw new ProjectCliError(
30726
- "DXC_PROJECT_STAGE_INVALID",
30727
- "\u5F53\u524D\u5185\u5BB9\u6216\u6E32\u67D3\u5FEB\u7167\u4E0D\u662F\u521A\u624D\u7B49\u5F85\u786E\u8BA4\u7684\u7248\u672C\uFF1B\u8BF7\u5148\u91CD\u65B0\u5C55\u793A\u5E76\u5199\u5165 awaiting-user \u68C0\u67E5\u70B9\uFF0C\u518D\u6839\u636E\u7528\u6237\u660E\u786E\u56DE\u7B54\u786E\u8BA4\u3002"
30728
- );
30729
- }
30730
- const requestedAt = previousBinding !== null && previousSnapshotMatches && previousBinding.snapshotType === confirmationSnapshotType ? previousBinding.requestedAt : timestamp;
30731
- const confirmedBy = options.confirmedBy?.trim() || "local-interactive-user";
30732
- const checkpointResult = stepCheckpointSchema.safeParse({
30733
- ...needsArtifact && artifactStatus.status === "ready" ? {
30734
- artifact: {
30735
- bytes: artifactStatus.bytes,
30736
- kind: stage.data,
30737
- path: artifactStatus.path,
30738
- sha256: artifactStatus.sha256
30739
- }
30740
- } : {},
30741
- checkpointVersion: "3",
30742
- ...TERMINAL_CHECKPOINT_STATUSES.has(effectiveStatus) ? { completedAt: timestamp } : {},
30743
- confirmation: effectiveStatus === "awaiting-user" ? "pending" : effectiveStatus === "completed" && requiresUserConfirmation && options.confirmed ? "confirmed" : "not-required",
30744
- confirmationBinding: confirmationRelevant && confirmationSnapshotHash !== void 0 ? {
30745
- confirmedAt: effectiveStatus === "completed" ? timestamp : null,
30746
- confirmedBy: effectiveStatus === "completed" ? confirmedBy : null,
30747
- requestedAt,
30748
- snapshotHash: confirmationSnapshotHash,
30749
- snapshotType: confirmationSnapshotType,
30750
- status: effectiveStatus === "completed" ? "confirmed" : "pending"
30751
- } : null,
30752
- ...effectiveStatus === "failed" ? { errorCode: options.errorCode } : {},
30753
- execution: {
30754
- dataTransit: dataTransit.data,
30755
- location: executionLocation.data
30756
- },
30757
- inputs,
30758
- metadata: {
30759
- summary
30760
- },
30761
- outputs: [output],
30762
- projectId: manifest.projectId,
30763
- revision: (existing?.revision ?? 0) + 1,
30764
- skill: {
30765
- name: effectiveSkill,
30766
- version: effectiveSkillVersion
30767
- },
30768
- stage: stage.data,
30769
- startedAt: status.data === "running" && existing !== void 0 && TERMINAL_CHECKPOINT_STATUSES.has(existing.status) ? timestamp : existing?.startedAt ?? timestamp,
30770
- status: effectiveStatus,
30771
- updatedAt: timestamp,
30772
- waitingFor: waitingFor ?? null,
30773
- workflowId: manifest.workflowId
30774
- });
30775
- if (!checkpointResult.success) {
30776
- throw new ProjectCliError("DXC_PROJECT_STAGE_INVALID", "Checkpoint options are invalid");
30777
- }
30778
- const checkpoint = checkpointResult.data;
30779
- const relativePath = checkpointRelativePath(manifest, stage.data);
30780
- if (adoptsExistingArticle) {
30781
- await this.#skipArticleAdoptionPrerequisites(directory, manifest, timestamp, {
30782
- dataTransit: dataTransit.data,
30783
- location: executionLocation.data
31226
+ let adoptionTargets = [];
31227
+ try {
31228
+ if (adoptsExistingArticle) {
31229
+ adoptionTargets = await this.#skipArticleAdoptionPrerequisites(
31230
+ directory,
31231
+ manifest,
31232
+ timestamp,
31233
+ {
31234
+ dataTransit: dataTransit.data,
31235
+ location: executionLocation.data
31236
+ }
31237
+ );
31238
+ }
31239
+ await writeJsonAtomically(insideProject2(directory, relativePath), checkpoint);
31240
+ } catch (error) {
31241
+ await Promise.all(adoptionTargets.map((target) => unlink2(target).catch(() => void 0)));
31242
+ await artifactNormalization?.rollbackCommitted();
31243
+ throw error;
31244
+ }
31245
+ await this.#rememberProject(directory, manifest, timestamp).catch(() => void 0);
31246
+ return contentProjectCheckpointResultSchema.parse({
31247
+ command: "project.checkpoint",
31248
+ data: {
31249
+ artifactMutations: artifactNormalization?.mutations ?? [],
31250
+ checkpoint,
31251
+ checkpointPath: relativePath,
31252
+ guidance: effectiveStatus === "awaiting-user" ? {
31253
+ action: requestingExternalAuthorization ? "authorize-external-action" : "confirm-stage",
31254
+ message: waitingFor ?? "\u8BF7\u786E\u8BA4\u5F53\u524D\u9636\u6BB5\u5FEB\u7167\u3002",
31255
+ suggestedFlag: "--confirm"
31256
+ } : null
31257
+ },
31258
+ ok: true
30784
31259
  });
30785
31260
  }
30786
- await this.#rememberProject(directory, manifest, timestamp);
30787
- await writeJsonAtomically(insideProject2(directory, relativePath), checkpoint);
30788
- return contentProjectCheckpointResultSchema.parse({
30789
- command: "project.checkpoint",
30790
- data: {
30791
- checkpoint,
30792
- checkpointPath: relativePath,
30793
- guidance: confirmationRequired ? {
30794
- action: "confirm-stage",
30795
- message: waitingFor ?? "\u8BF7\u786E\u8BA4\u5F53\u524D\u9636\u6BB5\u5FEB\u7167\u3002",
30796
- suggestedFlag: "--confirm"
30797
- } : null
30798
- },
30799
- ok: true
30800
- });
30801
31261
  }
30802
31262
  };
30803
31263
 
30804
31264
  // apps/cli/src/skills.ts
30805
- import { cp, lstat as lstat3, mkdir as mkdir2, mkdtemp, readdir, rename as rename4, rm } from "node:fs/promises";
31265
+ import { cp, lstat as lstat4, mkdir as mkdir2, mkdtemp, readdir, rename as rename4, rm } from "node:fs/promises";
30806
31266
  import os from "node:os";
30807
31267
  import path5 from "node:path";
30808
31268
  import { fileURLToPath } from "node:url";
@@ -30831,7 +31291,7 @@ var SkillInstallerError = class extends Error {
30831
31291
  };
30832
31292
  async function isDirectory(directory) {
30833
31293
  try {
30834
- return (await lstat3(directory)).isDirectory();
31294
+ return (await lstat4(directory)).isDirectory();
30835
31295
  } catch {
30836
31296
  return false;
30837
31297
  }
@@ -30855,7 +31315,7 @@ async function findBundledSkills() {
30855
31315
  async function assertRegularSkillTree(directory) {
30856
31316
  for (const entry of await readdir(directory, { withFileTypes: true })) {
30857
31317
  const entryPath = path5.join(directory, entry.name);
30858
- const entryStat = await lstat3(entryPath);
31318
+ const entryStat = await lstat4(entryPath);
30859
31319
  if (entryStat.isSymbolicLink()) {
30860
31320
  throw new SkillInstallerError(
30861
31321
  "DXC_SKILL_SOURCE_UNSAFE",
@@ -30954,16 +31414,16 @@ var SkillInstaller = class {
30954
31414
  // apps/cli/src/wechat.ts
30955
31415
  import { spawn } from "node:child_process";
30956
31416
  import {
30957
- createHash as createHash7,
31417
+ createHash as createHash8,
30958
31418
  createPrivateKey as createPrivateKey2,
30959
31419
  createPublicKey as createPublicKey2,
30960
31420
  randomBytes,
30961
- randomUUID as randomUUID4
31421
+ randomUUID as randomUUID5
30962
31422
  } from "node:crypto";
30963
- import { constants as fileConstants3 } from "node:fs";
30964
- import { chmod, mkdir as mkdir3, open as open3, rename as rename5, rm as rm2, writeFile as writeFile3 } from "node:fs/promises";
31423
+ import { constants as fileConstants4 } from "node:fs";
31424
+ import { chmod, lstat as lstat7, mkdir as mkdir4, open as open4, rename as rename6, rm as rm2, writeFile as writeFile4 } from "node:fs/promises";
30965
31425
  import os2 from "node:os";
30966
- import path7 from "node:path";
31426
+ import path8 from "node:path";
30967
31427
 
30968
31428
  // packages/security/src/index.ts
30969
31429
  var import_pino = __toESM(require_pino(), 1);
@@ -31111,20 +31571,25 @@ var LOG_REDACTION_PATHS = Object.freeze([
31111
31571
  // apps/cli/src/publishing-assets.ts
31112
31572
  import { createHash as createHash6 } from "node:crypto";
31113
31573
  import { constants as fileConstants2 } from "node:fs";
31114
- import { lstat as lstat4, open as open2, readdir as readdir2, realpath } from "node:fs/promises";
31574
+ import { lstat as lstat5, open as open2, readdir as readdir2, realpath } from "node:fs/promises";
31115
31575
  import path6 from "node:path";
31116
31576
  var import_yaml3 = __toESM(require_dist(), 1);
31577
+ import sharp from "sharp";
31117
31578
 
31118
31579
  // apps/cli/src/wechat-error.ts
31119
31580
  var WechatCliError = class extends Error {
31120
- constructor(code, guidance) {
31581
+ constructor(code, guidance, retryable = false, fields) {
31121
31582
  super(guidance ?? code);
31122
31583
  this.code = code;
31123
31584
  this.guidance = guidance;
31585
+ this.retryable = retryable;
31586
+ this.fields = fields;
31124
31587
  this.name = "WechatCliError";
31125
31588
  }
31126
31589
  code;
31127
31590
  guidance;
31591
+ retryable;
31592
+ fields;
31128
31593
  };
31129
31594
 
31130
31595
  // apps/cli/src/publishing-assets.ts
@@ -31137,22 +31602,61 @@ var VISUAL_PLAN_MAXIMUM_BYTES = 128 * 1024;
31137
31602
  var ARTICLE_FRONTMATTER = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)([\s\S]*)$/u;
31138
31603
  var VISUAL_PLAN_FRONTMATTER = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/u;
31139
31604
  var LOCAL_WORKFLOW_FRONTMATTER_KEYS = ["dxc", "goldenLinesPath", "goldenLinesSha256"];
31140
- async function readPublishingInput(inputPath, maximumBytes) {
31605
+ async function validatePublishingImage(bytes, target) {
31606
+ let metadata;
31607
+ try {
31608
+ metadata = await sharp(bytes, { failOn: "error", limitInputPixels: 8e7 }).metadata();
31609
+ } catch {
31610
+ throw new WechatCliError(
31611
+ "DXC_PUBLISHING_INPUT_INVALID",
31612
+ `\u56FE\u7247 ${path6.basename(target)} \u65E0\u6CD5\u88AB\u5B89\u5168\u89E3\u7801\uFF1B\u4EC5\u652F\u6301\u6709\u6548 PNG/JPEG\u3002`
31613
+ );
31614
+ }
31615
+ const extension = path6.extname(target).toLowerCase();
31616
+ const expectedFormat = extension === ".png" ? "png" : extension === ".jpg" || extension === ".jpeg" ? "jpeg" : void 0;
31617
+ if (expectedFormat === void 0 || metadata.format !== expectedFormat || metadata.width === void 0 || metadata.height === void 0) {
31618
+ throw new WechatCliError(
31619
+ "DXC_PUBLISHING_INPUT_INVALID",
31620
+ `\u56FE\u7247 ${path6.basename(target)} \u7684\u6269\u5C55\u540D\u4E0E\u771F\u5B9E PNG/JPEG \u683C\u5F0F\u4E0D\u4E00\u81F4\u3002`
31621
+ );
31622
+ }
31623
+ }
31624
+ async function readPublishingInput(inputPath, maximumBytes, role = "article") {
31141
31625
  const target = path6.resolve(inputPath);
31142
31626
  let handle;
31143
31627
  try {
31144
31628
  handle = await open2(target, fileConstants2.O_RDONLY | fileConstants2.O_NOFOLLOW);
31145
31629
  const metadata = await handle.stat();
31146
- if (!metadata.isFile() || metadata.size <= 0 || metadata.size > maximumBytes) {
31630
+ if (metadata.isFile() && metadata.size > maximumBytes) {
31631
+ const fileName = path6.basename(target);
31632
+ if (role === "inline-image") {
31633
+ throw new WechatCliError(
31634
+ "DXC_PUBLISHING_INLINE_IMAGE_TOO_LARGE",
31635
+ `\u6B63\u6587\u56FE\u7247 ${fileName} \u4E3A ${metadata.size} bytes\uFF1B\u5FC5\u987B\u5C0F\u4E8E 1048576 bytes\u3002\u8BF7\u5BFC\u51FA\u4E3A JPEG\u3001\u964D\u4F4E\u5C3A\u5BF8\u6216\u8D28\u91CF\uFF0C\u66F4\u65B0 visual-plan \u540E\u91CD\u65B0 checkpoint \u548C\u9884\u89C8\u3002`
31636
+ );
31637
+ }
31638
+ if (role === "cover") {
31639
+ throw new WechatCliError(
31640
+ "DXC_PUBLISHING_COVER_TOO_LARGE",
31641
+ `\u5C01\u9762 ${fileName} \u4E3A ${metadata.size} bytes\uFF1B\u4E0A\u9650\u4E3A ${maximumBytes} bytes\u3002\u8BF7\u964D\u4F4E\u5C3A\u5BF8\u6216\u8D28\u91CF\u540E\u91CD\u65B0 checkpoint \u548C\u9884\u89C8\u3002`
31642
+ );
31643
+ }
31147
31644
  throw new WechatCliError(
31148
31645
  "DXC_PUBLISHING_INPUT_INVALID",
31149
- `\u6587\u4EF6 ${path6.basename(target)} \u4E0D\u662F\u53EF\u8BFB\u53D6\u7684\u666E\u901A\u6587\u4EF6\uFF0C\u6216\u5927\u5C0F\u8D85\u51FA\u9650\u5236\u3002`
31646
+ `\u6587\u4EF6 ${fileName} \u4E3A ${metadata.size} bytes\uFF0C\u8D85\u8FC7 ${maximumBytes} bytes \u7684\u9650\u5236\u3002`
31150
31647
  );
31151
31648
  }
31152
- return {
31153
- bytes: await handle.readFile(),
31154
- path: target
31155
- };
31649
+ if (!metadata.isFile() || metadata.size <= 0) {
31650
+ throw new WechatCliError(
31651
+ "DXC_PUBLISHING_INPUT_INVALID",
31652
+ `\u6587\u4EF6 ${path6.basename(target)} \u4E0D\u662F\u53EF\u8BFB\u53D6\u7684\u975E\u7A7A\u666E\u901A\u6587\u4EF6\u3002`
31653
+ );
31654
+ }
31655
+ const bytes = await handle.readFile();
31656
+ if (role === "cover" || role === "inline-image") {
31657
+ await validatePublishingImage(bytes, target);
31658
+ }
31659
+ return { bytes, path: target };
31156
31660
  } catch (error) {
31157
31661
  if (error instanceof WechatCliError) {
31158
31662
  throw error;
@@ -31165,7 +31669,7 @@ async function readPublishingInput(inputPath, maximumBytes) {
31165
31669
  await handle?.close();
31166
31670
  }
31167
31671
  }
31168
- async function readContainedPublishingInput(inputPath, maximumBytes, allowedDirectories) {
31672
+ async function readContainedPublishingInput(inputPath, maximumBytes, allowedDirectories, role) {
31169
31673
  try {
31170
31674
  const [target, ...directories] = await Promise.all([
31171
31675
  realpath(path6.resolve(inputPath)),
@@ -31189,7 +31693,7 @@ async function readContainedPublishingInput(inputPath, maximumBytes, allowedDire
31189
31693
  `\u65E0\u6CD5\u5B89\u5168\u89E3\u6790\u7D20\u6750 ${path6.basename(inputPath)}\u3002`
31190
31694
  );
31191
31695
  }
31192
- return readPublishingInput(inputPath, maximumBytes);
31696
+ return readPublishingInput(inputPath, maximumBytes, role);
31193
31697
  }
31194
31698
  function publishingImageMediaType(inputPath) {
31195
31699
  const extension = path6.extname(inputPath).toLowerCase();
@@ -31226,7 +31730,7 @@ async function collectedImages(directoryInput, articleDirectory) {
31226
31730
  const directory = path6.resolve(directoryInput);
31227
31731
  let entries;
31228
31732
  try {
31229
- const metadata = await lstat4(directory);
31733
+ const metadata = await lstat5(directory);
31230
31734
  if (!metadata.isDirectory() || metadata.isSymbolicLink()) {
31231
31735
  throw new WechatCliError(
31232
31736
  "DXC_PUBLISHING_ASSETS_DIRECTORY_INVALID",
@@ -31260,6 +31764,13 @@ async function collectedImages(directoryInput, articleDirectory) {
31260
31764
  ).map((entry) => path6.join(directory, entry.name)).sort((left, right) => left.localeCompare(right, "zh-CN"));
31261
31765
  }
31262
31766
  function injectCollectedImages(source, images) {
31767
+ const diagnosticText = (value, maximum = 120) => {
31768
+ const sanitized = [...value].map((character) => {
31769
+ const codePoint = character.codePointAt(0) ?? 0;
31770
+ return codePoint < 32 || codePoint >= 127 && codePoint <= 159 ? " " : character;
31771
+ }).join("").trim();
31772
+ return sanitized.length <= maximum ? sanitized : `${sanitized.slice(0, maximum)}\u2026`;
31773
+ };
31263
31774
  if (images.length === 0) {
31264
31775
  return source;
31265
31776
  }
@@ -31283,11 +31794,14 @@ function injectCollectedImages(source, images) {
31283
31794
  let headingLine = headingLines[index];
31284
31795
  if (image.placementAnchor !== void 0) {
31285
31796
  const match = /^after-heading:(.+)$/u.exec(image.placementAnchor);
31286
- const matches = match === null ? void 0 : headingLineByText.get(match[1]?.trim() ?? "");
31797
+ const requestedHeading = match?.[1]?.trim().replace(/^##\s+/u, "").replace(/\s+#+\s*$/u, "").trim();
31798
+ const matches = requestedHeading === void 0 ? void 0 : headingLineByText.get(requestedHeading);
31287
31799
  if (matches === void 0 || matches.length !== 1) {
31800
+ const matchCount = matches?.length ?? 0;
31801
+ const availableHeadings = [...headingLineByText.keys()].slice(0, 10).map((heading) => diagnosticText(heading)).join("\u3001").slice(0, 600);
31288
31802
  throw new WechatCliError(
31289
31803
  "DXC_PUBLISHING_VISUAL_ANCHOR_INVALID",
31290
- "\u89C6\u89C9\u8BA1\u5212\u7684\u63D2\u56FE\u951A\u70B9\u5FC5\u987B\u552F\u4E00\u5339\u914D\u6B63\u6587\u4E2D\u7684\u4E00\u4E2A\u4E8C\u7EA7\u6807\u9898\u3002"
31804
+ `\u89C6\u89C9\u8BA1\u5212\u951A\u70B9 ${diagnosticText(image.placementAnchor, 180)} \u7684\u7CBE\u786E\u5339\u914D\u6570\u4E3A ${matchCount}\uFF1B\u5FC5\u987B\u552F\u4E00\u5339\u914D\u6B63\u6587\u4E2D\u7684\u4E00\u4E2A\u4E8C\u7EA7\u6807\u9898\u3002\u53EF\u7528\u6807\u9898\uFF1A${availableHeadings.length === 0 ? "\uFF08\u65E0\uFF09" : availableHeadings}\u3002\u8BF7\u590D\u5236\u6807\u9898\u539F\u6587\uFF08\u542B\u6807\u70B9\uFF09\u66F4\u65B0 placementAnchor\u3002`
31291
31805
  );
31292
31806
  }
31293
31807
  headingLine = matches[0];
@@ -31307,12 +31821,10 @@ function injectCollectedImages(source, images) {
31307
31821
  }
31308
31822
  return output.join("\n");
31309
31823
  }
31310
- async function plannedInlineImages(visualPlanFile, availableByFileName) {
31824
+ async function plannedVisualAssets(visualPlanFile, assetsDirectoryInput) {
31311
31825
  let source;
31312
31826
  try {
31313
- source = (await readPublishingInput(visualPlanFile, VISUAL_PLAN_MAXIMUM_BYTES)).bytes.toString(
31314
- "utf8"
31315
- );
31827
+ source = (await readPublishingInput(visualPlanFile, VISUAL_PLAN_MAXIMUM_BYTES, "visual-plan")).bytes.toString("utf8");
31316
31828
  } catch {
31317
31829
  throw new WechatCliError("DXC_PUBLISHING_VISUAL_PLAN_INVALID");
31318
31830
  }
@@ -31330,37 +31842,89 @@ async function plannedInlineImages(visualPlanFile, availableByFileName) {
31330
31842
  if (!parsed.success) {
31331
31843
  throw new WechatCliError("DXC_PUBLISHING_VISUAL_PLAN_INVALID");
31332
31844
  }
31333
- return Promise.all(
31334
- parsed.data.inlineAssets.map(async (asset) => {
31335
- const absolutePath = availableByFileName.get(path6.posix.basename(asset.path));
31336
- if (absolutePath === void 0) {
31337
- throw new WechatCliError(
31338
- "DXC_PUBLISHING_VISUAL_PLAN_INVALID",
31339
- `\u89C6\u89C9\u8BA1\u5212\u58F0\u660E\u7684\u7D20\u6750 ${path6.posix.basename(asset.path)} \u4E0D\u5728\u6307\u5B9A\u7D20\u6750\u76EE\u5F55\u4E2D\u3002`
31340
- );
31341
- }
31342
- const input = await readPublishingInput(absolutePath, MAXIMUM_INLINE_IMAGE_BYTES2);
31343
- if (createHash6("sha256").update(input.bytes).digest("hex") !== asset.sha256) {
31344
- throw new WechatCliError(
31345
- "DXC_PUBLISHING_VISUAL_PLAN_INVALID",
31346
- `\u89C6\u89C9\u8BA1\u5212\u58F0\u660E\u7684\u7D20\u6750 ${path6.posix.basename(asset.path)} \u4E0E\u8BB0\u5F55\u7684\u54C8\u5E0C\u4E0D\u4E00\u81F4\u3002`
31347
- );
31348
- }
31349
- const digest = createHash6("sha256").update(absolutePath).digest("hex").slice(0, 12);
31350
- const fileName = safeFileName(path6.basename(absolutePath)) || `visual-${digest}.png`;
31351
- return {
31352
- absolutePath,
31353
- alt: asset.purpose,
31354
- logicalPath: `assets/dxc-visuals/${digest}-${fileName}`,
31355
- placementAnchor: asset.placementAnchor
31356
- };
31357
- })
31845
+ if (!("inlineAssets" in parsed.data)) {
31846
+ throw new WechatCliError(
31847
+ "DXC_PUBLISHING_VISUAL_PLAN_INVALID",
31848
+ "\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"
31849
+ );
31850
+ }
31851
+ if (assetsDirectoryInput === void 0) {
31852
+ throw new WechatCliError(
31853
+ "DXC_PUBLISHING_VISUAL_PLAN_INVALID",
31854
+ "\u4F7F\u7528\u89C6\u89C9\u8BA1\u5212\u65F6\u5FC5\u987B\u663E\u5F0F\u63D0\u4F9B\u5176\u58F0\u660E\u7684\u7D20\u6750\u76EE\u5F55\u3002"
31855
+ );
31856
+ }
31857
+ const assetsDirectory = path6.resolve(assetsDirectoryInput);
31858
+ const projectDirectory2 = commonDirectory(
31859
+ path6.dirname(path6.resolve(visualPlanFile)),
31860
+ assetsDirectory
31861
+ );
31862
+ const declaredAssetsDirectory = path6.resolve(projectDirectory2, parsed.data.assetsDirectory);
31863
+ if (!isWithinDirectory(assetsDirectory, declaredAssetsDirectory)) {
31864
+ throw new WechatCliError(
31865
+ "DXC_PUBLISHING_VISUAL_PLAN_INVALID",
31866
+ "\u663E\u5F0F\u7D20\u6750\u76EE\u5F55\u4E0D\u5728\u89C6\u89C9\u8BA1\u5212\u58F0\u660E\u7684\u9879\u76EE\u7D20\u6750\u76EE\u5F55\u4E2D\u3002"
31867
+ );
31868
+ }
31869
+ const resolvePlannedAsset = (assetPath) => {
31870
+ const target = path6.resolve(projectDirectory2, assetPath);
31871
+ if (!isWithinDirectory(target, declaredAssetsDirectory) || !isWithinDirectory(target, assetsDirectory)) {
31872
+ throw new WechatCliError("DXC_PUBLISHING_VISUAL_PLAN_INVALID");
31873
+ }
31874
+ return target;
31875
+ };
31876
+ const coverAbsolutePath = resolvePlannedAsset(parsed.data.coverAsset);
31877
+ const cover = await readContainedPublishingInput(
31878
+ coverAbsolutePath,
31879
+ MAXIMUM_IMAGE_BYTES,
31880
+ [assetsDirectory],
31881
+ "cover"
31358
31882
  );
31883
+ if (createHash6("sha256").update(cover.bytes).digest("hex") !== parsed.data.coverSha256) {
31884
+ throw new WechatCliError(
31885
+ "DXC_PUBLISHING_VISUAL_PLAN_INVALID",
31886
+ `\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`
31887
+ );
31888
+ }
31889
+ return {
31890
+ coverAbsolutePath,
31891
+ inline: await Promise.all(
31892
+ parsed.data.inlineAssets.map(async (asset) => {
31893
+ const absolutePath = resolvePlannedAsset(asset.path);
31894
+ if (!isWithinDirectory(absolutePath, assetsDirectory)) {
31895
+ throw new WechatCliError(
31896
+ "DXC_PUBLISHING_VISUAL_PLAN_INVALID",
31897
+ `\u89C6\u89C9\u8BA1\u5212\u58F0\u660E\u7684\u7D20\u6750 ${path6.posix.basename(asset.path)} \u4E0D\u5728\u6307\u5B9A\u7D20\u6750\u76EE\u5F55\u4E2D\u3002`
31898
+ );
31899
+ }
31900
+ const input = await readContainedPublishingInput(
31901
+ absolutePath,
31902
+ MAXIMUM_INLINE_IMAGE_BYTES2,
31903
+ [assetsDirectory],
31904
+ "inline-image"
31905
+ );
31906
+ if (createHash6("sha256").update(input.bytes).digest("hex") !== asset.sha256) {
31907
+ throw new WechatCliError(
31908
+ "DXC_PUBLISHING_VISUAL_PLAN_INVALID",
31909
+ `\u89C6\u89C9\u8BA1\u5212\u58F0\u660E\u7684\u7D20\u6750 ${path6.posix.basename(asset.path)} \u4E0E\u8BB0\u5F55\u7684\u54C8\u5E0C\u4E0D\u4E00\u81F4\u3002`
31910
+ );
31911
+ }
31912
+ const digest = createHash6("sha256").update(absolutePath).digest("hex").slice(0, 12);
31913
+ const fileName = safeFileName(path6.basename(absolutePath)) || `visual-${digest}.png`;
31914
+ return {
31915
+ absolutePath,
31916
+ alt: asset.purpose,
31917
+ logicalPath: `assets/dxc-visuals/${digest}-${fileName}`,
31918
+ placementAnchor: asset.placementAnchor
31919
+ };
31920
+ })
31921
+ )
31922
+ };
31359
31923
  }
31360
31924
  function logicalInlinePaths(bundle) {
31361
31925
  return bundle.assets.filter((asset) => asset.role === "inline").map((asset) => asset.logicalPath);
31362
31926
  }
31363
- function publishingArticleSource(source) {
31927
+ function publishingArticleSource(source, digestOverride) {
31364
31928
  const match = ARTICLE_FRONTMATTER.exec(source);
31365
31929
  const yamlSource = match?.[1];
31366
31930
  const body = match?.[2];
@@ -31374,6 +31938,10 @@ function publishingArticleSource(source) {
31374
31938
  for (const key of LOCAL_WORKFLOW_FRONTMATTER_KEYS) {
31375
31939
  document.delete(key);
31376
31940
  }
31941
+ if (digestOverride !== void 0) {
31942
+ document.set("digest", digestOverride.trim());
31943
+ document.delete("wechat_digest");
31944
+ }
31377
31945
  return `---
31378
31946
  ${document.toString().trimEnd()}
31379
31947
  ---
@@ -31408,14 +31976,15 @@ async function preparePublishingDraft(input) {
31408
31976
  (candidate) => /^cover(?:[._-]|$)/iu.test(path6.basename(candidate))
31409
31977
  );
31410
31978
  const explicitCover = input.coverFile !== void 0 && input.coverFile !== "auto" ? input.coverFile : void 0;
31411
- const coverCandidate = explicitCover ?? articleCoverCandidate ?? namedCoverCandidate;
31412
- const coverMode = explicitCover !== void 0 ? "explicit-file" : articleCoverCandidate !== void 0 ? "article-frontmatter" : namedCoverCandidate !== void 0 ? "assets-directory" : void 0;
31413
- const planned = input.visualPlanFile === void 0 ? [] : await plannedInlineImages(input.visualPlanFile, availableByFileName);
31979
+ const planned = input.visualPlanFile === void 0 ? void 0 : await plannedVisualAssets(input.visualPlanFile, input.assetsDirectory);
31980
+ const coverCandidate = explicitCover ?? planned?.coverAbsolutePath ?? articleCoverCandidate ?? namedCoverCandidate;
31981
+ 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;
31982
+ const plannedInline = planned?.inline ?? [];
31414
31983
  const pickupCandidates = availableImages.filter(
31415
31984
  (candidate) => candidate !== namedCoverCandidate && candidate !== articleCoverCandidate && !referencedFiles.has(path6.resolve(candidate)) && input.visualPlanFile === void 0
31416
31985
  );
31417
31986
  const injected = [
31418
- ...planned,
31987
+ ...plannedInline,
31419
31988
  ...pickupCandidates.slice(0, Math.max(0, MAXIMUM_INLINE_IMAGES - referenced.size)).map((candidate) => {
31420
31989
  const digest = createHash6("sha256").update(candidate).digest("hex").slice(0, 12);
31421
31990
  const fileName = safeFileName(path6.basename(candidate)) || `visual-${digest}.png`;
@@ -31431,7 +32000,7 @@ async function preparePublishingDraft(input) {
31431
32000
  let bundle;
31432
32001
  try {
31433
32002
  parseArticleDocument(materializedSource);
31434
- finalSource = publishingArticleSource(materializedSource);
32003
+ finalSource = publishingArticleSource(materializedSource, input.digest);
31435
32004
  bundle = parseArticleDocument(finalSource);
31436
32005
  } catch (error) {
31437
32006
  if (error instanceof WechatCliError) {
@@ -31442,7 +32011,20 @@ async function preparePublishingDraft(input) {
31442
32011
  bundle = input.title === void 0 ? bundle : { ...bundle, title: input.title.trim() };
31443
32012
  const localRender = renderWechatArticle(bundle);
31444
32013
  if (!localRender.preflight.ok) {
31445
- throw new WechatCliError("DXC_PUBLISHING_PREFLIGHT_FAILED");
32014
+ const digestTooLong = localRender.preflight.errors.some(
32015
+ (error) => error.code === "DIGEST_TOO_LONG"
32016
+ );
32017
+ 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")}`;
32018
+ throw new WechatCliError(
32019
+ "DXC_PUBLISHING_PREFLIGHT_FAILED",
32020
+ guidance,
32021
+ false,
32022
+ digestTooLong ? {
32023
+ currentLength: localRender.preflight.metrics.digestCharacters,
32024
+ max: LEGACY_DIGEST_CHARACTER_LIMIT,
32025
+ metadataField: "digest"
32026
+ } : void 0
32027
+ );
31446
32028
  }
31447
32029
  if (localRender.preflight.metrics.imageCount > MAXIMUM_INLINE_IMAGES) {
31448
32030
  throw new WechatCliError("DXC_PUBLISHING_TOO_MANY_INLINE_IMAGES");
@@ -31456,7 +32038,8 @@ async function preparePublishingDraft(input) {
31456
32038
  const asset = await readContainedPublishingInput(
31457
32039
  target,
31458
32040
  MAXIMUM_INLINE_IMAGE_BYTES2,
31459
- automaticAssetDirectories
32041
+ automaticAssetDirectories,
32042
+ "inline-image"
31460
32043
  );
31461
32044
  return {
31462
32045
  ...asset,
@@ -31474,8 +32057,9 @@ async function preparePublishingDraft(input) {
31474
32057
  const cover = explicitCover === void 0 ? await readContainedPublishingInput(
31475
32058
  coverCandidate,
31476
32059
  MAXIMUM_IMAGE_BYTES,
31477
- automaticAssetDirectories
31478
- ) : await readPublishingInput(coverCandidate, MAXIMUM_IMAGE_BYTES);
32060
+ automaticAssetDirectories,
32061
+ "cover"
32062
+ ) : await readPublishingInput(coverCandidate, MAXIMUM_IMAGE_BYTES, "cover");
31479
32063
  publishingImageMediaType(cover.path);
31480
32064
  return {
31481
32065
  article: {
@@ -31491,9 +32075,356 @@ async function preparePublishingDraft(input) {
31491
32075
  };
31492
32076
  }
31493
32077
 
32078
+ // apps/cli/src/publishing-image-optimization.ts
32079
+ var import_yaml4 = __toESM(require_dist(), 1);
32080
+ import { createHash as createHash7, randomUUID as randomUUID4 } from "node:crypto";
32081
+ import { constants as fileConstants3 } from "node:fs";
32082
+ import {
32083
+ lstat as lstat6,
32084
+ mkdir as mkdir3,
32085
+ open as open3,
32086
+ readFile as readFile4,
32087
+ realpath as realpath2,
32088
+ rename as rename5,
32089
+ unlink as unlink3,
32090
+ writeFile as writeFile3
32091
+ } from "node:fs/promises";
32092
+ import path7 from "node:path";
32093
+ import sharp2 from "sharp";
32094
+ var MAXIMUM_INPUT_BYTES = 32 * 1024 * 1024;
32095
+ var INLINE_IMAGE_LIMIT = 1024 * 1024 - 1;
32096
+ var INLINE_IMAGE_TARGET = 950 * 1024;
32097
+ var COVER_IMAGE_LIMIT = 5 * 1024 * 1024;
32098
+ var COVER_IMAGE_TARGET = 4500 * 1024;
32099
+ var VISUAL_PLAN_MAXIMUM_BYTES2 = 128 * 1024;
32100
+ var VISUAL_PLAN_FRONTMATTER2 = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)([\s\S]*)$/u;
32101
+ function sha2562(value) {
32102
+ return createHash7("sha256").update(value).digest("hex");
32103
+ }
32104
+ function safeDerivativeBase(value) {
32105
+ return value.normalize("NFKC").replaceAll(/[^A-Za-z0-9._-]+/gu, "-").replaceAll(/^-+|-+$/gu, "").slice(0, 80) || "image";
32106
+ }
32107
+ function recordValue2(value) {
32108
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
32109
+ }
32110
+ function portablePath(value, label) {
32111
+ if (typeof value !== "string" || value.trim().length === 0 || path7.isAbsolute(value) || value.includes("\\") || value.split("/").some((segment) => segment === "" || segment === "." || segment === "..")) {
32112
+ throw new WechatCliError(
32113
+ "DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
32114
+ `${label} \u5FC5\u987B\u662F\u9879\u76EE\u5185\u4F7F\u7528 / \u5206\u9694\u7684\u5B89\u5168\u76F8\u5BF9\u8DEF\u5F84\u3002`
32115
+ );
32116
+ }
32117
+ return value;
32118
+ }
32119
+ function isWithin(target, directory) {
32120
+ const relative = path7.relative(directory, target);
32121
+ return relative === "" || !relative.startsWith(`..${path7.sep}`) && relative !== "..";
32122
+ }
32123
+ async function regularImage(target) {
32124
+ let handle;
32125
+ try {
32126
+ handle = await open3(target, fileConstants3.O_RDONLY | fileConstants3.O_NOFOLLOW);
32127
+ const metadata = await handle.stat();
32128
+ if (!metadata.isFile() || metadata.size <= 0 || metadata.size > MAXIMUM_INPUT_BYTES) {
32129
+ throw new Error("invalid image");
32130
+ }
32131
+ return await handle.readFile();
32132
+ } catch {
32133
+ throw new WechatCliError(
32134
+ "DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
32135
+ `\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`
32136
+ );
32137
+ } finally {
32138
+ await handle?.close();
32139
+ }
32140
+ }
32141
+ async function requirePreservedAlpha(bytes) {
32142
+ const metadata = await sharp2(bytes, {
32143
+ failOn: "error",
32144
+ limitInputPixels: 8e7
32145
+ }).metadata();
32146
+ if (metadata.format !== "png" || metadata.hasAlpha !== true) {
32147
+ throw new WechatCliError(
32148
+ "DXC_PUBLISHING_IMAGE_ALPHA_LOST",
32149
+ "\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"
32150
+ );
32151
+ }
32152
+ }
32153
+ async function decodedImageMetadata(source, sourcePath) {
32154
+ let metadata;
32155
+ try {
32156
+ metadata = await sharp2(source, { failOn: "error", limitInputPixels: 8e7 }).metadata();
32157
+ } catch {
32158
+ throw new WechatCliError(
32159
+ "DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
32160
+ "\u56FE\u7247\u65E0\u6CD5\u88AB\u5B89\u5168\u89E3\u7801\uFF1B\u4EC5\u652F\u6301\u6709\u6548 PNG/JPEG\u3002"
32161
+ );
32162
+ }
32163
+ const extension = path7.extname(sourcePath).toLowerCase();
32164
+ const expectedFormat = extension === ".png" ? "png" : extension === ".jpg" || extension === ".jpeg" ? "jpeg" : void 0;
32165
+ if (expectedFormat === void 0 || metadata.format !== expectedFormat || metadata.width === void 0 || metadata.height === void 0) {
32166
+ throw new WechatCliError(
32167
+ "DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
32168
+ "\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"
32169
+ );
32170
+ }
32171
+ return {
32172
+ format: expectedFormat,
32173
+ hasAlpha: metadata.hasAlpha === true,
32174
+ height: metadata.height,
32175
+ width: metadata.width
32176
+ };
32177
+ }
32178
+ async function writeExclusiveOrVerify(target, bytes) {
32179
+ await mkdir3(path7.dirname(target), { recursive: true, mode: 448 });
32180
+ try {
32181
+ await writeFile3(target, bytes, { flag: "wx", mode: 384 });
32182
+ return true;
32183
+ } catch (error) {
32184
+ if (error.code !== "EEXIST") {
32185
+ throw error;
32186
+ }
32187
+ const existing = await regularImage(target);
32188
+ if (sha2562(existing) !== sha2562(bytes)) {
32189
+ throw new WechatCliError(
32190
+ "DXC_PUBLISHING_IMAGE_OPTIMIZATION_CONFLICT",
32191
+ `\u4F18\u5316\u76EE\u6807 ${path7.basename(target)} \u5DF2\u5B58\u5728\u4F46\u5185\u5BB9\u4E0D\u540C\uFF1B\u672A\u8986\u76D6\u4EFB\u4F55\u6587\u4EF6\u3002`
32192
+ );
32193
+ }
32194
+ return false;
32195
+ }
32196
+ }
32197
+ async function safeRealPathWithin(target, directory, label) {
32198
+ const resolved = await realpath2(target).catch(() => void 0);
32199
+ if (resolved === void 0 || !isWithin(resolved, directory)) {
32200
+ throw new WechatCliError(
32201
+ "DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
32202
+ `${label} \u7684\u771F\u5B9E\u8DEF\u5F84\u4E0D\u5728\u5141\u8BB8\u7684\u9879\u76EE\u76EE\u5F55\u5185\u3002`
32203
+ );
32204
+ }
32205
+ return resolved;
32206
+ }
32207
+ async function ensureSafeOptimizedDirectory(assetsDirectory, realAssetsDirectory) {
32208
+ const optimizedDirectory = path7.join(assetsDirectory, "optimized");
32209
+ await mkdir3(optimizedDirectory, { recursive: true, mode: 448 });
32210
+ const metadata = await lstat6(optimizedDirectory).catch(() => void 0);
32211
+ if (metadata === void 0 || !metadata.isDirectory() || metadata.isSymbolicLink()) {
32212
+ throw new WechatCliError(
32213
+ "DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
32214
+ "\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"
32215
+ );
32216
+ }
32217
+ await safeRealPathWithin(optimizedDirectory, realAssetsDirectory, "\u4F18\u5316\u76EE\u5F55");
32218
+ return optimizedDirectory;
32219
+ }
32220
+ async function writePlanAtomically(target, expectedSource, source) {
32221
+ const temporary = `${target}.${randomUUID4()}.tmp`;
32222
+ try {
32223
+ await writeFile3(temporary, source, { encoding: "utf8", flag: "wx", mode: 384 });
32224
+ if (await readFile4(target, "utf8") !== expectedSource) {
32225
+ throw new WechatCliError(
32226
+ "DXC_PUBLISHING_IMAGE_OPTIMIZATION_CONFLICT",
32227
+ "\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"
32228
+ );
32229
+ }
32230
+ await rename5(temporary, target);
32231
+ } finally {
32232
+ await unlink3(temporary).catch(() => void 0);
32233
+ }
32234
+ }
32235
+ function candidateWidths(width) {
32236
+ return [.../* @__PURE__ */ new Set([width, 2400, 2e3, 1600, 1280, 1080, 900, 720])].filter((candidate) => candidate > 0 && candidate <= width).sort((left, right) => right - left);
32237
+ }
32238
+ async function optimizedImage(source, targetBytes, metadata) {
32239
+ const hasAlpha = metadata.hasAlpha;
32240
+ for (const width of candidateWidths(metadata.width)) {
32241
+ if (hasAlpha) {
32242
+ const lossless = await sharp2(source, { failOn: "error", limitInputPixels: 8e7 }).rotate().resize({ fit: "inside", width, withoutEnlargement: true }).png({ compressionLevel: 9, effort: 10 }).toBuffer();
32243
+ if (lossless.byteLength <= targetBytes) {
32244
+ await requirePreservedAlpha(lossless);
32245
+ return { alphaPreserved: true, bytes: lossless, extension: ".png" };
32246
+ }
32247
+ for (const colours of [256, 192, 128, 96, 64]) {
32248
+ const quantized = await sharp2(source, {
32249
+ failOn: "error",
32250
+ limitInputPixels: 8e7
32251
+ }).rotate().resize({ fit: "inside", width, withoutEnlargement: true }).png({ colours, compressionLevel: 9, effort: 10, palette: true }).toBuffer();
32252
+ if (quantized.byteLength <= targetBytes) {
32253
+ await requirePreservedAlpha(quantized);
32254
+ return { alphaPreserved: true, bytes: quantized, extension: ".png" };
32255
+ }
32256
+ }
32257
+ continue;
32258
+ }
32259
+ for (const quality of [88, 82, 76, 70, 64, 58]) {
32260
+ 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();
32261
+ if (jpeg.byteLength <= targetBytes) {
32262
+ return { alphaPreserved: true, bytes: jpeg, extension: ".jpg" };
32263
+ }
32264
+ }
32265
+ }
32266
+ throw new WechatCliError(
32267
+ "DXC_PUBLISHING_IMAGE_OPTIMIZATION_LIMIT_UNREACHABLE",
32268
+ `\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`
32269
+ );
32270
+ }
32271
+ async function optimizePublishingImages(input) {
32272
+ const projectDirectory2 = path7.resolve(input.projectDirectory);
32273
+ const visualPlanPath = path7.resolve(input.visualPlanFile);
32274
+ if (!isWithin(visualPlanPath, projectDirectory2)) {
32275
+ throw new WechatCliError(
32276
+ "DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
32277
+ "\u89C6\u89C9\u8BA1\u5212\u5FC5\u987B\u4F4D\u4E8E\u5F53\u524D\u5185\u5BB9\u9879\u76EE\u5185\u3002"
32278
+ );
32279
+ }
32280
+ const projectMetadata = await lstat6(projectDirectory2).catch(() => void 0);
32281
+ const visualPlanMetadata = await lstat6(visualPlanPath).catch(() => void 0);
32282
+ if (projectMetadata === void 0 || !projectMetadata.isDirectory() || projectMetadata.isSymbolicLink() || visualPlanMetadata === void 0 || !visualPlanMetadata.isFile() || visualPlanMetadata.isSymbolicLink() || visualPlanMetadata.size > VISUAL_PLAN_MAXIMUM_BYTES2) {
32283
+ throw new WechatCliError(
32284
+ "DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
32285
+ "\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"
32286
+ );
32287
+ }
32288
+ const realProjectDirectory = await realpath2(projectDirectory2);
32289
+ await safeRealPathWithin(visualPlanPath, realProjectDirectory, "\u89C6\u89C9\u8BA1\u5212");
32290
+ const source = await readFile4(visualPlanPath, "utf8").catch(() => "");
32291
+ if (Buffer.byteLength(source, "utf8") > VISUAL_PLAN_MAXIMUM_BYTES2) {
32292
+ throw new WechatCliError("DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID");
32293
+ }
32294
+ const match = VISUAL_PLAN_FRONTMATTER2.exec(source);
32295
+ if (match?.[1] === void 0 || match[2] === void 0) {
32296
+ throw new WechatCliError("DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID");
32297
+ }
32298
+ let frontmatter;
32299
+ try {
32300
+ frontmatter = recordValue2((0, import_yaml4.parse)(match[1], { maxAliasCount: 10, uniqueKeys: true }));
32301
+ } catch {
32302
+ throw new WechatCliError("DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID");
32303
+ }
32304
+ if (frontmatter === void 0 || Object.hasOwn(frontmatter, "planned")) {
32305
+ throw new WechatCliError(
32306
+ "DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
32307
+ "\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"
32308
+ );
32309
+ }
32310
+ const assetsRelative = portablePath(frontmatter["assetsDirectory"], "assetsDirectory");
32311
+ const assetsDirectory = path7.resolve(projectDirectory2, assetsRelative);
32312
+ if (!isWithin(assetsDirectory, projectDirectory2)) {
32313
+ throw new WechatCliError("DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID");
32314
+ }
32315
+ const assetsMetadata = await lstat6(assetsDirectory).catch(() => void 0);
32316
+ if (assetsMetadata === void 0 || !assetsMetadata.isDirectory() || assetsMetadata.isSymbolicLink()) {
32317
+ throw new WechatCliError("DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID");
32318
+ }
32319
+ const realAssetsDirectory = await safeRealPathWithin(
32320
+ assetsDirectory,
32321
+ realProjectDirectory,
32322
+ "\u7D20\u6750\u76EE\u5F55"
32323
+ );
32324
+ const inlineAssets = Array.isArray(frontmatter["inlineAssets"]) ? frontmatter["inlineAssets"] : [];
32325
+ const entries = [
32326
+ {
32327
+ limit: COVER_IMAGE_LIMIT,
32328
+ record: { path: frontmatter["coverAsset"] },
32329
+ role: "cover",
32330
+ target: COVER_IMAGE_TARGET
32331
+ },
32332
+ ...inlineAssets.map((asset) => ({
32333
+ limit: INLINE_IMAGE_LIMIT,
32334
+ record: recordValue2(asset),
32335
+ role: "inline",
32336
+ target: INLINE_IMAGE_TARGET
32337
+ }))
32338
+ ];
32339
+ const createdFiles = [];
32340
+ const mutations = [];
32341
+ let unchangedCount = 0;
32342
+ let optimizedDirectory;
32343
+ try {
32344
+ for (const entry of entries) {
32345
+ const assetPath = portablePath(entry.record?.["path"], `${entry.role} \u56FE\u7247\u8DEF\u5F84`);
32346
+ const absolutePath = path7.resolve(projectDirectory2, assetPath);
32347
+ if (!isWithin(absolutePath, assetsDirectory)) {
32348
+ throw new WechatCliError(
32349
+ "DXC_PUBLISHING_IMAGE_OPTIMIZATION_INVALID",
32350
+ `${assetPath} \u4E0D\u5728\u89C6\u89C9\u8BA1\u5212\u58F0\u660E\u7684\u7D20\u6750\u76EE\u5F55\u5185\u3002`
32351
+ );
32352
+ }
32353
+ await safeRealPathWithin(absolutePath, realAssetsDirectory, `${assetPath} \u56FE\u7247`);
32354
+ const bytes = await regularImage(absolutePath);
32355
+ const metadata = await decodedImageMetadata(bytes, assetPath);
32356
+ const beforeSha256 = sha2562(bytes);
32357
+ let finalPath = assetPath;
32358
+ let finalBytes = bytes;
32359
+ let alphaPreserved = true;
32360
+ if (bytes.byteLength > entry.limit) {
32361
+ const optimized = await optimizedImage(bytes, entry.target, metadata);
32362
+ optimizedDirectory ??= await ensureSafeOptimizedDirectory(
32363
+ assetsDirectory,
32364
+ realAssetsDirectory
32365
+ );
32366
+ const baseName = safeDerivativeBase(path7.basename(assetPath, path7.extname(assetPath)));
32367
+ const optimizedSha256 = sha2562(optimized.bytes);
32368
+ const optimizedName = `${baseName}-${entry.role}-${beforeSha256.slice(0, 12)}-${optimizedSha256.slice(0, 12)}${optimized.extension}`;
32369
+ const optimizedAbsolute = path7.join(optimizedDirectory, optimizedName);
32370
+ const created = await writeExclusiveOrVerify(optimizedAbsolute, optimized.bytes);
32371
+ if (created) {
32372
+ createdFiles.push(optimizedAbsolute);
32373
+ }
32374
+ finalPath = path7.relative(projectDirectory2, optimizedAbsolute).split(path7.sep).join("/");
32375
+ finalBytes = optimized.bytes;
32376
+ alphaPreserved = optimized.alphaPreserved;
32377
+ mutations.push({
32378
+ alphaPreserved,
32379
+ afterBytes: finalBytes.byteLength,
32380
+ afterSha256: sha2562(finalBytes),
32381
+ beforeBytes: bytes.byteLength,
32382
+ beforeSha256,
32383
+ from: assetPath,
32384
+ role: entry.role,
32385
+ to: finalPath
32386
+ });
32387
+ } else {
32388
+ unchangedCount += 1;
32389
+ }
32390
+ if (entry.role === "cover") {
32391
+ frontmatter["coverAsset"] = finalPath;
32392
+ frontmatter["coverSha256"] = sha2562(finalBytes);
32393
+ } else if (entry.record !== void 0) {
32394
+ entry.record["path"] = finalPath;
32395
+ entry.record["sha256"] = sha2562(finalBytes);
32396
+ }
32397
+ }
32398
+ frontmatter["inlineAssets"] = inlineAssets;
32399
+ const normalizedSource = `---
32400
+ ${(0, import_yaml4.stringify)(frontmatter, { lineWidth: 0 }).trimEnd()}
32401
+ ---
32402
+ ${match[2]}`;
32403
+ await writePlanAtomically(visualPlanPath, source, normalizedSource);
32404
+ } catch (error) {
32405
+ await Promise.all(createdFiles.map((target) => unlink3(target).catch(() => void 0)));
32406
+ if (error instanceof WechatCliError) {
32407
+ throw error;
32408
+ }
32409
+ throw new WechatCliError(
32410
+ "DXC_PUBLISHING_IMAGE_OPTIMIZATION_FAILED",
32411
+ "\u56FE\u7247\u4F18\u5316\u672A\u5B8C\u6210\uFF1B\u539F\u56FE\u548C\u89C6\u89C9\u8BA1\u5212\u5747\u672A\u88AB\u8986\u76D6\u3002"
32412
+ );
32413
+ }
32414
+ return {
32415
+ command: "wechat.draft.optimize-images",
32416
+ data: { mutations, unchangedCount, visualPlanPath },
32417
+ ok: true
32418
+ };
32419
+ }
32420
+
31494
32421
  // apps/cli/src/wechat.ts
31495
32422
  var DEFAULT_API_BASE_URL = "https://content.deployxai.com";
31496
32423
  var DEFAULT_POLL_INTERVAL_MS = 2e3;
32424
+ var MAXIMUM_LOCAL_PREVIEW_BYTES = 40 * 1024 * 1024;
32425
+ var WECHAT_AUTHOR_CHARACTER_LIMIT = 16;
32426
+ var WECHAT_DIGEST_CHARACTER_LIMIT = 120;
32427
+ var WECHAT_TITLE_CHARACTER_LIMIT = 32;
31497
32428
  function userFacingDraftIntent(intent) {
31498
32429
  const { status, ...userFacing } = intent;
31499
32430
  void status;
@@ -31509,6 +32440,158 @@ function writeAgentBrowserEvent(output, event) {
31509
32440
  `
31510
32441
  );
31511
32442
  }
32443
+ function escapeLocalPreviewText(value) {
32444
+ return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
32445
+ }
32446
+ function localPreviewImageSource(asset) {
32447
+ return `data:${publishingImageMediaType(asset.path)};base64,${asset.bytes.toString("base64")}`;
32448
+ }
32449
+ function localVisualPreviewHtml(prepared) {
32450
+ const replacements = new Map(
32451
+ prepared.inlineAssets.map((asset) => [asset.logicalPath, localPreviewImageSource(asset)])
32452
+ );
32453
+ const renderedArticle = rewriteWechatAssetSources(prepared.localRender.html, replacements);
32454
+ for (const asset of prepared.inlineAssets) {
32455
+ const originalSource = `src="${escapeLocalPreviewText(asset.logicalPath)}"`;
32456
+ if (!prepared.localRender.html.includes(originalSource) || renderedArticle.includes(originalSource)) {
32457
+ throw new WechatCliError(
32458
+ "DXC_PUBLISHING_LOCAL_PREVIEW_ASSET_MISMATCH",
32459
+ `\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`
32460
+ );
32461
+ }
32462
+ }
32463
+ const title = escapeLocalPreviewText(prepared.bundle.title);
32464
+ const coverSource = localPreviewImageSource(prepared.cover);
32465
+ const html = `<!doctype html>
32466
+ <html lang="zh-CN">
32467
+ <head>
32468
+ <meta charset="utf-8">
32469
+ <meta name="viewport" content="width=device-width, initial-scale=1">
32470
+ <meta name="referrer" content="no-referrer">
32471
+ <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'">
32472
+ <title>${title} \xB7 \u672C\u5730\u5E26\u56FE\u9884\u89C8</title>
32473
+ <style>
32474
+ :root { color-scheme: light; background: #f5f5f4; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; }
32475
+ body { margin: 0; color: #292524; }
32476
+ .dxc-shell { box-sizing: border-box; margin: 0 auto; max-width: 780px; min-height: 100vh; padding: 24px 16px 64px; }
32477
+ .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; }
32478
+ .dxc-card { background: white; border: 1px solid #e7e5e4; border-radius: 16px; box-shadow: 0 12px 36px rgb(41 37 36 / 8%); overflow: hidden; }
32479
+ .dxc-cover { background: #e7e5e4; display: block; max-height: 360px; object-fit: cover; width: 100%; }
32480
+ .dxc-meta { border-bottom: 1px solid #f5f5f4; padding: 22px 24px 14px; }
32481
+ .dxc-meta h1 { font-size: 24px; line-height: 1.35; margin: 0 0 6px; }
32482
+ .dxc-meta p { color: #78716c; font-size: 13px; margin: 0; }
32483
+ .dxc-article { overflow-wrap: anywhere; padding: 8px 24px 32px; }
32484
+ .dxc-article img { height: auto; max-width: 100%; }
32485
+ .dxc-article a { pointer-events: none; }
32486
+ @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; } }
32487
+ </style>
32488
+ </head>
32489
+ <body>
32490
+ <main class="dxc-shell">
32491
+ <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>
32492
+ <article class="dxc-card">
32493
+ <img class="dxc-cover" src="${coverSource}" alt="${title}\u5C01\u9762">
32494
+ <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>
32495
+ <div class="dxc-article">${renderedArticle}</div>
32496
+ </article>
32497
+ </main>
32498
+ </body>
32499
+ </html>`;
32500
+ const bytes = Buffer.byteLength(html, "utf8");
32501
+ if (bytes > MAXIMUM_LOCAL_PREVIEW_BYTES) {
32502
+ throw new WechatCliError(
32503
+ "DXC_PUBLISHING_LOCAL_PREVIEW_TOO_LARGE",
32504
+ `\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`
32505
+ );
32506
+ }
32507
+ return {
32508
+ hash: createHash8("sha256").update(html, "utf8").digest("hex"),
32509
+ html
32510
+ };
32511
+ }
32512
+ function writeLocalPreviewBrowserEvent(output, event) {
32513
+ output.writeStderr(
32514
+ `DXC_BROWSER_EVENT ${JSON.stringify({
32515
+ action: "open-file",
32516
+ contentHash: event.contentHash,
32517
+ kind: "content-local-preview",
32518
+ path: event.path,
32519
+ replaceExisting: true,
32520
+ surface: "agent-side-panel"
32521
+ })}
32522
+ `
32523
+ );
32524
+ }
32525
+ function fileSystemErrorCode(error) {
32526
+ return typeof error === "object" && error !== null && "code" in error ? String(error.code) : void 0;
32527
+ }
32528
+ function localPreviewOutputConflict() {
32529
+ return new WechatCliError(
32530
+ "DXC_PUBLISHING_LOCAL_PREVIEW_OUTPUT_CONFLICT",
32531
+ "\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"
32532
+ );
32533
+ }
32534
+ async function ensureLocalPreviewDirectory(directory) {
32535
+ let metadata;
32536
+ try {
32537
+ metadata = await lstat7(directory);
32538
+ } catch (error) {
32539
+ if (fileSystemErrorCode(error) !== "ENOENT") {
32540
+ throw error;
32541
+ }
32542
+ try {
32543
+ await mkdir4(directory, { mode: 448 });
32544
+ } catch (mkdirError) {
32545
+ if (fileSystemErrorCode(mkdirError) !== "EEXIST") {
32546
+ throw mkdirError;
32547
+ }
32548
+ }
32549
+ metadata = await lstat7(directory);
32550
+ }
32551
+ if (!metadata.isDirectory() || metadata.isSymbolicLink()) {
32552
+ throw localPreviewOutputConflict();
32553
+ }
32554
+ }
32555
+ async function safeLocalPreviewOutput(options) {
32556
+ const projectDirectory2 = path8.resolve(options.projectDirectory);
32557
+ const previewDirectory = path8.join(projectDirectory2, ".dxc", "previews");
32558
+ const outputFile = path8.resolve(options.outputFile);
32559
+ const relativeOutput = path8.relative(previewDirectory, outputFile);
32560
+ if (relativeOutput.length === 0 || relativeOutput === ".." || relativeOutput.startsWith(`..${path8.sep}`) || path8.isAbsolute(relativeOutput)) {
32561
+ throw localPreviewOutputConflict();
32562
+ }
32563
+ try {
32564
+ const projectMetadata = await lstat7(projectDirectory2);
32565
+ if (!projectMetadata.isDirectory() || projectMetadata.isSymbolicLink()) {
32566
+ throw localPreviewOutputConflict();
32567
+ }
32568
+ let directory = projectDirectory2;
32569
+ const relativeParent = path8.relative(projectDirectory2, path8.dirname(outputFile));
32570
+ for (const segment of relativeParent.split(path8.sep).filter((value) => value.length > 0)) {
32571
+ directory = path8.join(directory, segment);
32572
+ await ensureLocalPreviewDirectory(directory);
32573
+ }
32574
+ try {
32575
+ const outputMetadata = await lstat7(outputFile);
32576
+ if (!outputMetadata.isFile() || outputMetadata.isSymbolicLink()) {
32577
+ throw localPreviewOutputConflict();
32578
+ }
32579
+ } catch (error) {
32580
+ if (fileSystemErrorCode(error) !== "ENOENT") {
32581
+ throw error;
32582
+ }
32583
+ }
32584
+ } catch (error) {
32585
+ if (error instanceof WechatCliError) {
32586
+ throw error;
32587
+ }
32588
+ throw new WechatCliError(
32589
+ "DXC_PUBLISHING_LOCAL_PREVIEW_WRITE_FAILED",
32590
+ "\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"
32591
+ );
32592
+ }
32593
+ return outputFile;
32594
+ }
31512
32595
  async function presentDraftPreview(output, openExternal, preview, browserMode) {
31513
32596
  if (browserMode === "agent") {
31514
32597
  writeAgentBrowserEvent(output, {
@@ -31590,13 +32673,13 @@ async function retryExpiredBrowserFlow(action, output) {
31590
32673
  }
31591
32674
  }
31592
32675
  function sessionPath(stateDirectory) {
31593
- return path7.join(stateDirectory, "wechat-session.json");
32676
+ return path8.join(stateDirectory, "wechat-session.json");
31594
32677
  }
31595
32678
  function deviceIdentityPath(stateDirectory) {
31596
- return path7.join(stateDirectory, "device-identity.json");
32679
+ return path8.join(stateDirectory, "device-identity.json");
31597
32680
  }
31598
32681
  function publishingMediaType(inputPath, kind) {
31599
- const extension = path7.extname(inputPath).toLowerCase();
32682
+ const extension = path8.extname(inputPath).toLowerCase();
31600
32683
  if (kind === "article-source" && (extension === ".md" || extension === ".markdown")) {
31601
32684
  return "text/markdown";
31602
32685
  }
@@ -31608,7 +32691,7 @@ function publishingMediaType(inputPath, kind) {
31608
32691
  async function readProtectedStateFile(target, invalidCode) {
31609
32692
  let handle;
31610
32693
  try {
31611
- handle = await open3(target, fileConstants3.O_RDONLY | fileConstants3.O_NOFOLLOW);
32694
+ handle = await open4(target, fileConstants4.O_RDONLY | fileConstants4.O_NOFOLLOW);
31612
32695
  } catch (error) {
31613
32696
  if (error instanceof WechatCliError) {
31614
32697
  throw error;
@@ -31630,17 +32713,17 @@ async function readProtectedStateFile(target, invalidCode) {
31630
32713
  }
31631
32714
  }
31632
32715
  async function saveSession(stateDirectory, session) {
31633
- await mkdir3(stateDirectory, { mode: 448, recursive: true });
32716
+ await mkdir4(stateDirectory, { mode: 448, recursive: true });
31634
32717
  await chmod(stateDirectory, 448);
31635
32718
  const target = sessionPath(stateDirectory);
31636
32719
  const temporary = `${target}.${process.pid}.tmp`;
31637
- await writeFile3(temporary, `${JSON.stringify(session)}
32720
+ await writeFile4(temporary, `${JSON.stringify(session)}
31638
32721
  `, {
31639
32722
  encoding: "utf8",
31640
32723
  mode: 384
31641
32724
  });
31642
32725
  await chmod(temporary, 384);
31643
- await rename5(temporary, target);
32726
+ await rename6(temporary, target);
31644
32727
  await chmod(target, 384);
31645
32728
  }
31646
32729
  async function readSessionValue(stateDirectory) {
@@ -31758,22 +32841,22 @@ async function loadOrCreateDeviceIdentity(stateDirectory) {
31758
32841
  const keyPair = generateDeviceKeyPair();
31759
32842
  const identity = {
31760
32843
  deviceName: os2.hostname().trim().slice(0, 80) || "DxC \u8BBE\u5907",
31761
- installationId: randomUUID4(),
32844
+ installationId: randomUUID5(),
31762
32845
  privateKeyPem: keyPair.privateKeyPem,
31763
32846
  publicKeyFingerprint: keyPair.publicKeyFingerprint,
31764
32847
  publicKeyPem: keyPair.publicKeyPem
31765
32848
  };
31766
- await mkdir3(stateDirectory, { mode: 448, recursive: true });
32849
+ await mkdir4(stateDirectory, { mode: 448, recursive: true });
31767
32850
  await chmod(stateDirectory, 448);
31768
32851
  const target = deviceIdentityPath(stateDirectory);
31769
32852
  const temporary = `${target}.${process.pid}.tmp`;
31770
- await writeFile3(temporary, `${JSON.stringify(identity)}
32853
+ await writeFile4(temporary, `${JSON.stringify(identity)}
31771
32854
  `, {
31772
32855
  encoding: "utf8",
31773
32856
  mode: 384
31774
32857
  });
31775
32858
  await chmod(temporary, 384);
31776
- await rename5(temporary, target);
32859
+ await rename6(temporary, target);
31777
32860
  await chmod(target, 384);
31778
32861
  return { created: true, identity };
31779
32862
  }
@@ -31785,11 +32868,31 @@ async function responseJson(response) {
31785
32868
  }
31786
32869
  }
31787
32870
  async function checkedJson(response) {
31788
- const value = await responseJson(response);
32871
+ let value;
32872
+ try {
32873
+ value = await responseJson(response);
32874
+ } catch (error) {
32875
+ if (!response.ok && error instanceof WechatCliError && error.code === "DXC_API_RESPONSE_INVALID") {
32876
+ throw new WechatCliError(
32877
+ "DXC_API_REQUEST_FAILED",
32878
+ `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`,
32879
+ response.status === 429 || response.status >= 500,
32880
+ { httpStatus: response.status }
32881
+ );
32882
+ }
32883
+ throw error;
32884
+ }
31789
32885
  if (!response.ok) {
31790
32886
  const apiError = apiErrorResponseSchema.safeParse(value);
32887
+ if (apiError.success) {
32888
+ 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;
32889
+ throw new WechatCliError(apiError.data.error.code, guidance, apiError.data.error.retryable);
32890
+ }
31791
32891
  throw new WechatCliError(
31792
- apiError.success ? apiError.data.error.code : "DXC_API_REQUEST_FAILED"
32892
+ "DXC_API_REQUEST_FAILED",
32893
+ `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`,
32894
+ response.status === 429 || response.status >= 500,
32895
+ { httpStatus: response.status }
31793
32896
  );
31794
32897
  }
31795
32898
  return value;
@@ -31800,10 +32903,10 @@ function authorizationHeaders(clientToken) {
31800
32903
  };
31801
32904
  }
31802
32905
  function secretHash(value) {
31803
- return createHash7("sha256").update(value, "utf8").digest("hex");
32906
+ return createHash8("sha256").update(value, "utf8").digest("hex");
31804
32907
  }
31805
32908
  function bytesHash(value) {
31806
- return createHash7("sha256").update(value).digest("hex");
32909
+ return createHash8("sha256").update(value).digest("hex");
31807
32910
  }
31808
32911
  function assertCompleteInlineAssets(expected, actual) {
31809
32912
  const expectedRecords = expected.map((asset) => ({
@@ -31832,7 +32935,7 @@ var WechatCli = class {
31832
32935
  this.#openExternal = dependencies.openExternal ?? defaultOpenExternal;
31833
32936
  this.#pollIntervalMilliseconds = dependencies.pollIntervalMilliseconds ?? DEFAULT_POLL_INTERVAL_MS;
31834
32937
  this.#sleep = dependencies.sleep ?? defaultSleep;
31835
- this.#stateDirectory = dependencies.stateDirectory ?? process.env["DXC_CLI_STATE_DIR"] ?? path7.join(os2.homedir(), ".dxc");
32938
+ this.#stateDirectory = dependencies.stateDirectory ?? process.env["DXC_CLI_STATE_DIR"] ?? path8.join(os2.homedir(), ".dxc");
31836
32939
  }
31837
32940
  async #authenticatedFetch(session, url, init = {}, timeoutMilliseconds = 8e3) {
31838
32941
  const request = async (current) => {
@@ -31915,7 +33018,7 @@ var WechatCli = class {
31915
33018
  const pending = session.pendingRefresh ?? {
31916
33019
  nextDeviceRefreshToken: randomBytes(32).toString("base64url"),
31917
33020
  nextDeviceToken: randomBytes(32).toString("base64url"),
31918
- rotationId: randomUUID4()
33021
+ rotationId: randomUUID5()
31919
33022
  };
31920
33023
  const pendingSession = {
31921
33024
  apiBaseUrl: session.apiBaseUrl,
@@ -32049,8 +33152,7 @@ var WechatCli = class {
32049
33152
  `);
32050
33153
  return result;
32051
33154
  }
32052
- async previewDraft(options, output) {
32053
- let session = await loadSession(this.#stateDirectory);
33155
+ async previewLocalDraft(options, output) {
32054
33156
  const prepared = await preparePublishingDraft({
32055
33157
  articleFile: options.articleFile,
32056
33158
  ...options.assetsDirectory === void 0 ? {} : { assetsDirectory: options.assetsDirectory },
@@ -32058,9 +33160,123 @@ var WechatCli = class {
32058
33160
  ...options.title === void 0 ? {} : { title: options.title },
32059
33161
  ...options.visualPlanFile === void 0 ? {} : { visualPlanFile: options.visualPlanFile }
32060
33162
  });
33163
+ const preview = localVisualPreviewHtml(prepared);
33164
+ const outputFile = await safeLocalPreviewOutput({
33165
+ outputFile: options.outputFile,
33166
+ projectDirectory: options.projectDirectory
33167
+ });
33168
+ const protectedInputs = /* @__PURE__ */ new Set([
33169
+ path8.resolve(prepared.article.path),
33170
+ path8.resolve(prepared.cover.path),
33171
+ ...prepared.inlineAssets.map((asset) => path8.resolve(asset.path)),
33172
+ ...options.visualPlanFile === void 0 ? [] : [path8.resolve(options.visualPlanFile)]
33173
+ ]);
33174
+ if (protectedInputs.has(outputFile)) {
33175
+ throw new WechatCliError(
33176
+ "DXC_PUBLISHING_LOCAL_PREVIEW_OUTPUT_CONFLICT",
33177
+ "\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"
33178
+ );
33179
+ }
33180
+ try {
33181
+ await writePrivateBuffer(outputFile, Buffer.from(preview.html, "utf8"));
33182
+ } catch {
33183
+ throw new WechatCliError(
33184
+ "DXC_PUBLISHING_LOCAL_PREVIEW_WRITE_FAILED",
33185
+ "\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"
33186
+ );
33187
+ }
33188
+ const result = {
33189
+ command: "wechat.draft.preview-local",
33190
+ data: {
33191
+ contentHash: preview.hash,
33192
+ inlineImageCount: prepared.inlineAssets.length,
33193
+ path: outputFile,
33194
+ presentation: {
33195
+ action: "open-file",
33196
+ replaceExisting: true,
33197
+ surface: "agent-side-panel"
33198
+ },
33199
+ templateId: prepared.localRender.templateId
33200
+ },
33201
+ ok: true
33202
+ };
33203
+ output.writeStdout(`${JSON.stringify(result)}
33204
+ `);
33205
+ writeLocalPreviewBrowserEvent(output, { contentHash: preview.hash, path: outputFile });
33206
+ output.writeStderr(
33207
+ "\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"
33208
+ );
33209
+ return result;
33210
+ }
33211
+ async optimizeDraftImages(options, output) {
33212
+ const result = await optimizePublishingImages(options);
33213
+ output.writeStdout(`${JSON.stringify(result)}
33214
+ `);
33215
+ output.writeStderr(
33216
+ 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
33217
+ ` : `\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
33218
+ `
33219
+ );
33220
+ return result;
33221
+ }
33222
+ async previewDraft(options, output) {
33223
+ let session = await loadSession(this.#stateDirectory);
33224
+ if (options.title !== void 0 && options.title.trim().length === 0) {
33225
+ throw new WechatCliError(
33226
+ "DXC_PUBLISHING_TITLE_TOO_LONG",
33227
+ `\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`,
33228
+ false,
33229
+ { currentLength: 0, empty: true, max: WECHAT_TITLE_CHARACTER_LIMIT }
33230
+ );
33231
+ }
33232
+ let prepared;
33233
+ try {
33234
+ prepared = await preparePublishingDraft({
33235
+ articleFile: options.articleFile,
33236
+ ...options.assetsDirectory === void 0 ? {} : { assetsDirectory: options.assetsDirectory },
33237
+ ...options.coverFile === void 0 ? {} : { coverFile: options.coverFile },
33238
+ ...options.digest === void 0 ? {} : { digest: options.digest },
33239
+ ...options.title === void 0 ? {} : { title: options.title },
33240
+ ...options.visualPlanFile === void 0 ? {} : { visualPlanFile: options.visualPlanFile }
33241
+ });
33242
+ } catch (error) {
33243
+ if (error instanceof WechatCliError && error.code === "DXC_PUBLISHING_PREFLIGHT_FAILED" && error.fields?.["metadataField"] === "digest") {
33244
+ const currentLength = error.fields["currentLength"];
33245
+ const max = error.fields["max"];
33246
+ throw new WechatCliError("DXC_PUBLISHING_DIGEST_TOO_LONG", error.guidance, false, {
33247
+ ...typeof currentLength === "number" ? { currentLength } : {},
33248
+ ...typeof max === "number" ? { max } : {}
33249
+ });
33250
+ }
33251
+ throw error;
33252
+ }
32061
33253
  const finalBundle = prepared.bundle;
32062
- if (finalBundle.title.length === 0 || [...finalBundle.title].length > 32 || [...finalBundle.author].length > 16 || [...finalBundle.digest].length > 120) {
32063
- throw new WechatCliError("DXC_PUBLISHING_WECHAT_METADATA_INVALID");
33254
+ const titleLength = [...finalBundle.title].length;
33255
+ if (titleLength === 0 || titleLength > WECHAT_TITLE_CHARACTER_LIMIT) {
33256
+ throw new WechatCliError(
33257
+ "DXC_PUBLISHING_TITLE_TOO_LONG",
33258
+ 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`,
33259
+ false,
33260
+ { currentLength: titleLength, empty: titleLength === 0, max: WECHAT_TITLE_CHARACTER_LIMIT }
33261
+ );
33262
+ }
33263
+ const authorLength = [...finalBundle.author].length;
33264
+ if (authorLength > WECHAT_AUTHOR_CHARACTER_LIMIT) {
33265
+ throw new WechatCliError(
33266
+ "DXC_PUBLISHING_AUTHOR_TOO_LONG",
33267
+ `\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`,
33268
+ false,
33269
+ { currentLength: authorLength, max: WECHAT_AUTHOR_CHARACTER_LIMIT }
33270
+ );
33271
+ }
33272
+ const digestLength = [...finalBundle.digest].length;
33273
+ if (digestLength > WECHAT_DIGEST_CHARACTER_LIMIT) {
33274
+ throw new WechatCliError(
33275
+ "DXC_PUBLISHING_DIGEST_TOO_LONG",
33276
+ `\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`,
33277
+ false,
33278
+ { currentLength: digestLength, max: WECHAT_DIGEST_CHARACTER_LIMIT }
33279
+ );
32064
33280
  }
32065
33281
  const accountsResult = await this.#authenticatedFetch(
32066
33282
  session,
@@ -32120,8 +33336,6 @@ var WechatCli = class {
32120
33336
  );
32121
33337
  assertCompleteInlineAssets(prepared.inlineAssets, snapshot.inlineAssets);
32122
33338
  if (!snapshot.preflight.ok) {
32123
- output.writeStdout(`${JSON.stringify({ account, snapshot })}
32124
- `);
32125
33339
  throw new WechatCliError("DXC_PUBLISHING_CLOUD_PREFLIGHT_FAILED");
32126
33340
  }
32127
33341
  const previewResponse = await this.#authenticatedFetch(
@@ -32134,7 +33348,14 @@ var WechatCli = class {
32134
33348
  }
32135
33349
  );
32136
33350
  const preview = publishingPreviewLinkSchema.parse(await checkedJson(previewResponse.response));
32137
- const browserMode = options.browserMode ?? "agent";
33351
+ const browserMode = options.browserMode ?? "system";
33352
+ const templateWarnings = prepared.bundle.templateHint !== void 0 && prepared.bundle.templateHint !== snapshot.templateId ? [
33353
+ {
33354
+ code: "DXC_PUBLISHING_TEMPLATE_HINT_MISMATCH",
33355
+ effectiveTemplateId: snapshot.templateId,
33356
+ requestedHintTemplateId: prepared.bundle.templateHint
33357
+ }
33358
+ ] : [];
32138
33359
  const result = {
32139
33360
  account,
32140
33361
  presentation: {
@@ -32142,10 +33363,17 @@ var WechatCli = class {
32142
33363
  surface: browserMode === "agent" ? "agent-side-panel" : "system-browser"
32143
33364
  },
32144
33365
  preview,
32145
- snapshot
33366
+ snapshot,
33367
+ ...templateWarnings.length === 0 ? {} : { warnings: templateWarnings }
32146
33368
  };
32147
33369
  output.writeStdout(`${JSON.stringify(result)}
32148
33370
  `);
33371
+ if (templateWarnings[0] !== void 0) {
33372
+ output.writeStderr(
33373
+ `${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
33374
+ `
33375
+ );
33376
+ }
32149
33377
  const previewSecondsRemaining = preview.expiresInSeconds ?? Math.max(0, Math.floor((Date.parse(preview.expiresAt) - Date.now()) / 1e3));
32150
33378
  output.writeStderr(
32151
33379
  `\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
@@ -32154,7 +33382,8 @@ var WechatCli = class {
32154
33382
  const coverDescription = {
32155
33383
  "article-frontmatter": "\u6587\u7AE0\u58F0\u660E\u7684\u5185\u5BB9\u5C01\u9762",
32156
33384
  "assets-directory": "\u89C6\u89C9\u9636\u6BB5\u51C6\u5907\u7684\u5185\u5BB9\u5C01\u9762",
32157
- "explicit-file": "\u663E\u5F0F\u6307\u5B9A\u7684\u5185\u5BB9\u5C01\u9762"
33385
+ "explicit-file": "\u663E\u5F0F\u6307\u5B9A\u7684\u5185\u5BB9\u5C01\u9762",
33386
+ "visual-plan": "\u89C6\u89C9\u8BA1\u5212\u786E\u8BA4\u7684\u5185\u5BB9\u5C01\u9762"
32158
33387
  }[prepared.coverMode];
32159
33388
  output.writeStderr(
32160
33389
  `\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
@@ -32181,9 +33410,25 @@ var WechatCli = class {
32181
33410
  const secondsRemaining = preview.expiresInSeconds ?? Math.max(0, Math.floor((Date.parse(preview.expiresAt) - Date.now()) / 1e3));
32182
33411
  output.writeStderr(`\u5DF2\u4E3A\u540C\u4E00\u4E2A\u4E0D\u53EF\u53D8\u5FEB\u7167\u91CD\u5EFA\u9884\u89C8\u94FE\u63A5\uFF0C\u5C06\u5728 ${secondsRemaining} \u79D2\u540E\u5931\u6548\u3002
32183
33412
  `);
32184
- await presentDraftPreview(output, this.#openExternal, preview, options.browserMode ?? "agent");
33413
+ await presentDraftPreview(output, this.#openExternal, preview, options.browserMode ?? "system");
32185
33414
  return preview;
32186
33415
  }
33416
+ async draftPreviewStatus(options, output) {
33417
+ const session = await loadSession(this.#stateDirectory);
33418
+ const { response } = await this.#authenticatedFetch(
33419
+ session,
33420
+ `${session.apiBaseUrl}/api/v1/render-snapshots/${encodeURIComponent(options.snapshotId)}/preview-state?snapshotHash=${encodeURIComponent(options.snapshotHash)}`
33421
+ );
33422
+ const state = publishingPreviewSelectionStateSchema.parse(await checkedJson(response));
33423
+ output.writeStdout(`${JSON.stringify({ previewState: state })}
33424
+ `);
33425
+ output.writeStderr(
33426
+ state.viewed ? `\u5F53\u524D\u6700\u7EC8\u6A21\u677F\uFF1A${state.templateId}\uFF1B\u9009\u62E9\u4FEE\u8BA2 ${state.selectionRevision} \u5DF2\u6210\u529F\u6253\u5F00\u3002
33427
+ ` : `\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
33428
+ `
33429
+ );
33430
+ return state;
33431
+ }
32187
33432
  async createDraft(options, output) {
32188
33433
  if (!options.confirmed) {
32189
33434
  throw new WechatCliError(
@@ -32244,6 +33489,84 @@ var WechatCli = class {
32244
33489
  );
32245
33490
  return result;
32246
33491
  }
33492
+ async retryDraft(options, output) {
33493
+ if (!options.confirmed) {
33494
+ throw new WechatCliError(
33495
+ "DXC_DRAFT_RETRY_CONFIRMATION_REQUIRED",
33496
+ "\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"
33497
+ );
33498
+ }
33499
+ let delivery;
33500
+ try {
33501
+ delivery = await readDeliveryRetryIdentity(options.deliveryFile);
33502
+ } catch (error) {
33503
+ throw new WechatCliError(
33504
+ "DXC_DRAFT_DELIVERY_INVALID",
33505
+ error instanceof StageArtifactValidationError ? error.message : "\u65E0\u6CD5\u8BFB\u53D6 delivery \u9636\u6BB5\u4EA7\u7269\u3002"
33506
+ );
33507
+ }
33508
+ if (delivery.state !== "failed" || delivery.intentId !== options.previousIntentId) {
33509
+ throw new WechatCliError(
33510
+ "DXC_DRAFT_RETRY_NOT_SAFE",
33511
+ "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"
33512
+ );
33513
+ }
33514
+ let session = await loadSession(this.#stateDirectory);
33515
+ const previousResponse = await this.#authenticatedFetch(
33516
+ session,
33517
+ `${session.apiBaseUrl}/api/v1/draft-intents/${encodeURIComponent(options.previousIntentId)}`
33518
+ );
33519
+ session = previousResponse.session;
33520
+ const previous = publishingDraftIntentResponseSchema.parse(
33521
+ await checkedJson(previousResponse.response)
33522
+ ).intent;
33523
+ if (previous.status !== "FAILED" || previous.snapshotHash !== delivery.selectedSnapshotHash) {
33524
+ throw new WechatCliError(
33525
+ "DXC_DRAFT_RETRY_NOT_SAFE",
33526
+ "\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"
33527
+ );
33528
+ }
33529
+ const idempotencyKey = `dxc:retry:${previous.id}:${delivery.retryAttempt + 1}`;
33530
+ const retryRequest = createPublishingDraftIntentRequestSchema.parse({
33531
+ approvalId: previous.approvalId,
33532
+ previousIntentId: previous.id
33533
+ });
33534
+ const retryResponse = await this.#authenticatedFetch(
33535
+ session,
33536
+ `${session.apiBaseUrl}/api/v1/draft-intents`,
33537
+ {
33538
+ body: JSON.stringify(retryRequest),
33539
+ headers: {
33540
+ "content-type": "application/json",
33541
+ "idempotency-key": idempotencyKey
33542
+ },
33543
+ method: "POST"
33544
+ }
33545
+ );
33546
+ const result = publishingDraftIntentResponseSchema.parse(
33547
+ await checkedJson(retryResponse.response)
33548
+ );
33549
+ try {
33550
+ await bindDeliveryRetryIntentArtifact({
33551
+ idempotencyKey,
33552
+ intent: result.intent,
33553
+ previousIntentId: previous.id,
33554
+ target: options.deliveryFile
33555
+ });
33556
+ } catch (error) {
33557
+ throw new WechatCliError(
33558
+ "DXC_DRAFT_RETRY_DELIVERY_WRITE_FAILED",
33559
+ 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"
33560
+ );
33561
+ }
33562
+ output.writeStdout(`${JSON.stringify({ intent: userFacingDraftIntent(result.intent) })}
33563
+ `);
33564
+ output.writeStderr(
33565
+ `${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
33566
+ `
33567
+ );
33568
+ return result;
33569
+ }
32247
33570
  async publishingDraftStatus(intentId, output) {
32248
33571
  const session = await loadSession(this.#stateDirectory);
32249
33572
  const { response } = await this.#authenticatedFetch(
@@ -32354,7 +33677,7 @@ var WechatCli = class {
32354
33677
  `${session.apiBaseUrl}/api/v1/uploads`,
32355
33678
  {
32356
33679
  body: JSON.stringify({
32357
- fileName: path7.basename(input.path),
33680
+ fileName: path8.basename(input.path),
32358
33681
  kind,
32359
33682
  mediaType,
32360
33683
  sha256: bytesHash(input.bytes),
@@ -32599,8 +33922,8 @@ ${session.authorizationUrl}
32599
33922
  );
32600
33923
  const deviceSessionToken = randomBytes(32).toString("base64url");
32601
33924
  const deviceRefreshToken = randomBytes(32).toString("base64url");
32602
- const deviceSessionTokenHash = createHash7("sha256").update(deviceSessionToken, "utf8").digest("hex");
32603
- const deviceRefreshTokenHash = createHash7("sha256").update(deviceRefreshToken, "utf8").digest("hex");
33925
+ const deviceSessionTokenHash = createHash8("sha256").update(deviceSessionToken, "utf8").digest("hex");
33926
+ const deviceRefreshTokenHash = createHash8("sha256").update(deviceRefreshToken, "utf8").digest("hex");
32604
33927
  const message = createDeviceProofMessage({
32605
33928
  bindingSessionId: binding.id,
32606
33929
  challenge: binding.challenge,
@@ -32735,12 +34058,24 @@ function previewBrowserMode(value) {
32735
34058
  function collectValues(value, previous) {
32736
34059
  return [...previous, value];
32737
34060
  }
32738
- async function runWechatAction(context, action) {
34061
+ async function runWechatAction(context, action, json = false) {
32739
34062
  try {
32740
34063
  await action(new WechatCli(context.wechatDependencies));
32741
34064
  } catch (error) {
32742
34065
  const code = error instanceof WechatCliError ? error.code : "DXC_WECHAT_FAILED";
32743
34066
  const guidance = error instanceof WechatCliError ? error.guidance : void 0;
34067
+ const retryable = error instanceof WechatCliError ? error.retryable : false;
34068
+ const fields = error instanceof WechatCliError ? error.fields : void 0;
34069
+ if (json) {
34070
+ writeJson(context, {
34071
+ error: {
34072
+ code,
34073
+ ...fields === void 0 ? {} : { fields },
34074
+ message: guidance ?? code,
34075
+ retryable
34076
+ }
34077
+ });
34078
+ }
32744
34079
  context.writeStderr(`${code}${guidance === void 0 ? "" : `: ${guidance}`}
32745
34080
  `);
32746
34081
  context.setExitCode(1);
@@ -32768,7 +34103,7 @@ async function loadKnowledgeModule() {
32768
34103
  Reflect.apply(emitWarning, process, [warning2, ...arguments_]);
32769
34104
  });
32770
34105
  try {
32771
- return await import("./chunks/knowledge-PWFALFEC.js");
34106
+ return await import("./chunks/knowledge-RAGVN36S.js");
32772
34107
  } finally {
32773
34108
  process.emitWarning = emitWarning;
32774
34109
  }
@@ -32782,7 +34117,7 @@ async function loadMonitorModule() {
32782
34117
  Reflect.apply(emitWarning, process, [warning2, ...arguments_]);
32783
34118
  });
32784
34119
  try {
32785
- return await import("./chunks/monitor-CL5UXEO2.js");
34120
+ return await import("./chunks/monitor-XTYUQFQT.js");
32786
34121
  } finally {
32787
34122
  process.emitWarning = emitWarning;
32788
34123
  }
@@ -32850,7 +34185,8 @@ async function runMemoryAction(context, command, json, action) {
32850
34185
  error: { code, message },
32851
34186
  ok: false
32852
34187
  }),
32853
- code
34188
+ code,
34189
+ message
32854
34190
  );
32855
34191
  }
32856
34192
  }
@@ -32885,10 +34221,16 @@ async function runProjectAction(context, command, json, action) {
32885
34221
  json,
32886
34222
  contentProjectErrorResultSchema.parse({
32887
34223
  command,
32888
- error: { code, message },
34224
+ error: {
34225
+ code,
34226
+ message,
34227
+ ...error instanceof ProjectCliError ? error.details : {}
34228
+ },
32889
34229
  ok: false
32890
34230
  }),
32891
- code
34231
+ code,
34232
+ message,
34233
+ error instanceof ProjectCliError ? error.details.recovery : void 0
32892
34234
  );
32893
34235
  }
32894
34236
  }
@@ -33264,16 +34606,23 @@ ${hint}
33264
34606
  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(
33265
34607
  "--skill-version <version>",
33266
34608
  "\u7279\u6B8A\u63A5\u7BA1\u6D41\u7A0B\u4F7F\u7528\u7684 Skill \u7248\u672C\uFF1B\u5E38\u89C4\u9636\u6BB5\u7531 catalog \u81EA\u52A8\u786E\u5B9A"
33267
- ).requiredOption("--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(
34609
+ ).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(
33268
34610
  "--data-transit <transit>",
33269
34611
  "local-only / agent-provider / dxc-cloud / unknown",
33270
34612
  "unknown"
33271
- ).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("--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(
34613
+ ).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(
34614
+ "--authorization-purpose <purpose>",
34615
+ "\u9636\u6BB5\u5185\u5916\u90E8\u52A8\u4F5C\u6388\u6743\uFF1B\u5F53\u524D\u4EC5 visual-plan \u652F\u6301 image-generation"
34616
+ ).option("--confirmed-by <actor>", "\u786E\u8BA4\u4EBA\u6216\u7A33\u5B9A\u8EAB\u4EFD\u6807\u8BC6", "local-interactive-user").option(
34617
+ "--confirmation-snapshot <sha256>",
34618
+ "\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"
34619
+ ).option("--json", "\u8F93\u51FA JSON").action(
33272
34620
  async (stage, options) => runProjectAction(
33273
34621
  context,
33274
34622
  "project.checkpoint",
33275
34623
  options.json === true,
33276
34624
  async (projectCli) => projectCli.checkpoint({
34625
+ ...options.authorizationPurpose === void 0 ? {} : { authorizationPurpose: options.authorizationPurpose },
33277
34626
  confirmed: options.confirm === true,
33278
34627
  ...options.confirmedBy === void 0 ? {} : { confirmedBy: options.confirmedBy },
33279
34628
  ...options.confirmationSnapshot === void 0 ? {} : {
@@ -33294,7 +34643,7 @@ ${hint}
33294
34643
  ...options.skillVersion === void 0 ? {} : { skillVersion: options.skillVersion },
33295
34644
  stage,
33296
34645
  status: options.status,
33297
- summary: options.summary,
34646
+ ...options.summary === void 0 ? {} : { summary: options.summary },
33298
34647
  ...options.waitingFor === void 0 ? {} : { waitingFor: options.waitingFor }
33299
34648
  })
33300
34649
  )
@@ -33456,9 +34805,13 @@ ${hint}
33456
34805
  })
33457
34806
  );
33458
34807
  auth.command("status").description("\u663E\u793A\u5F53\u524D\u8BBE\u5907\u3001\u7528\u6237\u548C\u5185\u5BB9\u7A7A\u95F4").option("--json", "\u8F93\u51FA JSON").action(
33459
- async () => runWechatAction(context, async (wechatCli) => {
33460
- await wechatCli.status(context);
33461
- })
34808
+ async (options) => runWechatAction(
34809
+ context,
34810
+ async (wechatCli) => {
34811
+ await wechatCli.status(context);
34812
+ },
34813
+ options.json === true
34814
+ )
33462
34815
  );
33463
34816
  auth.command("logout").description("\u64A4\u9500\u5F53\u524D\u8BBE\u5907\u4F1A\u8BDD").action(
33464
34817
  async () => runWechatAction(context, async (wechatCli) => {
@@ -33479,149 +34832,312 @@ ${hint}
33479
34832
  })
33480
34833
  );
33481
34834
  wechat.command("accounts").description("\u5217\u51FA\u5DF2\u7ED1\u5B9A\u516C\u4F17\u53F7\u548C\u8349\u7A3F\u6743\u9650").option("--json", "\u8F93\u51FA JSON").action(
33482
- async (options) => runWechatAction(context, async (wechatCli) => {
33483
- await wechatCli.accounts(context, options.json === true);
33484
- })
34835
+ async (options) => runWechatAction(
34836
+ context,
34837
+ async (wechatCli) => {
34838
+ await wechatCli.accounts(context, options.json === true);
34839
+ },
34840
+ options.json === true
34841
+ )
33485
34842
  );
33486
34843
  const draft = wechat.command("draft").description("\u9884\u89C8\u5E76\u521B\u5EFA\u5FAE\u4FE1\u516C\u4F17\u53F7\u8349\u7A3F");
33487
- 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("--browser <agent|system>", "\u4F18\u5148\u5728 Agent \u53F3\u4FA7\u9884\u89C8\uFF1B\u4E0D\u652F\u6301\u65F6\u53EF\u6539\u7528\u7CFB\u7EDF\u6D4F\u89C8\u5668", "agent").action(
33488
- async (options) => runWechatAction(context, async (wechatCli) => {
33489
- await wechatCli.previewDraft(
33490
- {
33491
- accountId: validatedOption(
33492
- options.account,
33493
- /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu,
33494
- "account"
33495
- ),
33496
- browserMode: previewBrowserMode(options.browser),
33497
- articleFile: resolveUserPath({
33498
- currentDirectory: context.currentDirectory,
33499
- homeDirectory: context.homeDirectory,
33500
- input: options.article
33501
- }),
33502
- ...options.assetsDirectory === void 0 ? {} : {
33503
- assetsDirectory: resolveUserPath({
34844
+ 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(
34845
+ async (options) => runWechatAction(
34846
+ context,
34847
+ async (wechatCli) => {
34848
+ await wechatCli.optimizeDraftImages(
34849
+ {
34850
+ projectDirectory: resolveUserPath({
33504
34851
  currentDirectory: context.currentDirectory,
33505
34852
  homeDirectory: context.homeDirectory,
33506
- input: options.assetsDirectory
33507
- })
33508
- },
33509
- ...options.cover === void 0 ? {} : {
33510
- coverFile: options.cover === "auto" ? "auto" : resolveUserPath({
34853
+ input: options.directory
34854
+ }),
34855
+ visualPlanFile: resolveUserPath({
33511
34856
  currentDirectory: context.currentDirectory,
33512
34857
  homeDirectory: context.homeDirectory,
33513
- input: options.cover
34858
+ input: options.visualPlan
33514
34859
  })
33515
34860
  },
33516
- ...options.title === void 0 ? {} : { title: options.title },
33517
- ...options.visualPlan === void 0 ? {} : {
34861
+ context
34862
+ );
34863
+ },
34864
+ options.json === true
34865
+ )
34866
+ );
34867
+ 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(
34868
+ "--output <path>",
34869
+ "\u6D3E\u751F\u9884\u89C8\u6587\u4EF6\uFF1B\u9ED8\u8BA4\u4FDD\u5B58\u5728\u9879\u76EE\u79C1\u6709\u76EE\u5F55",
34870
+ ".dxc/previews/visual-preview.html"
34871
+ ).option("--json", "\u8F93\u51FA JSON\uFF1B\u540C\u65F6\u53D1\u51FA\u53F3\u4FA7\u6D4F\u89C8\u5668\u66FF\u6362\u4E8B\u4EF6").action(
34872
+ async (options) => runWechatAction(
34873
+ context,
34874
+ async (wechatCli) => {
34875
+ await wechatCli.previewLocalDraft(
34876
+ {
34877
+ articleFile: resolveUserPath({
34878
+ currentDirectory: context.currentDirectory,
34879
+ homeDirectory: context.homeDirectory,
34880
+ input: options.article
34881
+ }),
34882
+ assetsDirectory: resolveUserPath({
34883
+ currentDirectory: context.currentDirectory,
34884
+ homeDirectory: context.homeDirectory,
34885
+ input: options.assetsDirectory
34886
+ }),
34887
+ ...options.cover === void 0 ? {} : {
34888
+ coverFile: options.cover === "auto" ? "auto" : resolveUserPath({
34889
+ currentDirectory: context.currentDirectory,
34890
+ homeDirectory: context.homeDirectory,
34891
+ input: options.cover
34892
+ })
34893
+ },
34894
+ outputFile: resolveUserPath({
34895
+ currentDirectory: context.currentDirectory,
34896
+ homeDirectory: context.homeDirectory,
34897
+ input: options.output
34898
+ }),
34899
+ projectDirectory: context.currentDirectory,
34900
+ ...options.title === void 0 ? {} : { title: options.title },
33518
34901
  visualPlanFile: resolveUserPath({
33519
34902
  currentDirectory: context.currentDirectory,
33520
34903
  homeDirectory: context.homeDirectory,
33521
34904
  input: options.visualPlan
33522
34905
  })
33523
- }
33524
- },
33525
- context
33526
- );
33527
- })
34906
+ },
34907
+ context
34908
+ );
34909
+ },
34910
+ options.json === true
34911
+ )
33528
34912
  );
33529
- draft.command("preview-refresh").description("\u4E3A\u540C\u4E00\u4E2A\u4E0D\u53EF\u53D8\u5FEB\u7167\u91CD\u5EFA\u77ED\u65F6\u9884\u89C8\u94FE\u63A5").option("--snapshot <uuid>", "\u4E0D\u53EF\u53D8\u5FEB\u7167 ID").option("--snapshot-hash <sha256>", "\u4E0D\u53EF\u53D8\u5FEB\u7167 SHA-256").option("--browser <agent|system>", "\u4F18\u5148\u5728 Agent \u53F3\u4FA7\u9884\u89C8\uFF1B\u4E0D\u652F\u6301\u65F6\u53EF\u6539\u7528\u7CFB\u7EDF\u6D4F\u89C8\u5668", "agent").action(
33530
- async (options) => runWechatAction(context, async (wechatCli) => {
33531
- const missing = [
33532
- ...options.snapshot === void 0 ? ["--snapshot"] : [],
33533
- ...options.snapshotHash === void 0 ? ["--snapshot-hash"] : []
33534
- ];
33535
- if (missing.length > 0) {
33536
- throw new WechatCliError(
33537
- "DXC_PREVIEW_REFRESH_OPTIONS_REQUIRED",
33538
- `\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570\uFF1A${missing.join("\u3001")}\u3002`
34913
+ 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(
34914
+ "--browser <agent|system>",
34915
+ "\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",
34916
+ "system"
34917
+ ).option("--json", "\u8F93\u51FA JSON\uFF1B\u5931\u8D25\u65F6\u4E5F\u5728 stdout \u8FD4\u56DE\u7ED3\u6784\u5316\u9519\u8BEF").action(
34918
+ async (options) => runWechatAction(
34919
+ context,
34920
+ async (wechatCli) => {
34921
+ await wechatCli.previewDraft(
34922
+ {
34923
+ accountId: validatedOption(
34924
+ options.account,
34925
+ /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu,
34926
+ "account"
34927
+ ),
34928
+ browserMode: previewBrowserMode(options.browser),
34929
+ articleFile: resolveUserPath({
34930
+ currentDirectory: context.currentDirectory,
34931
+ homeDirectory: context.homeDirectory,
34932
+ input: options.article
34933
+ }),
34934
+ ...options.assetsDirectory === void 0 ? {} : {
34935
+ assetsDirectory: resolveUserPath({
34936
+ currentDirectory: context.currentDirectory,
34937
+ homeDirectory: context.homeDirectory,
34938
+ input: options.assetsDirectory
34939
+ })
34940
+ },
34941
+ ...options.cover === void 0 ? {} : {
34942
+ coverFile: options.cover === "auto" ? "auto" : resolveUserPath({
34943
+ currentDirectory: context.currentDirectory,
34944
+ homeDirectory: context.homeDirectory,
34945
+ input: options.cover
34946
+ })
34947
+ },
34948
+ ...options.digest === void 0 ? {} : { digest: options.digest },
34949
+ ...options.title === void 0 ? {} : { title: options.title },
34950
+ ...options.visualPlan === void 0 ? {} : {
34951
+ visualPlanFile: resolveUserPath({
34952
+ currentDirectory: context.currentDirectory,
34953
+ homeDirectory: context.homeDirectory,
34954
+ input: options.visualPlan
34955
+ })
34956
+ }
34957
+ },
34958
+ context
33539
34959
  );
33540
- }
33541
- if (options.snapshot === void 0 || options.snapshotHash === void 0) {
33542
- throw new WechatCliError("DXC_PREVIEW_REFRESH_OPTIONS_REQUIRED");
33543
- }
33544
- await wechatCli.refreshDraftPreview(
33545
- {
33546
- browserMode: previewBrowserMode(options.browser),
33547
- snapshotHash: validatedOption(
33548
- options.snapshotHash,
33549
- /^[a-f0-9]{64}$/u,
33550
- "snapshot-hash"
33551
- ),
33552
- snapshotId: validatedOption(
33553
- options.snapshot,
33554
- /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu,
33555
- "snapshot"
33556
- )
33557
- },
33558
- context
33559
- );
33560
- })
34960
+ },
34961
+ options.json === true
34962
+ )
33561
34963
  );
33562
- 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").action(
33563
- async (options) => runWechatAction(context, async (wechatCli) => {
33564
- const missing = [
33565
- ...options.account === void 0 ? ["--account"] : [],
33566
- ...options.snapshot === void 0 ? ["--snapshot"] : [],
33567
- ...options.snapshotHash === void 0 ? ["--snapshot-hash"] : [],
33568
- ...options.idempotencyKey === void 0 ? ["--idempotency-key"] : []
33569
- ];
33570
- if (missing.length > 0) {
33571
- throw new WechatCliError(
33572
- "DXC_DRAFT_OPTIONS_REQUIRED",
33573
- `\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570\uFF1A${missing.join("\u3001")}\u3002`
34964
+ draft.command("preview-refresh").description("\u4E3A\u540C\u4E00\u4E2A\u4E0D\u53EF\u53D8\u5FEB\u7167\u91CD\u5EFA\u77ED\u65F6\u9884\u89C8\u94FE\u63A5").option("--snapshot <uuid>", "\u4E0D\u53EF\u53D8\u5FEB\u7167 ID").option("--snapshot-hash <sha256>", "\u4E0D\u53EF\u53D8\u5FEB\u7167 SHA-256").option(
34965
+ "--browser <agent|system>",
34966
+ "\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",
34967
+ "system"
34968
+ ).option("--json", "\u8F93\u51FA JSON\uFF1B\u5931\u8D25\u65F6\u4E5F\u5728 stdout \u8FD4\u56DE\u7ED3\u6784\u5316\u9519\u8BEF").action(
34969
+ async (options) => runWechatAction(
34970
+ context,
34971
+ async (wechatCli) => {
34972
+ const missing = [
34973
+ ...options.snapshot === void 0 ? ["--snapshot"] : [],
34974
+ ...options.snapshotHash === void 0 ? ["--snapshot-hash"] : []
34975
+ ];
34976
+ if (missing.length > 0) {
34977
+ throw new WechatCliError(
34978
+ "DXC_PREVIEW_REFRESH_OPTIONS_REQUIRED",
34979
+ `\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570\uFF1A${missing.join("\u3001")}\u3002`
34980
+ );
34981
+ }
34982
+ if (options.snapshot === void 0 || options.snapshotHash === void 0) {
34983
+ throw new WechatCliError("DXC_PREVIEW_REFRESH_OPTIONS_REQUIRED");
34984
+ }
34985
+ await wechatCli.refreshDraftPreview(
34986
+ {
34987
+ browserMode: previewBrowserMode(options.browser),
34988
+ snapshotHash: validatedOption(
34989
+ options.snapshotHash,
34990
+ /^[a-f0-9]{64}$/u,
34991
+ "snapshot-hash"
34992
+ ),
34993
+ snapshotId: validatedOption(
34994
+ options.snapshot,
34995
+ /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu,
34996
+ "snapshot"
34997
+ )
34998
+ },
34999
+ context
33574
35000
  );
33575
- }
33576
- const account = options.account;
33577
- const snapshot = options.snapshot;
33578
- const snapshotHash = options.snapshotHash;
33579
- const idempotencyKey = options.idempotencyKey;
33580
- if (account === void 0 || snapshot === void 0 || snapshotHash === void 0 || idempotencyKey === void 0) {
33581
- throw new WechatCliError("DXC_DRAFT_OPTIONS_REQUIRED");
33582
- }
33583
- await wechatCli.createDraft(
33584
- {
33585
- accountId: validatedOption(
33586
- account,
33587
- /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu,
33588
- "account"
33589
- ),
33590
- confirmed: options.confirm === true,
33591
- ...options.delivery === void 0 ? {} : {
35001
+ },
35002
+ options.json === true
35003
+ )
35004
+ );
35005
+ 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(
35006
+ async (options) => runWechatAction(
35007
+ context,
35008
+ async (wechatCli) => {
35009
+ await wechatCli.draftPreviewStatus(
35010
+ {
35011
+ snapshotHash: validatedOption(
35012
+ options.snapshotHash,
35013
+ /^[a-f0-9]{64}$/u,
35014
+ "snapshot-hash"
35015
+ ),
35016
+ snapshotId: validatedOption(
35017
+ options.snapshot,
35018
+ /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu,
35019
+ "snapshot"
35020
+ )
35021
+ },
35022
+ context
35023
+ );
35024
+ },
35025
+ options.json === true
35026
+ )
35027
+ );
35028
+ 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(
35029
+ async (options) => runWechatAction(
35030
+ context,
35031
+ async (wechatCli) => {
35032
+ const deliveryFile = options.delivery === void 0 ? void 0 : resolveUserPath({
35033
+ currentDirectory: context.currentDirectory,
35034
+ homeDirectory: context.homeDirectory,
35035
+ input: options.delivery
35036
+ });
35037
+ let deliveryIdentity;
35038
+ if (deliveryFile !== void 0) {
35039
+ try {
35040
+ deliveryIdentity = await readDeliveryDraftIdentity(deliveryFile);
35041
+ } catch (error) {
35042
+ throw new WechatCliError(
35043
+ "DXC_DRAFT_DELIVERY_INVALID",
35044
+ error instanceof StageArtifactValidationError ? error.message : "\u65E0\u6CD5\u8BFB\u53D6 delivery \u9636\u6BB5\u4EA7\u7269\u3002"
35045
+ );
35046
+ }
35047
+ }
35048
+ const missing = [
35049
+ ...options.account === void 0 ? ["--account"] : [],
35050
+ ...options.snapshot === void 0 ? ["--snapshot"] : [],
35051
+ ...options.snapshotHash === void 0 ? ["--snapshot-hash"] : [],
35052
+ ...options.idempotencyKey === void 0 && deliveryIdentity === void 0 ? ["--idempotency-key \u6216 --delivery"] : []
35053
+ ];
35054
+ if (missing.length > 0) {
35055
+ throw new WechatCliError(
35056
+ "DXC_DRAFT_OPTIONS_REQUIRED",
35057
+ `\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570\uFF1A${missing.join("\u3001")}\u3002`
35058
+ );
35059
+ }
35060
+ const account = options.account;
35061
+ const snapshot = options.snapshot;
35062
+ const snapshotHash = options.snapshotHash;
35063
+ const idempotencyKey = options.idempotencyKey ?? deliveryIdentity?.idempotencyKey;
35064
+ if (account === void 0 || snapshot === void 0 || snapshotHash === void 0 || idempotencyKey === void 0) {
35065
+ throw new WechatCliError("DXC_DRAFT_OPTIONS_REQUIRED");
35066
+ }
35067
+ if (deliveryIdentity !== void 0 && (deliveryIdentity.accountId !== account || deliveryIdentity.rootSnapshotId !== snapshot || deliveryIdentity.rootSnapshotHash !== snapshotHash || options.idempotencyKey !== void 0 && options.idempotencyKey !== deliveryIdentity.idempotencyKey)) {
35068
+ throw new WechatCliError(
35069
+ "DXC_DRAFT_DELIVERY_MISMATCH",
35070
+ "\u547D\u4EE4\u4E2D\u7684\u516C\u4F17\u53F7\u3001root \u5FEB\u7167\u6216\u5E42\u7B49\u952E\u4E0E delivery \u9636\u6BB5\u4EA7\u7269\u4E0D\u4E00\u81F4\uFF1B\u5DF2\u5728\u4EFB\u4F55\u670D\u52A1\u7AEF\u8BF7\u6C42\u524D\u505C\u6B62\u3002"
35071
+ );
35072
+ }
35073
+ await wechatCli.createDraft(
35074
+ {
35075
+ accountId: validatedOption(
35076
+ account,
35077
+ /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu,
35078
+ "account"
35079
+ ),
35080
+ confirmed: options.confirm === true,
35081
+ ...deliveryFile === void 0 ? {} : {
35082
+ deliveryFile
35083
+ },
35084
+ idempotencyKey: validatedOption(
35085
+ idempotencyKey,
35086
+ /^[A-Za-z0-9._:-]{16,128}$/u,
35087
+ "idempotency-key"
35088
+ ),
35089
+ snapshotHash: validatedOption(snapshotHash, /^[a-f0-9]{64}$/u, "snapshot-hash"),
35090
+ snapshotId: validatedOption(
35091
+ snapshot,
35092
+ /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu,
35093
+ "snapshot"
35094
+ )
35095
+ },
35096
+ context
35097
+ );
35098
+ },
35099
+ options.json === true
35100
+ )
35101
+ );
35102
+ 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(
35103
+ async (options) => runWechatAction(
35104
+ context,
35105
+ async (wechatCli) => {
35106
+ await wechatCli.retryDraft(
35107
+ {
35108
+ confirmed: options.confirm === true,
33592
35109
  deliveryFile: resolveUserPath({
33593
35110
  currentDirectory: context.currentDirectory,
33594
35111
  homeDirectory: context.homeDirectory,
33595
35112
  input: options.delivery
33596
- })
35113
+ }),
35114
+ previousIntentId: validatedOption(
35115
+ options.intent,
35116
+ /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu,
35117
+ "intent"
35118
+ )
33597
35119
  },
33598
- idempotencyKey: validatedOption(
33599
- idempotencyKey,
33600
- /^[A-Za-z0-9._:-]{16,128}$/u,
33601
- "idempotency-key"
33602
- ),
33603
- snapshotHash: validatedOption(snapshotHash, /^[a-f0-9]{64}$/u, "snapshot-hash"),
33604
- snapshotId: validatedOption(
33605
- snapshot,
33606
- /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu,
33607
- "snapshot"
33608
- )
33609
- },
33610
- context
33611
- );
33612
- })
35120
+ context
35121
+ );
35122
+ },
35123
+ options.json === true
35124
+ )
33613
35125
  );
33614
- 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").action(
33615
- async (intentId) => runWechatAction(context, async (wechatCli) => {
33616
- await wechatCli.publishingDraftStatus(
33617
- validatedOption(
33618
- intentId,
33619
- /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu,
33620
- "intent-id"
33621
- ),
33622
- context
33623
- );
33624
- })
35126
+ 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(
35127
+ async (intentId, options) => runWechatAction(
35128
+ context,
35129
+ async (wechatCli) => {
35130
+ await wechatCli.publishingDraftStatus(
35131
+ validatedOption(
35132
+ intentId,
35133
+ /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu,
35134
+ "intent-id"
35135
+ ),
35136
+ context
35137
+ );
35138
+ },
35139
+ options.json === true
35140
+ )
33625
35141
  );
33626
35142
  draft.command("smoke-preview").description("\u83B7\u53D6\u56FA\u5B9A\u6D4B\u8BD5\u8349\u7A3F\u7684\u4E0D\u53EF\u53D8\u9884\u89C8").requiredOption("--account <uuid>", "\u76EE\u6807\u516C\u4F17\u53F7\u8D26\u53F7 ID").action(
33627
35143
  async (options) => runWechatAction(context, async (wechatCli) => {
@@ -33676,6 +35192,15 @@ async function runCli(arguments_, context = processContext()) {
33676
35192
  await program2.parseAsync([...arguments_]);
33677
35193
  } catch (error) {
33678
35194
  if (error instanceof CommanderError) {
35195
+ if (arguments_.includes("--json")) {
35196
+ writeJson(context, {
35197
+ error: {
35198
+ code: error.code || "DXC_CLI_OPTIONS_INVALID",
35199
+ message: error.message,
35200
+ retryable: false
35201
+ }
35202
+ });
35203
+ }
33679
35204
  context.setExitCode(error.exitCode);
33680
35205
  return;
33681
35206
  }