@gobing-ai/knowledge-kit 0.0.23 → 0.0.24

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.
Files changed (67) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/dist/index.js +137 -59
  3. package/package.json +4 -4
  4. package/plugins/generations/content-gen/dist/index.js +97 -45
  5. package/plugins/generations/core-facts-gen/dist/index.js +106 -57
  6. package/plugins/generations/daily-article-gen/dist/index.js +105 -56
  7. package/plugins/generations/dailynews-gen/dist/index.js +235 -57
  8. package/plugins/generations/dailynews-gen/src/index.ts +67 -2
  9. package/plugins/generations/dailynews-gen/src/script-builder.ts +36 -15
  10. package/plugins/generations/dailynews-gen/src/script-plan.ts +142 -0
  11. package/plugins/generations/episode-plan-gen/dist/index.js +115 -66
  12. package/plugins/generations/gemini-tts/README.md +24 -0
  13. package/plugins/generations/gemini-tts/dist/index.js +326 -260
  14. package/plugins/generations/gemini-tts/src/gemini-client.ts +41 -11
  15. package/plugins/generations/image-gen/dist/index.js +338 -117
  16. package/plugins/generations/image-gen/presets/formats/daily-news-cover.yaml +19 -0
  17. package/plugins/generations/image-gen/presets/formats/xhs-card.yaml +55 -0
  18. package/plugins/generations/image-gen/presets/styles/daily-news.yaml +9 -0
  19. package/plugins/generations/image-gen/presets/styles/xhs-knowledge.yaml +7 -0
  20. package/plugins/generations/image-gen/src/index.ts +148 -14
  21. package/plugins/generations/image-gen/src/job.ts +30 -0
  22. package/plugins/generations/image-gen/src/providers/errors.ts +91 -0
  23. package/plugins/generations/image-gen/src/providers/types.ts +79 -0
  24. package/plugins/generations/news-report-gen/dist/index.js +136 -55
  25. package/plugins/generations/news-report-gen/src/index.ts +57 -1
  26. package/plugins/generations/voice-gen/dist/index.js +119 -67
  27. package/plugins/ingestions/aihot-ingest/dist/index.js +103 -53
  28. package/plugins/ingestions/horizon-ingest/dist/index.js +102 -53
  29. package/plugins/ingestions/karakeep-local/dist/index.js +273 -224
  30. package/plugins/ingestions/last30days-ingest/dist/index.js +97 -48
  31. package/plugins/ingestions/web-search/dist/index.js +121 -72
  32. package/plugins/kk/config.example.yaml +13 -0
  33. package/plugins/kk/plugin.json +1 -1
  34. package/plugins/kk/scripts/daily-voice-style.zh.md +52 -0
  35. package/plugins/kk/scripts/kk-workflow-stages.ts +433 -16
  36. package/plugins/kk/skills/publish/SKILL.md +24 -1
  37. package/plugins/kk/skills/xhs-images/SKILL.md +89 -0
  38. package/plugins/kk/skills/xhs-images/references/card-layouts.md +35 -0
  39. package/plugins/kk/workflows/kk-daily-ai-voice.yaml +162 -11
  40. package/plugins/publishings/emdash-pub/dist/index.js +94 -45
  41. package/plugins/publishings/infoq-pub/dist/index.js +94 -45
  42. package/plugins/publishings/juejin-pub/dist/index.js +94 -45
  43. package/plugins/publishings/medium-pub/dist/index.js +94 -45
  44. package/plugins/publishings/podcast-pub/dist/index.js +115 -55
  45. package/plugins/publishings/podcast-pub/src/map.ts +30 -10
  46. package/plugins/publishings/podcast-pub/src/show-notes.ts +6 -1
  47. package/plugins/publishings/qiita-pub/dist/index.js +94 -45
  48. package/plugins/publishings/substack-pub/dist/index.js +94 -45
  49. package/plugins/publishings/surfdash-pub/dist/index.js +99 -63
  50. package/plugins/publishings/surfdash-pub/src/index.ts +10 -1
  51. package/plugins/publishings/wechatmp-pub/dist/index.js +94 -45
  52. package/plugins/publishings/x-pub/dist/index.js +94 -45
  53. package/plugins/publishings/xhs-pub/dist/index.js +8908 -229
  54. package/plugins/publishings/xhs-pub/package.json +1 -0
  55. package/plugins/publishings/xhs-pub/plugin.json +1 -1
  56. package/plugins/publishings/xhs-pub/src/automation-guard.ts +128 -0
  57. package/plugins/publishings/xhs-pub/src/index.ts +753 -24
  58. package/plugins/publishings/xhs-pub/src/profile-check.ts +133 -0
  59. package/plugins/publishings/zenn-pub/dist/index.js +94 -45
  60. package/plugins/sp/lib/env.ts +46 -0
  61. package/plugins/sp/lib/inline-run.generated.mjs +1489 -0
  62. package/plugins/sp/scripts/feature-verification-steps.ts +275 -0
  63. package/plugins/sp/scripts/inline-run-setup.ts +571 -47
  64. package/plugins/sp/scripts/wrapup-drift-probe.mjs +190 -0
  65. package/plugins/sp/scripts/wrapup-drift-probe.ts +258 -0
  66. package/plugins/sp/scripts/wrapup-steps.mjs +77 -6
  67. package/plugins/sp/scripts/wrapup-steps.ts +91 -5
@@ -14642,6 +14642,72 @@ var init_zod = __esm(() => {
14642
14642
  init_external();
14643
14643
  });
14644
14644
 
14645
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.11/node_modules/@gobing-ai/ts-utils/dist/errors.js
14646
+ var ErrorCode;
14647
+ var init_errors3 = __esm(() => {
14648
+ ErrorCode = {
14649
+ NotFound: "NOT_FOUND",
14650
+ Validation: "VALIDATION",
14651
+ Conflict: "CONFLICT",
14652
+ Internal: "INTERNAL"
14653
+ };
14654
+ });
14655
+
14656
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.11/node_modules/@gobing-ai/ts-utils/dist/api-response.js
14657
+ var API_ERROR_CODES, ERROR_CODE_TO_HTTP, CLIENT_SAFE_CODES;
14658
+ var init_api_response = __esm(() => {
14659
+ init_errors3();
14660
+ API_ERROR_CODES = {
14661
+ SUCCESS: 0,
14662
+ NOT_FOUND: 404,
14663
+ VALIDATION_ERROR: 422,
14664
+ BAD_REQUEST: 400,
14665
+ UNAUTHORIZED: 401,
14666
+ FORBIDDEN: 403,
14667
+ CONFLICT: 409,
14668
+ INTERNAL_ERROR: 500
14669
+ };
14670
+ ERROR_CODE_TO_HTTP = {
14671
+ [ErrorCode.NotFound]: API_ERROR_CODES.NOT_FOUND,
14672
+ [ErrorCode.Validation]: API_ERROR_CODES.VALIDATION_ERROR,
14673
+ [ErrorCode.Conflict]: API_ERROR_CODES.CONFLICT,
14674
+ [ErrorCode.Internal]: API_ERROR_CODES.INTERNAL_ERROR
14675
+ };
14676
+ CLIENT_SAFE_CODES = new Set([ErrorCode.NotFound, ErrorCode.Validation, ErrorCode.Conflict]);
14677
+ });
14678
+
14679
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.11/node_modules/@gobing-ai/ts-utils/dist/cursor.js
14680
+ var init_cursor = () => {};
14681
+
14682
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.11/node_modules/@gobing-ai/ts-utils/dist/event-severity.js
14683
+ var init_event_severity = () => {};
14684
+
14685
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.11/node_modules/@gobing-ai/ts-utils/dist/output.js
14686
+ function processStream(name) {
14687
+ const proc = globalThis.process;
14688
+ const stream = proc?.[name];
14689
+ if (stream === undefined) {
14690
+ throw new Error(`No ${name} target available: set one via setDefaultOutputTargets or pass an explicit target`);
14691
+ }
14692
+ return stream;
14693
+ }
14694
+ function writeLine(message, target) {
14695
+ target.write(`${message}
14696
+ `);
14697
+ }
14698
+ function echoError(message, target = defaultStderrTarget ?? processStream("stderr")) {
14699
+ writeLine(message, target);
14700
+ }
14701
+ var defaultStderrTarget;
14702
+
14703
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.11/node_modules/@gobing-ai/ts-utils/dist/index.js
14704
+ var init_dist = __esm(() => {
14705
+ init_api_response();
14706
+ init_cursor();
14707
+ init_errors3();
14708
+ init_event_severity();
14709
+ });
14710
+
14645
14711
  // ../../node_modules/.bun/yaml@2.9.0/node_modules/yaml/dist/nodes/identity.js
14646
14712
  var require_identity = __commonJS((exports) => {
14647
14713
  var ALIAS = Symbol.for("yaml.alias");
@@ -17546,15 +17612,15 @@ var require_timestamp = __commonJS((exports) => {
17546
17612
  throw new Error("!!timestamp expects a date, starting with yyyy-mm-dd");
17547
17613
  const [, year, month, day, hour, minute, second] = match.map(Number);
17548
17614
  const millisec = match[7] ? Number((match[7] + "00").substr(1, 3)) : 0;
17549
- let date5 = Date.UTC(year, month - 1, day, hour || 0, minute || 0, second || 0, millisec);
17615
+ let date6 = Date.UTC(year, month - 1, day, hour || 0, minute || 0, second || 0, millisec);
17550
17616
  const tz = match[8];
17551
17617
  if (tz && tz !== "Z") {
17552
17618
  let d = parseSexagesimal(tz, false);
17553
17619
  if (Math.abs(d) < 30)
17554
17620
  d *= 60;
17555
- date5 -= 60000 * d;
17621
+ date6 -= 60000 * d;
17556
17622
  }
17557
- return new Date(date5);
17623
+ return new Date(date6);
17558
17624
  },
17559
17625
  stringify: ({ value }) => value?.toISOString().replace(/(T00:00:00)?\.000Z$/, "") ?? ""
17560
17626
  };
@@ -19414,7 +19480,7 @@ var require_composer = __commonJS((exports) => {
19414
19480
  var node_process = __require("process");
19415
19481
  var directives = require_directives();
19416
19482
  var Document = require_Document();
19417
- var errors3 = require_errors();
19483
+ var errors4 = require_errors();
19418
19484
  var identity = require_identity();
19419
19485
  var composeDoc = require_compose_doc();
19420
19486
  var resolveEnd = require_resolve_end();
@@ -19465,9 +19531,9 @@ var require_composer = __commonJS((exports) => {
19465
19531
  this.onError = (source, code, message, warning) => {
19466
19532
  const pos = getErrorPos(source);
19467
19533
  if (warning)
19468
- this.warnings.push(new errors3.YAMLWarning(pos, code, message));
19534
+ this.warnings.push(new errors4.YAMLWarning(pos, code, message));
19469
19535
  else
19470
- this.errors.push(new errors3.YAMLParseError(pos, code, message));
19536
+ this.errors.push(new errors4.YAMLParseError(pos, code, message));
19471
19537
  };
19472
19538
  this.directives = new directives.Directives({ version: options.version || "1.2" });
19473
19539
  this.options = options;
@@ -19553,7 +19619,7 @@ ${cb}` : comment;
19553
19619
  break;
19554
19620
  case "error": {
19555
19621
  const msg = token.source ? `${token.message}: ${JSON.stringify(token.source)}` : token.message;
19556
- const error51 = new errors3.YAMLParseError(getErrorPos(token), "UNEXPECTED_TOKEN", msg);
19622
+ const error51 = new errors4.YAMLParseError(getErrorPos(token), "UNEXPECTED_TOKEN", msg);
19557
19623
  if (this.atDirectives || !this.doc)
19558
19624
  this.errors.push(error51);
19559
19625
  else
@@ -19563,7 +19629,7 @@ ${cb}` : comment;
19563
19629
  case "doc-end": {
19564
19630
  if (!this.doc) {
19565
19631
  const msg = "Unexpected doc-end without preceding document";
19566
- this.errors.push(new errors3.YAMLParseError(getErrorPos(token), "UNEXPECTED_TOKEN", msg));
19632
+ this.errors.push(new errors4.YAMLParseError(getErrorPos(token), "UNEXPECTED_TOKEN", msg));
19567
19633
  break;
19568
19634
  }
19569
19635
  this.doc.directives.docEnd = true;
@@ -19578,7 +19644,7 @@ ${end.comment}` : end.comment;
19578
19644
  break;
19579
19645
  }
19580
19646
  default:
19581
- this.errors.push(new errors3.YAMLParseError(getErrorPos(token), "UNEXPECTED_TOKEN", `Unsupported token ${token.type}`));
19647
+ this.errors.push(new errors4.YAMLParseError(getErrorPos(token), "UNEXPECTED_TOKEN", `Unsupported token ${token.type}`));
19582
19648
  }
19583
19649
  }
19584
19650
  *end(forceDoc = false, endOffset = -1) {
@@ -19604,7 +19670,7 @@ ${end.comment}` : end.comment;
19604
19670
  var require_cst_scalar = __commonJS((exports) => {
19605
19671
  var resolveBlockScalar = require_resolve_block_scalar();
19606
19672
  var resolveFlowScalar = require_resolve_flow_scalar();
19607
- var errors3 = require_errors();
19673
+ var errors4 = require_errors();
19608
19674
  var stringifyString = require_stringifyString();
19609
19675
  function resolveAsScalar(token, strict = true, onError) {
19610
19676
  if (token) {
@@ -19613,7 +19679,7 @@ var require_cst_scalar = __commonJS((exports) => {
19613
19679
  if (onError)
19614
19680
  onError(offset, code, message);
19615
19681
  else
19616
- throw new errors3.YAMLParseError([offset, offset + 1], code, message);
19682
+ throw new errors4.YAMLParseError([offset, offset + 1], code, message);
19617
19683
  };
19618
19684
  switch (token.type) {
19619
19685
  case "scalar":
@@ -21493,7 +21559,7 @@ var require_parser = __commonJS((exports) => {
21493
21559
  var require_public_api = __commonJS((exports) => {
21494
21560
  var composer = require_composer();
21495
21561
  var Document = require_Document();
21496
- var errors3 = require_errors();
21562
+ var errors4 = require_errors();
21497
21563
  var log = require_log();
21498
21564
  var identity = require_identity();
21499
21565
  var lineCounter = require_line_counter();
@@ -21510,8 +21576,8 @@ var require_public_api = __commonJS((exports) => {
21510
21576
  const docs = Array.from(composer$1.compose(parser$1.parse(source)));
21511
21577
  if (prettyErrors && lineCounter2)
21512
21578
  for (const doc2 of docs) {
21513
- doc2.errors.forEach(errors3.prettifyError(source, lineCounter2));
21514
- doc2.warnings.forEach(errors3.prettifyError(source, lineCounter2));
21579
+ doc2.errors.forEach(errors4.prettifyError(source, lineCounter2));
21580
+ doc2.warnings.forEach(errors4.prettifyError(source, lineCounter2));
21515
21581
  }
21516
21582
  if (docs.length > 0)
21517
21583
  return docs;
@@ -21526,13 +21592,13 @@ var require_public_api = __commonJS((exports) => {
21526
21592
  if (!doc2)
21527
21593
  doc2 = _doc;
21528
21594
  else if (doc2.options.logLevel !== "silent") {
21529
- doc2.errors.push(new errors3.YAMLParseError(_doc.range.slice(0, 2), "MULTIPLE_DOCS", "Source contains multiple documents; please use YAML.parseAllDocuments()"));
21595
+ doc2.errors.push(new errors4.YAMLParseError(_doc.range.slice(0, 2), "MULTIPLE_DOCS", "Source contains multiple documents; please use YAML.parseAllDocuments()"));
21530
21596
  break;
21531
21597
  }
21532
21598
  }
21533
21599
  if (prettyErrors && lineCounter2) {
21534
- doc2.errors.forEach(errors3.prettifyError(source, lineCounter2));
21535
- doc2.warnings.forEach(errors3.prettifyError(source, lineCounter2));
21600
+ doc2.errors.forEach(errors4.prettifyError(source, lineCounter2));
21601
+ doc2.warnings.forEach(errors4.prettifyError(source, lineCounter2));
21536
21602
  }
21537
21603
  return doc2;
21538
21604
  }
@@ -21584,12 +21650,12 @@ var require_public_api = __commonJS((exports) => {
21584
21650
  });
21585
21651
 
21586
21652
  // ../../node_modules/.bun/yaml@2.9.0/node_modules/yaml/dist/index.js
21587
- var composer, Document, Schema, errors3, Alias, identity, Pair, Scalar, YAMLMap, YAMLSeq, cst, lexer, lineCounter, parser, publicApi, visit, $Composer, $Document, $Schema, $YAMLError, $YAMLParseError, $YAMLWarning, $Alias, $isAlias, $isCollection, $isDocument, $isMap, $isNode, $isPair, $isScalar, $isSeq, $Pair, $Scalar, $YAMLMap, $YAMLSeq, $Lexer, $LineCounter, $Parser, $parse, $parseAllDocuments, $parseDocument, $stringify, $visit, $visitAsync;
21588
- var init_dist = __esm(() => {
21653
+ var composer, Document, Schema, errors4, Alias, identity, Pair, Scalar, YAMLMap, YAMLSeq, cst, lexer, lineCounter, parser, publicApi, visit, $Composer, $Document, $Schema, $YAMLError, $YAMLParseError, $YAMLWarning, $Alias, $isAlias, $isCollection, $isDocument, $isMap, $isNode, $isPair, $isScalar, $isSeq, $Pair, $Scalar, $YAMLMap, $YAMLSeq, $Lexer, $LineCounter, $Parser, $parse, $parseAllDocuments, $parseDocument, $stringify, $visit, $visitAsync;
21654
+ var init_dist2 = __esm(() => {
21589
21655
  composer = require_composer();
21590
21656
  Document = require_Document();
21591
21657
  Schema = require_Schema();
21592
- errors3 = require_errors();
21658
+ errors4 = require_errors();
21593
21659
  Alias = require_Alias();
21594
21660
  identity = require_identity();
21595
21661
  Pair = require_Pair();
@@ -21605,9 +21671,9 @@ var init_dist = __esm(() => {
21605
21671
  $Composer = composer.Composer;
21606
21672
  $Document = Document.Document;
21607
21673
  $Schema = Schema.Schema;
21608
- $YAMLError = errors3.YAMLError;
21609
- $YAMLParseError = errors3.YAMLParseError;
21610
- $YAMLWarning = errors3.YAMLWarning;
21674
+ $YAMLError = errors4.YAMLError;
21675
+ $YAMLParseError = errors4.YAMLParseError;
21676
+ $YAMLWarning = errors4.YAMLWarning;
21611
21677
  $Alias = Alias.Alias;
21612
21678
  $isAlias = identity.isAlias;
21613
21679
  $isCollection = identity.isCollection;
@@ -21632,10 +21698,10 @@ var init_dist = __esm(() => {
21632
21698
  $visitAsync = visit.visitAsync;
21633
21699
  });
21634
21700
 
21635
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.39/node_modules/@gobing-ai/ts-runtime/dist/config.js
21701
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.11/node_modules/@gobing-ai/ts-runtime/dist/config.js
21636
21702
  var configSchema;
21637
21703
  var init_config = __esm(() => {
21638
- init_dist();
21704
+ init_dist2();
21639
21705
  init_zod();
21640
21706
  configSchema = exports_external.object({
21641
21707
  app: exports_external.object({
@@ -21656,7 +21722,7 @@ var init_config = __esm(() => {
21656
21722
  });
21657
21723
  });
21658
21724
 
21659
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.39/node_modules/@gobing-ai/ts-runtime/dist/file-system-node.js
21725
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.11/node_modules/@gobing-ai/ts-runtime/dist/file-system-node.js
21660
21726
  import { appendFileSync, cpSync, createReadStream, createWriteStream, existsSync, mkdirSync, readdirSync, readFileSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "fs";
21661
21727
  import { dirname, resolve as resolvePath } from "path";
21662
21728
  function createNodeFileSystem(root, paths) {
@@ -21834,30 +21900,15 @@ var PluginManifestSchema = exports_external.looseObject({
21834
21900
  description: exports_external.string().optional(),
21835
21901
  operations: exports_external.record(exports_external.string(), PluginOperationSchema).optional()
21836
21902
  });
21837
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.39/node_modules/@gobing-ai/ts-runtime/dist/index.js
21903
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.11/node_modules/@gobing-ai/ts-runtime/dist/index.js
21838
21904
  init_file_system_node();
21839
21905
  init_config();
21840
21906
 
21841
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.4.67/node_modules/@gobing-ai/ts-utils/dist/output.js
21842
- var defaultStderrTarget;
21843
- function processStream(name) {
21844
- const proc = globalThis.process;
21845
- const stream = proc?.[name];
21846
- if (stream === undefined) {
21847
- throw new Error(`No ${name} target available: set one via setDefaultOutputTargets or pass an explicit target`);
21848
- }
21849
- return stream;
21850
- }
21851
- function writeLine(message, target) {
21852
- target.write(`${message}
21853
- `);
21854
- }
21855
- function echoError(message, target = defaultStderrTarget ?? processStream("stderr")) {
21856
- writeLine(message, target);
21857
- }
21858
-
21859
21907
  // ../../packages/kk-core/src/render-md.ts
21860
21908
  if (false) {}
21909
+ // ../../plugins/generations/image-gen/src/index.ts
21910
+ init_dist();
21911
+
21861
21912
  // ../../plugins/generations/image-gen/src/bytes.ts
21862
21913
  import { readFile, writeFile } from "fs/promises";
21863
21914
  async function writeBytes(path2, bytes) {
@@ -21877,6 +21928,7 @@ var ImageJobSpecSchema = exports_external.strictObject({
21877
21928
  vars: exports_external.record(exports_external.string(), exports_external.string()).optional(),
21878
21929
  extra: exports_external.string().optional(),
21879
21930
  provider: exports_external.string().optional(),
21931
+ fallback: exports_external.union([exports_external.literal(true), exports_external.array(exports_external.string().min(1)).min(1)]).optional(),
21880
21932
  model: exports_external.string().optional(),
21881
21933
  referenceImages: exports_external.array(exports_external.string()).optional(),
21882
21934
  count: exports_external.number().int().positive().optional(),
@@ -22011,22 +22063,22 @@ function resolvePlaceholder(expr, vars, formatName) {
22011
22063
  }
22012
22064
  function renderTemplate(template, vars, formatName) {
22013
22065
  let rendered = "";
22014
- let cursor = 0;
22015
- while (cursor < template.length) {
22016
- const start = template.indexOf("{{", cursor);
22066
+ let cursor2 = 0;
22067
+ while (cursor2 < template.length) {
22068
+ const start = template.indexOf("{{", cursor2);
22017
22069
  if (start === -1) {
22018
- rendered += template.slice(cursor);
22070
+ rendered += template.slice(cursor2);
22019
22071
  break;
22020
22072
  }
22021
22073
  const match = matchPlaceholder(template, start);
22022
22074
  if (match === undefined) {
22023
- rendered += template.slice(cursor, start + 2);
22024
- cursor = start + 2;
22075
+ rendered += template.slice(cursor2, start + 2);
22076
+ cursor2 = start + 2;
22025
22077
  continue;
22026
22078
  }
22027
- rendered += template.slice(cursor, start);
22079
+ rendered += template.slice(cursor2, start);
22028
22080
  rendered += resolvePlaceholder(match.expr, vars, formatName);
22029
- cursor = match.end;
22081
+ cursor2 = match.end;
22030
22082
  }
22031
22083
  return rendered;
22032
22084
  }
@@ -22151,8 +22203,8 @@ function extensionFromUrl(url2) {
22151
22203
  var createSeedream = (options) => {
22152
22204
  const fetchFn = options?.fetch ?? fetch;
22153
22205
  const timeoutMs = options?.timeoutMs ?? PROVIDER_REQUEST_TIMEOUT_MS;
22154
- const env = options?.env ?? process.env;
22155
- const readEnv = (key) => env[key] ?? "";
22206
+ const env2 = options?.env ?? process.env;
22207
+ const readEnv = (key) => env2[key] ?? "";
22156
22208
  const supportsRef = (model) => REF_MODEL_FRAGMENTS.some((fragment) => model.includes(fragment));
22157
22209
  return {
22158
22210
  name: "seedream",
@@ -22288,8 +22340,8 @@ async function extractImageFromResponse(result, fetchFn = fetch, timeoutMs = PRO
22288
22340
  var createAgnes = (options) => {
22289
22341
  const fetchFn = options?.fetch ?? fetch;
22290
22342
  const timeoutMs = options?.timeoutMs ?? PROVIDER_REQUEST_TIMEOUT_MS;
22291
- const env = options?.env ?? process.env;
22292
- const readEnv = (key) => env[key] ?? "";
22343
+ const env2 = options?.env ?? process.env;
22344
+ const readEnv = (key) => env2[key] ?? "";
22293
22345
  return {
22294
22346
  name: "agnes",
22295
22347
  defaultModel: () => DEFAULT_MODEL2,
@@ -22524,8 +22576,8 @@ async function extractImageFromResponse2(result, fetchFn = fetch, timeoutMs = PR
22524
22576
  var createOpenai = (options) => {
22525
22577
  const fetchFn = options?.fetch ?? fetch;
22526
22578
  const timeoutMs = options?.timeoutMs ?? PROVIDER_REQUEST_TIMEOUT_MS;
22527
- const env = options?.env ?? process.env;
22528
- const readEnv = (key) => env[key] ?? "";
22579
+ const env2 = options?.env ?? process.env;
22580
+ const readEnv = (key) => env2[key] ?? "";
22529
22581
  const supportsRef = (model) => model.includes("gpt-image");
22530
22582
  return {
22531
22583
  name: "openai",
@@ -22633,22 +22685,22 @@ function parseAzureBaseURL(url2) {
22633
22685
  parsed.pathname = trimmedPath.endsWith("/openai") ? trimmedPath : `${trimmedPath}/openai`;
22634
22686
  return { resourceBaseURL: parsed.toString().replace(/\/+$/, ""), deployment: null };
22635
22687
  }
22636
- function azureEndpoint(env) {
22637
- const url2 = env.AZURE_OPENAI_BASE_URL ?? "";
22688
+ function azureEndpoint(env2) {
22689
+ const url2 = env2.AZURE_OPENAI_BASE_URL ?? "";
22638
22690
  if (url2 === "") {
22639
22691
  throw new Error("AZURE_OPENAI_BASE_URL is required. Set it to your Azure resource or deployment endpoint, e.g.: https://your-resource.openai.azure.com or https://your-resource.openai.azure.com/openai/deployments/your-deployment");
22640
22692
  }
22641
22693
  return parseAzureBaseURL(url2);
22642
22694
  }
22643
- function getApiKey(env) {
22644
- const key = env.AZURE_OPENAI_API_KEY ?? "";
22695
+ function getApiKey(env2) {
22696
+ const key = env2.AZURE_OPENAI_API_KEY ?? "";
22645
22697
  if (key === "") {
22646
22698
  throw new Error("AZURE_OPENAI_API_KEY is required. Get it from Azure Portal \u2192 your OpenAI resource \u2192 Keys and Endpoint.");
22647
22699
  }
22648
22700
  return key;
22649
22701
  }
22650
- function buildURL(endpoint, deployment, pathSuffix, env) {
22651
- const apiVersion = env.AZURE_API_VERSION ?? DEFAULT_AZURE_API_VERSION;
22702
+ function buildURL(endpoint, deployment, pathSuffix, env2) {
22703
+ const apiVersion = env2.AZURE_API_VERSION ?? DEFAULT_AZURE_API_VERSION;
22652
22704
  return `${endpoint.resourceBaseURL}/deployments/${encodeURIComponent(deployment)}${pathSuffix}?api-version=${apiVersion}`;
22653
22705
  }
22654
22706
  function getAzureQuality(quality) {
@@ -22664,12 +22716,12 @@ function validateReferenceImages(referenceImages) {
22664
22716
  var createAzure = (options) => {
22665
22717
  const fetchFn = options?.fetch ?? fetch;
22666
22718
  const timeoutMs = options?.timeoutMs ?? PROVIDER_REQUEST_TIMEOUT_MS;
22667
- const env = options?.env ?? process.env;
22719
+ const env2 = options?.env ?? process.env;
22668
22720
  function defaultModel() {
22669
- const explicit = env.AZURE_OPENAI_DEPLOYMENT?.trim();
22721
+ const explicit = env2.AZURE_OPENAI_DEPLOYMENT?.trim();
22670
22722
  if (explicit !== undefined && explicit !== "")
22671
22723
  return explicit;
22672
- const baseURL = env.AZURE_OPENAI_BASE_URL;
22724
+ const baseURL = env2.AZURE_OPENAI_BASE_URL;
22673
22725
  if (baseURL !== undefined) {
22674
22726
  try {
22675
22727
  const { deployment } = parseAzureBaseURL(baseURL);
@@ -22683,14 +22735,14 @@ var createAzure = (options) => {
22683
22735
  return {
22684
22736
  name: "azure",
22685
22737
  defaultModel,
22686
- isAvailable: () => (env.AZURE_OPENAI_API_KEY ?? "") !== "",
22738
+ isAvailable: () => (env2.AZURE_OPENAI_API_KEY ?? "") !== "",
22687
22739
  supportsReferenceImages: supportsRef,
22688
22740
  validate(req) {
22689
22741
  validateReferenceImages(req.referenceImages ?? []);
22690
22742
  },
22691
22743
  async generate(req) {
22692
- const apiKey = getApiKey(env);
22693
- const endpoint = azureEndpoint(env);
22744
+ const apiKey = getApiKey(env2);
22745
+ const endpoint = azureEndpoint(env2);
22694
22746
  const deployment = req.model.trim();
22695
22747
  if (deployment === "") {
22696
22748
  throw new Error("Azure deployment name is required. Use --model <deployment>, AZURE_OPENAI_DEPLOYMENT, AZURE_OPENAI_IMAGE_MODEL, or embed the deployment in AZURE_OPENAI_BASE_URL.");
@@ -22710,7 +22762,7 @@ var createAzure = (options) => {
22710
22762
  const mimeType = extname3(filename).toLowerCase() === ".png" ? "image/png" : "image/jpeg";
22711
22763
  form.append("image[]", new Blob([fileBytes], { type: mimeType }), filename);
22712
22764
  }
22713
- const res2 = await fetchFn(buildURL(endpoint, deployment, "/images/edits", env), {
22765
+ const res2 = await fetchFn(buildURL(endpoint, deployment, "/images/edits", env2), {
22714
22766
  method: "POST",
22715
22767
  headers: { "api-key": apiKey },
22716
22768
  body: form,
@@ -22720,7 +22772,7 @@ var createAzure = (options) => {
22720
22772
  throw new Error(`Azure OpenAI edits API error: ${await res2.text()}`);
22721
22773
  return extractImageFromResponse2(await res2.json(), fetchFn, timeoutMs);
22722
22774
  }
22723
- const res = await fetchFn(buildURL(endpoint, deployment, "/images/generations", env), {
22775
+ const res = await fetchFn(buildURL(endpoint, deployment, "/images/generations", env2), {
22724
22776
  method: "POST",
22725
22777
  headers: { "content-type": "application/json", "api-key": apiKey },
22726
22778
  body: JSON.stringify({ prompt: req.prompt, size, n: 1, quality: getAzureQuality(req.quality) }),
@@ -22738,13 +22790,13 @@ var createAzure = (options) => {
22738
22790
  // ../../plugins/generations/image-gen/src/providers/codex-cli.ts
22739
22791
  import { spawn } from "child_process";
22740
22792
  import { randomBytes } from "crypto";
22741
- import { access, mkdir, rm, writeFile as writeFile2 } from "fs/promises";
22793
+ import { access as access2, mkdir, rm, writeFile as writeFile2 } from "fs/promises";
22742
22794
  import { tmpdir } from "os";
22743
22795
  import { resolve as resolve2 } from "path";
22744
22796
  var DEFAULT_MODEL4 = "codex-image-gen";
22745
22797
  async function exists(filePath) {
22746
22798
  try {
22747
- await access(filePath);
22799
+ await access2(filePath);
22748
22800
  return true;
22749
22801
  } catch {
22750
22802
  return false;
@@ -22797,8 +22849,8 @@ function parsePositiveInt(value) {
22797
22849
  return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
22798
22850
  }
22799
22851
  var createCodexCli = (options) => {
22800
- const env = options?.env ?? process.env;
22801
- const readEnv = (key) => env[key] ?? "";
22852
+ const env2 = options?.env ?? process.env;
22853
+ const readEnv = (key) => env2[key] ?? "";
22802
22854
  return {
22803
22855
  name: "codex-cli",
22804
22856
  defaultModel: () => DEFAULT_MODEL4,
@@ -22859,6 +22911,7 @@ var createCodexCli = (options) => {
22859
22911
  };
22860
22912
 
22861
22913
  // ../../plugins/generations/image-gen/src/providers/dashscope.ts
22914
+ init_dist();
22862
22915
  import { Buffer as Buffer5 } from "buffer";
22863
22916
  var DEFAULT_MODEL5 = "qwen-image-2.0-pro";
22864
22917
  var MIN_QWEN_2_TOTAL_PIXELS = 512 * 512;
@@ -23190,8 +23243,8 @@ async function extractImageFromResponse3(result, fetchFn, timeoutMs = PROVIDER_R
23190
23243
  var createDashscope = (options) => {
23191
23244
  const fetchFn = options?.fetch ?? fetch;
23192
23245
  const timeoutMs = options?.timeoutMs ?? PROVIDER_REQUEST_TIMEOUT_MS;
23193
- const env = options?.env ?? process.env;
23194
- const readEnv = (key) => env[key] ?? "";
23246
+ const env2 = options?.env ?? process.env;
23247
+ const readEnv = (key) => env2[key] ?? "";
23195
23248
  const supportsRef = (model) => model.includes("wan2.7");
23196
23249
  return {
23197
23250
  name: "dashscope",
@@ -23343,8 +23396,8 @@ function proxyPassword(proxy) {
23343
23396
  var createGoogle = (options) => {
23344
23397
  const fetchFn = options?.fetch ?? fetch;
23345
23398
  const timeoutMs = options?.timeoutMs ?? PROVIDER_REQUEST_TIMEOUT_MS;
23346
- const env = options?.env ?? process.env;
23347
- const readEnv = (key) => env[key] ?? "";
23399
+ const env2 = options?.env ?? process.env;
23400
+ const readEnv = (key) => env2[key] ?? "";
23348
23401
  const refModels = [
23349
23402
  "gemini-3-pro-image",
23350
23403
  "gemini-3.1-flash-image",
@@ -23490,8 +23543,8 @@ var buildPayload = (req) => ({
23490
23543
  var createHuggingface = (options) => {
23491
23544
  const fetchFn = options?.fetch ?? fetch;
23492
23545
  const timeoutMs = options?.timeoutMs ?? PROVIDER_REQUEST_TIMEOUT_MS;
23493
- const env = options?.env ?? process.env;
23494
- const readEnv = (key) => env[key] ?? "";
23546
+ const env2 = options?.env ?? process.env;
23547
+ const readEnv = (key) => env2[key] ?? "";
23495
23548
  return {
23496
23549
  name: "huggingface",
23497
23550
  defaultModel: () => readEnv("HUGGINGFACE_MODEL") || DEFAULT_MODEL7,
@@ -23619,8 +23672,8 @@ function timestampHeader() {
23619
23672
  var createJimeng = (options) => {
23620
23673
  const fetchFn = options?.fetch ?? fetch;
23621
23674
  const timeoutMs = options?.timeoutMs ?? PROVIDER_REQUEST_TIMEOUT_MS;
23622
- const env = options?.env ?? process.env;
23623
- const readEnv = (key) => env[key] ?? "";
23675
+ const env2 = options?.env ?? process.env;
23676
+ const readEnv = (key) => env2[key] ?? "";
23624
23677
  async function signedPost(query, body, accessKey, secretKey, region) {
23625
23678
  const base = readEnv("JIMENG_BASE_URL") || "https://visual.volcengineapi.com";
23626
23679
  const endpoint = resolveEndpoint(base, query);
@@ -23791,8 +23844,8 @@ async function extractImageFromResponse4(result, fetchFn = fetch, timeoutMs = PR
23791
23844
  var createMinimax = (options) => {
23792
23845
  const fetchFn = options?.fetch ?? fetch;
23793
23846
  const timeoutMs = options?.timeoutMs ?? PROVIDER_REQUEST_TIMEOUT_MS;
23794
- const env = options?.env ?? process.env;
23795
- const readEnv = (key) => env[key] ?? "";
23847
+ const env2 = options?.env ?? process.env;
23848
+ const readEnv = (key) => env2[key] ?? "";
23796
23849
  return {
23797
23850
  name: "minimax",
23798
23851
  defaultModel: () => DEFAULT_MODEL9,
@@ -24003,8 +24056,8 @@ function buildRequestBody2(prompt, model, req, referenceImages) {
24003
24056
  var createOpenrouter = (options) => {
24004
24057
  const fetchFn = options?.fetch ?? fetch;
24005
24058
  const timeoutMs = options?.timeoutMs ?? PROVIDER_REQUEST_TIMEOUT_MS;
24006
- const env = options?.env ?? process.env;
24007
- const readEnv = (key) => env[key] ?? "";
24059
+ const env2 = options?.env ?? process.env;
24060
+ const readEnv = (key) => env2[key] ?? "";
24008
24061
  return {
24009
24062
  name: "openrouter",
24010
24063
  defaultModel: () => DEFAULT_MODEL10,
@@ -24191,29 +24244,29 @@ function buildInput(req) {
24191
24244
  return { prompt: req.prompt };
24192
24245
  }
24193
24246
  function extractOutputUrl(prediction) {
24194
- const output = prediction.output;
24195
- if (typeof output === "string")
24196
- return output;
24197
- if (Array.isArray(output)) {
24198
- if (output.length !== 1) {
24199
- throw new Error(`Replicate returned ${output.length} outputs, but kk image-gen currently supports saving exactly one image per request.`);
24200
- }
24201
- const first = output[0];
24247
+ const output2 = prediction.output;
24248
+ if (typeof output2 === "string")
24249
+ return output2;
24250
+ if (Array.isArray(output2)) {
24251
+ if (output2.length !== 1) {
24252
+ throw new Error(`Replicate returned ${output2.length} outputs, but kk image-gen currently supports saving exactly one image per request.`);
24253
+ }
24254
+ const first = output2[0];
24202
24255
  if (typeof first === "string")
24203
24256
  return first;
24204
24257
  }
24205
- if (output !== null && typeof output === "object" && "url" in output) {
24206
- const url2 = output.url;
24258
+ if (output2 !== null && typeof output2 === "object" && "url" in output2) {
24259
+ const url2 = output2.url;
24207
24260
  if (typeof url2 === "string")
24208
24261
  return url2;
24209
24262
  }
24210
- throw new Error(`Unexpected Replicate output format: ${JSON.stringify(output)}`);
24263
+ throw new Error(`Unexpected Replicate output format: ${JSON.stringify(output2)}`);
24211
24264
  }
24212
24265
  var createReplicate = (options) => {
24213
24266
  const fetchFn = options?.fetch ?? fetch;
24214
- const env = options?.env ?? process.env;
24267
+ const env2 = options?.env ?? process.env;
24215
24268
  const timeoutMs = options?.timeoutMs ?? PROVIDER_REQUEST_TIMEOUT_MS;
24216
- const readEnv = (key) => env[key] ?? "";
24269
+ const readEnv = (key) => env2[key] ?? "";
24217
24270
  async function downloadImage2(url2) {
24218
24271
  const res = await fetchFn(url2, { signal: AbortSignal.timeout(timeoutMs) });
24219
24272
  if (!res.ok)
@@ -24430,8 +24483,8 @@ function resolveSizeForModel2(model, args) {
24430
24483
  var createZai = (options) => {
24431
24484
  const fetchFn = options?.fetch ?? fetch;
24432
24485
  const timeoutMs = options?.timeoutMs ?? PROVIDER_REQUEST_TIMEOUT_MS;
24433
- const env = options?.env ?? process.env;
24434
- const readEnv = (key) => env[key] ?? "";
24486
+ const env2 = options?.env ?? process.env;
24487
+ const readEnv = (key) => env2[key] ?? "";
24435
24488
  return {
24436
24489
  name: "zai",
24437
24490
  defaultModel: () => DEFAULT_MODEL12,
@@ -24485,6 +24538,48 @@ var createZai = (options) => {
24485
24538
  };
24486
24539
  };
24487
24540
 
24541
+ // ../../plugins/generations/image-gen/src/providers/errors.ts
24542
+ var POLICY_RE = /content[_ -]?policy|moderation|safety|sensitive|inappropriate|violat|blocked/i;
24543
+ var AUTH_RE = /api[_ -]?key|unauthori[sz]ed|authenticat|forbidden|requires [A-Z_]+|is required/i;
24544
+ var QUOTA_RE = /quota|rate[_ -]?limit|insufficient|balance|billing|exceeded|too many requests/i;
24545
+ var TRANSIENT_RE = /timed? ?out|ECONNRESET|ETIMEDOUT|ECONNREFUSED|fetch failed|socket|model loading/i;
24546
+ var TRANSIENT_NAMES = new Set(["TimeoutError", "AbortError"]);
24547
+ function statusesIn(message) {
24548
+ const statuses = [];
24549
+ for (const match of message.matchAll(/\((\d{3})\)|HTTP\s+(\d{3})\b|:\s*(\d{3})\s*$/gi)) {
24550
+ const status = match[1] ?? match[2] ?? match[3];
24551
+ if (status !== undefined)
24552
+ statuses.push(Number(status));
24553
+ }
24554
+ return statuses;
24555
+ }
24556
+ function partsOf(err) {
24557
+ if (typeof err !== "object" || err === null)
24558
+ return { name: "", message: "" };
24559
+ const candidate = err;
24560
+ return {
24561
+ name: typeof candidate.name === "string" ? candidate.name : "",
24562
+ message: typeof candidate.message === "string" ? candidate.message : ""
24563
+ };
24564
+ }
24565
+ function classifyProviderError(err) {
24566
+ const parts = partsOf(err);
24567
+ const statuses = statusesIn(parts.message);
24568
+ if (POLICY_RE.test(parts.message))
24569
+ return "policy";
24570
+ if (statuses.some((status) => status === 401 || status === 403) || AUTH_RE.test(parts.message))
24571
+ return "auth";
24572
+ if (statuses.some((status) => status === 402 || status === 429) || QUOTA_RE.test(parts.message))
24573
+ return "quota";
24574
+ if (TRANSIENT_NAMES.has(parts.name) || statuses.some((status) => status === 408 || status >= 500 && status <= 599) || TRANSIENT_RE.test(parts.message)) {
24575
+ return "transient";
24576
+ }
24577
+ return "unknown";
24578
+ }
24579
+ function isFallbackEligible(cls) {
24580
+ return cls !== "policy";
24581
+ }
24582
+
24488
24583
  // ../../plugins/generations/image-gen/src/providers/types.ts
24489
24584
  var IMAGE_GEN_PROVIDER_ENV = "IMAGE_GEN_PROVIDER";
24490
24585
  var NEVER_AUTO = new Set(["codex-cli"]);
@@ -24613,13 +24708,13 @@ function notConfiguredMessage(reg) {
24613
24708
  return `Provider '${reg.name}' is not configured: missing ${envSummary(reg)} (set it in plugins.generations.image-gen.env or process.env)`;
24614
24709
  }
24615
24710
  function selectProvider(requested, options) {
24616
- const env = options?.env ?? process.env;
24711
+ const env2 = options?.env ?? process.env;
24617
24712
  const available = options?.isAvailable ?? ((name) => {
24618
24713
  const reg = PROVIDERS[name];
24619
- return reg?.create({ env }).isAvailable() ?? false;
24714
+ return reg?.create({ env: env2 }).isAvailable() ?? false;
24620
24715
  });
24621
24716
  const names = Object.keys(PROVIDERS).sort();
24622
- const explicit = requested ?? env[IMAGE_GEN_PROVIDER_ENV];
24717
+ const explicit = requested ?? env2[IMAGE_GEN_PROVIDER_ENV];
24623
24718
  if (explicit !== undefined && explicit !== "") {
24624
24719
  const reg = PROVIDERS[explicit];
24625
24720
  if (reg === undefined) {
@@ -24641,6 +24736,40 @@ function selectProvider(requested, options) {
24641
24736
  }).join("; ");
24642
24737
  throw new Error(`No image provider is configured. Credentials wanted \u2014 ${wanted}`);
24643
24738
  }
24739
+ function resolveFallbackOrder(requested, fallback, options) {
24740
+ if (fallback === undefined) {
24741
+ return { order: [requested], skipped: [] };
24742
+ }
24743
+ let candidates;
24744
+ if (fallback === true) {
24745
+ candidates = AUTO_ORDER.filter((name) => !NEVER_AUTO.has(name) && name !== requested);
24746
+ } else {
24747
+ const names = Object.keys(PROVIDERS).sort();
24748
+ const seen = new Set([requested]);
24749
+ const listed = [];
24750
+ for (const name of fallback) {
24751
+ if (PROVIDERS[name] === undefined) {
24752
+ throw new Error(`Unknown fallback provider '${name}'. Valid providers: ${names.join(", ")}`);
24753
+ }
24754
+ if (!seen.has(name)) {
24755
+ seen.add(name);
24756
+ listed.push(name);
24757
+ }
24758
+ }
24759
+ candidates = listed;
24760
+ }
24761
+ const order = [requested];
24762
+ const skipped = [];
24763
+ for (const name of candidates) {
24764
+ const reason = options?.skipReason?.(name);
24765
+ if (reason === undefined) {
24766
+ order.push(name);
24767
+ } else {
24768
+ skipped.push({ provider: name, reason });
24769
+ }
24770
+ }
24771
+ return { order, skipped };
24772
+ }
24644
24773
 
24645
24774
  // ../../plugins/generations/image-gen/src/index.ts
24646
24775
  var EMPTY_CONTENT = {
@@ -24659,6 +24788,13 @@ function defaultProviderResolver(spec) {
24659
24788
  }
24660
24789
  return registration.create();
24661
24790
  }
24791
+ function registeredProvider(name) {
24792
+ const registration = PROVIDERS[name];
24793
+ if (registration === undefined) {
24794
+ throw new Error(`Provider '${name}' was selected but is missing from the registry`);
24795
+ }
24796
+ return registration.create();
24797
+ }
24662
24798
  function resolveMaxImages(spec) {
24663
24799
  if (spec.maxImages !== undefined) {
24664
24800
  return spec.maxImages;
@@ -24705,6 +24841,28 @@ function composePrompts(spec, format, style, doc2, positions) {
24705
24841
  const vars = spec.job === "free" ? { subject: doc2?.body ?? "", ...spec.vars ?? {} } : spec.vars ?? {};
24706
24842
  return [composePrompt(format, style, vars, spec.extra)];
24707
24843
  }
24844
+ function assertAnchorPlan(body, positions, count) {
24845
+ const ranges = [];
24846
+ for (let index = 0;index < count; index++) {
24847
+ const anchor = positions?.[index];
24848
+ if (anchor === undefined) {
24849
+ throw new Error("Illustration anchor missing from metadata.positions");
24850
+ }
24851
+ const found = anchor === "" ? 0 : body.split(anchor).length - 1;
24852
+ if (found !== 1) {
24853
+ throw new Error(`Illustration anchor must occur exactly once in the source body, found ${found}: '${anchor.slice(0, 50)}'`);
24854
+ }
24855
+ const start = body.indexOf(anchor);
24856
+ ranges.push({ anchor, start, end: start + anchor.length });
24857
+ }
24858
+ for (const [i, a] of ranges.entries()) {
24859
+ for (const b of ranges.slice(i + 1)) {
24860
+ if (a.start < b.end && b.start < a.end) {
24861
+ throw new Error(`Illustration anchors overlap in the source body: '${a.anchor.slice(0, 50)}' and '${b.anchor.slice(0, 50)}'`);
24862
+ }
24863
+ }
24864
+ }
24865
+ }
24708
24866
  async function processGeneratorIO(inputPath, outputPath, options = {}) {
24709
24867
  const fs2 = createNodeFileSystem();
24710
24868
  await fs2.deleteFile(outputPath);
@@ -24731,8 +24889,34 @@ async function processGeneratorIO(inputPath, outputPath, options = {}) {
24731
24889
  if (prompts.length > cap) {
24732
24890
  throw new Error(`Image count ${prompts.length} exceeds the budget cap ${cap} (raise ImageJobSpec.maxImages or KK_IMAGE_MAX_IMAGES)`);
24733
24891
  }
24892
+ if (spec.job === "illustration")
24893
+ assertAnchorPlan(doc2?.body ?? "", positions, prompts.length);
24734
24894
  const resolveProvider = options.providerResolver ?? defaultProviderResolver;
24735
- const provider = resolveProvider(spec);
24895
+ const primary = resolveProvider(spec);
24896
+ const built = new Map;
24897
+ const createCandidate = (name) => {
24898
+ const cached2 = built.get(name);
24899
+ if (cached2 !== undefined) {
24900
+ return cached2;
24901
+ }
24902
+ const created = options.createProvider !== undefined ? options.createProvider(name) : registeredProvider(name);
24903
+ built.set(name, created);
24904
+ return created;
24905
+ };
24906
+ const skipReason = (name) => {
24907
+ const prospect = createCandidate(name);
24908
+ if (!prospect.isAvailable()) {
24909
+ return "not configured";
24910
+ }
24911
+ if (spec.referenceImages !== undefined && spec.referenceImages.length > 0 && !prospect.supportsReferenceImages(prospect.defaultModel())) {
24912
+ return "no reference-image support";
24913
+ }
24914
+ return;
24915
+ };
24916
+ const { order, skipped } = resolveFallbackOrder(primary.name, spec.fallback, { skipReason });
24917
+ for (const skip of skipped) {
24918
+ echoError(`WARN image-gen: skipping fallback ${skip.provider} (${skip.reason})`);
24919
+ }
24736
24920
  if (process.env.KK_IMAGE_DRY_RUN === "1") {
24737
24921
  const metadata2 = {
24738
24922
  generator: "kk:image-gen",
@@ -24760,16 +24944,49 @@ async function processGeneratorIO(inputPath, outputPath, options = {}) {
24760
24944
  const stem = outStemFor(outputPath, spec.outputStem);
24761
24945
  const artifacts = [];
24762
24946
  const captions = [];
24947
+ const attempts = [];
24948
+ let at = 0;
24949
+ const generateWithFallback = async (image, prompt) => {
24950
+ const start = attempts.length;
24951
+ for (;; ) {
24952
+ const name = order[at];
24953
+ if (name === undefined) {
24954
+ throw new Error(`image-gen: fallback order exhausted before image ${image} was decided`);
24955
+ }
24956
+ const provider = at === 0 ? primary : createCandidate(name);
24957
+ const model = at === 0 ? spec.model ?? provider.defaultModel() : provider.defaultModel();
24958
+ const request = {
24959
+ prompt,
24960
+ model,
24961
+ aspectRatio: format.aspectRatio,
24962
+ ...spec.referenceImages !== undefined && spec.referenceImages.length > 0 ? { referenceImages: spec.referenceImages } : {}
24963
+ };
24964
+ try {
24965
+ provider.validate?.(request);
24966
+ return await provider.generate(request);
24967
+ } catch (err) {
24968
+ if (spec.fallback === undefined) {
24969
+ throw err;
24970
+ }
24971
+ const cls = classifyProviderError(err);
24972
+ const message = err instanceof Error ? err.message : String(err);
24973
+ if (!isFallbackEligible(cls)) {
24974
+ throw new Error(`image-gen: ${provider.name} rejected the prompt (policy): ${message}; fallback does not apply`);
24975
+ }
24976
+ attempts.push({ image, provider: provider.name, model, errorClass: cls, message });
24977
+ const next = order[at + 1];
24978
+ if (next === undefined) {
24979
+ const detail = attempts.slice(start).map((attempt) => `${attempt.provider} (${attempt.errorClass})`).join(", ");
24980
+ throw new Error(`image-gen: all providers failed for image ${image}: ${detail}; ${message}`);
24981
+ }
24982
+ echoError(`WARN image-gen: ${provider.name} failed (${cls}): ${message}; falling back to ${next}`);
24983
+ at += 1;
24984
+ }
24985
+ }
24986
+ };
24763
24987
  let body = doc2?.body ?? "";
24764
24988
  for (const [index, prompt] of prompts.entries()) {
24765
- const request = {
24766
- prompt,
24767
- model: spec.model ?? provider.defaultModel(),
24768
- aspectRatio: format.aspectRatio,
24769
- ...spec.referenceImages && spec.referenceImages.length > 0 ? { referenceImages: spec.referenceImages } : {}
24770
- };
24771
- provider.validate?.(request);
24772
- const result = await provider.generate(request);
24989
+ const result = await generateWithFallback(index + 1, prompt);
24773
24990
  let anchor;
24774
24991
  if (spec.job === "illustration") {
24775
24992
  anchor = positions?.[index];
@@ -24818,7 +25035,8 @@ async function processGeneratorIO(inputPath, outputPath, options = {}) {
24818
25035
  job: spec.job,
24819
25036
  images: artifacts,
24820
25037
  ...spec.job !== "free" && doc2?.id !== undefined ? { sourceDocId: doc2.id } : {},
24821
- ...captions.length > 0 ? { captions } : {}
25038
+ ...captions.length > 0 ? { captions } : {},
25039
+ ...attempts.length > 0 ? { attempts } : {}
24822
25040
  };
24823
25041
  const content = ContentSchema.parse({
24824
25042
  body: spec.job === "illustration" ? body : prompts.join(`
@@ -24867,6 +25085,7 @@ export {
24867
25085
  selectProvider,
24868
25086
  resolvePresetRoots,
24869
25087
  resolveMaxImages,
25088
+ resolveFallbackOrder,
24870
25089
  renderTemplate,
24871
25090
  readPositions,
24872
25091
  processGeneratorIO,
@@ -24875,7 +25094,9 @@ export {
24875
25094
  mergeVars,
24876
25095
  main2 as main,
24877
25096
  loadPresets,
25097
+ isFallbackEligible,
24878
25098
  composePrompt,
25099
+ classifyProviderError,
24879
25100
  artifactPath,
24880
25101
  StylePresetSchema,
24881
25102
  PROVIDER_REQUEST_TIMEOUT_MS,