@gobing-ai/knowledge-kit 0.0.32 → 0.0.34

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 (72) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/dist/index.js +43047 -24724
  3. package/package.json +4 -4
  4. package/plugins/generations/content-gen/dist/index.js +10 -9
  5. package/plugins/generations/core-facts-gen/dist/index.js +13 -12
  6. package/plugins/generations/daily-article-gen/dist/index.js +16 -21
  7. package/plugins/generations/daily-article-gen/src/index.ts +8 -12
  8. package/plugins/generations/dailynews-gen/dist/index.js +23 -21
  9. package/plugins/generations/dailynews-gen/src/script-builder.ts +25 -26
  10. package/plugins/generations/episode-plan-gen/dist/index.js +58 -15
  11. package/plugins/generations/episode-plan-gen/src/index.ts +76 -6
  12. package/plugins/generations/gemini-tts/README.md +11 -0
  13. package/plugins/generations/gemini-tts/dist/index.js +10 -9
  14. package/plugins/generations/image-gen/dist/index.js +171 -153
  15. package/plugins/generations/image-gen/presets/formats/xhs-card.yaml +16 -14
  16. package/plugins/generations/image-gen/presets/styles/xhs-knowledge.yaml +2 -2
  17. package/plugins/generations/image-gen/src/compose/card.ts +17 -2
  18. package/plugins/generations/image-gen/src/compose/chromium.ts +60 -42
  19. package/plugins/generations/news-report-gen/dist/index.js +13 -12
  20. package/plugins/generations/voice-gen/dist/index.js +10 -9
  21. package/plugins/ingestions/aihot-ingest/dist/index.js +13 -12
  22. package/plugins/ingestions/horizon-ingest/dist/index.js +13 -12
  23. package/plugins/ingestions/karakeep-local/dist/index.js +13 -13
  24. package/plugins/ingestions/last30days-ingest/dist/index.js +13 -12
  25. package/plugins/ingestions/web-search/dist/index.js +11 -10
  26. package/plugins/kk/README.md +38 -0
  27. package/plugins/kk/decisions/extract/ai-news.yaml +27 -0
  28. package/plugins/kk/decisions/kk-items.yaml +179 -0
  29. package/plugins/kk/plugin.json +1 -1
  30. package/plugins/kk/schedules/cron.tmpl +15 -0
  31. package/plugins/kk/schedules/launchd.plist.tmpl +77 -0
  32. package/plugins/kk/scripts/daily-stages.ts +2023 -0
  33. package/plugins/kk/scripts/daily-voice-style.zh.md +15 -10
  34. package/plugins/kk/scripts/kk-workflow-stages.ts +253 -1368
  35. package/plugins/kk/skills/content-safety/SKILL.md +39 -8
  36. package/plugins/kk/skills/content-safety/references/platforms/apple-podcasts.md +2 -2
  37. package/plugins/kk/skills/web-automation/SKILL.md +100 -0
  38. package/plugins/kk/skills/web-automation/references/browser-launch.md +86 -0
  39. package/plugins/kk/workflows/kk-collect.yaml +256 -0
  40. package/plugins/kk/workflows/kk-daily-ai-voice.yaml +9 -3
  41. package/plugins/kk/workflows/kk-daily-ai-voice2.yaml +774 -0
  42. package/plugins/kk/workflows/kk-daily-safety.yaml +167 -0
  43. package/plugins/publishings/emdash-pub/dist/index.js +10 -9
  44. package/plugins/publishings/infoq-pub/dist/index.js +152 -59
  45. package/plugins/publishings/infoq-pub/plugin.json +1 -0
  46. package/plugins/publishings/infoq-pub/src/index.ts +167 -55
  47. package/plugins/publishings/infoq-pub/src/profile-check.ts +4 -2
  48. package/plugins/publishings/juejin-pub/dist/index.js +111 -30
  49. package/plugins/publishings/juejin-pub/plugin.json +1 -0
  50. package/plugins/publishings/juejin-pub/src/index.ts +49 -9
  51. package/plugins/publishings/medium-pub/dist/index.js +10 -9
  52. package/plugins/publishings/podcast-pub/dist/index.js +10 -9
  53. package/plugins/publishings/qiita-pub/dist/index.js +10 -9
  54. package/plugins/publishings/substack-pub/dist/index.js +105 -28
  55. package/plugins/publishings/substack-pub/plugin.json +1 -0
  56. package/plugins/publishings/substack-pub/src/index.ts +39 -8
  57. package/plugins/publishings/substack-pub/src/profile-check.ts +2 -0
  58. package/plugins/publishings/surfdash-pub/dist/index.js +10 -9
  59. package/plugins/publishings/wechatmp-pub/dist/index.js +115 -31
  60. package/plugins/publishings/wechatmp-pub/plugin.json +1 -0
  61. package/plugins/publishings/wechatmp-pub/src/index.ts +42 -9
  62. package/plugins/publishings/wechatmp-pub/src/profile-check.ts +84 -40
  63. package/plugins/publishings/x-pub/dist/index.js +114 -35
  64. package/plugins/publishings/x-pub/plugin.json +1 -0
  65. package/plugins/publishings/x-pub/src/index.ts +68 -14
  66. package/plugins/publishings/xhs-pub/dist/index.js +154 -59
  67. package/plugins/publishings/xhs-pub/plugin.json +1 -0
  68. package/plugins/publishings/xhs-pub/src/flow.ts +9 -3
  69. package/plugins/publishings/xhs-pub/src/index.ts +119 -9
  70. package/plugins/publishings/xhs-pub/src/page.ts +4 -17
  71. package/plugins/publishings/xhs-pub/src/profile-check.ts +28 -15
  72. package/plugins/publishings/zenn-pub/dist/index.js +10 -9
@@ -14642,7 +14642,7 @@ var init_zod = __esm(() => {
14642
14642
  init_external();
14643
14643
  });
14644
14644
 
14645
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.15/node_modules/@gobing-ai/ts-utils/dist/errors.js
14645
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.21/node_modules/@gobing-ai/ts-utils/dist/errors.js
14646
14646
  var ErrorCode;
14647
14647
  var init_errors3 = __esm(() => {
14648
14648
  ErrorCode = {
@@ -14653,7 +14653,7 @@ var init_errors3 = __esm(() => {
14653
14653
  };
14654
14654
  });
14655
14655
 
14656
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.15/node_modules/@gobing-ai/ts-utils/dist/api-response.js
14656
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.21/node_modules/@gobing-ai/ts-utils/dist/api-response.js
14657
14657
  var API_ERROR_CODES, ERROR_CODE_TO_HTTP, CLIENT_SAFE_CODES;
14658
14658
  var init_api_response = __esm(() => {
14659
14659
  init_errors3();
@@ -14676,13 +14676,13 @@ var init_api_response = __esm(() => {
14676
14676
  CLIENT_SAFE_CODES = new Set([ErrorCode.NotFound, ErrorCode.Validation, ErrorCode.Conflict]);
14677
14677
  });
14678
14678
 
14679
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.15/node_modules/@gobing-ai/ts-utils/dist/cursor.js
14679
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.21/node_modules/@gobing-ai/ts-utils/dist/cursor.js
14680
14680
  var init_cursor = () => {};
14681
14681
 
14682
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.15/node_modules/@gobing-ai/ts-utils/dist/event-severity.js
14682
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.21/node_modules/@gobing-ai/ts-utils/dist/event-severity.js
14683
14683
  var init_event_severity = () => {};
14684
14684
 
14685
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.15/node_modules/@gobing-ai/ts-utils/dist/output.js
14685
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.21/node_modules/@gobing-ai/ts-utils/dist/output.js
14686
14686
  function processStream(name) {
14687
14687
  const proc = globalThis.process;
14688
14688
  const stream = proc?.[name];
@@ -14700,7 +14700,7 @@ function echoError(message, target = defaultStderrTarget ?? processStream("stder
14700
14700
  }
14701
14701
  var defaultStderrTarget;
14702
14702
 
14703
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.15/node_modules/@gobing-ai/ts-utils/dist/index.js
14703
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.21/node_modules/@gobing-ai/ts-utils/dist/index.js
14704
14704
  var init_dist = __esm(() => {
14705
14705
  init_api_response();
14706
14706
  init_cursor();
@@ -21698,7 +21698,7 @@ var init_dist2 = __esm(() => {
21698
21698
  $visitAsync = visit.visitAsync;
21699
21699
  });
21700
21700
 
21701
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.15/node_modules/@gobing-ai/ts-runtime/dist/config.js
21701
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.21+44edd5c4d6372504/node_modules/@gobing-ai/ts-runtime/dist/config.js
21702
21702
  var configSchema;
21703
21703
  var init_config = __esm(() => {
21704
21704
  init_dist2();
@@ -21722,7 +21722,7 @@ var init_config = __esm(() => {
21722
21722
  });
21723
21723
  });
21724
21724
 
21725
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.15/node_modules/@gobing-ai/ts-runtime/dist/file-system-node.js
21725
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.21+44edd5c4d6372504/node_modules/@gobing-ai/ts-runtime/dist/file-system-node.js
21726
21726
  import { appendFileSync, cpSync, createReadStream, createWriteStream, existsSync, mkdirSync, readdirSync, readFileSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "fs";
21727
21727
  import { dirname, resolve as resolvePath } from "path";
21728
21728
  function createNodeFileSystem(root, paths) {
@@ -21809,113 +21809,6 @@ function findProjectRoot(startDir) {
21809
21809
  }
21810
21810
  var init_file_system_node = () => {};
21811
21811
 
21812
- // ../../plugins/generations/image-gen/src/bytes.ts
21813
- import { readFile, writeFile } from "fs/promises";
21814
- async function writeBytes(path2, bytes) {
21815
- await writeFile(path2, bytes);
21816
- }
21817
- async function readBytes(path2) {
21818
- return new Uint8Array(await readFile(path2));
21819
- }
21820
- function imageDimensions(bytes) {
21821
- if (isPng(bytes))
21822
- return pngDimensions(bytes);
21823
- if (isJpeg(bytes))
21824
- return jpegDimensions(bytes);
21825
- if (isWebp(bytes))
21826
- return webpDimensions(bytes);
21827
- return null;
21828
- }
21829
- function isPng(b) {
21830
- const PNG_SIG = [137, 80, 78, 71, 13, 10, 26, 10];
21831
- if (b.byteLength < 24)
21832
- return false;
21833
- for (let i = 0;i < 8; i++) {
21834
- if (b[i] !== PNG_SIG[i])
21835
- return false;
21836
- }
21837
- return true;
21838
- }
21839
- function pngDimensions(b) {
21840
- const view = new DataView(b.buffer, b.byteOffset, b.byteLength);
21841
- const ihdrLength = view.getUint32(8, false);
21842
- if (ihdrLength !== 13 || view.getUint32(12, false) !== 1229472850) {
21843
- return null;
21844
- }
21845
- return { width: view.getUint32(16, false), height: view.getUint32(20, false) };
21846
- }
21847
- function isJpeg(b) {
21848
- const view = new DataView(b.buffer, b.byteOffset, b.byteLength);
21849
- return b.byteLength >= 4 && view.getUint16(0, false) === 65496 && view.getUint8(2) === 255;
21850
- }
21851
- function jpegDimensions(b) {
21852
- const view = new DataView(b.buffer, b.byteOffset, b.byteLength);
21853
- let at = 2;
21854
- while (at + 4 <= b.byteLength) {
21855
- if (view.getUint8(at) !== 255)
21856
- return null;
21857
- const marker = view.getUint8(at + 1);
21858
- at += 2;
21859
- if (marker === 1 || marker >= 208 && marker <= 215)
21860
- continue;
21861
- if (at + 2 > b.byteLength)
21862
- return null;
21863
- const length = view.getUint16(at, false);
21864
- if (length < 2)
21865
- return null;
21866
- const isSof = marker >= 192 && marker <= 207 && marker !== 196 && marker !== 200 && marker !== 204;
21867
- if (isSof) {
21868
- if (at + 7 > b.byteLength)
21869
- return null;
21870
- return { height: view.getUint16(at + 3, false), width: view.getUint16(at + 5, false) };
21871
- }
21872
- at += length;
21873
- }
21874
- return null;
21875
- }
21876
- function isWebp(b) {
21877
- if (b.byteLength < 20)
21878
- return false;
21879
- const view = new DataView(b.buffer, b.byteOffset, b.byteLength);
21880
- return view.getUint32(0, true) === 1179011410 && view.getUint32(8, true) === 1346520407;
21881
- }
21882
- function webpDimensions(b) {
21883
- const view = new DataView(b.buffer, b.byteOffset, b.byteLength);
21884
- let at = 12;
21885
- while (at + 8 <= b.byteLength) {
21886
- const id = String.fromCharCode(view.getUint8(at), view.getUint8(at + 1), view.getUint8(at + 2), view.getUint8(at + 3));
21887
- const size = view.getUint32(at + 4, true);
21888
- const body = at + 8;
21889
- if (id === "VP8 ") {
21890
- if (size < 10 || body + 10 > b.byteLength)
21891
- return null;
21892
- if (view.getUint8(body + 3) !== 157 || view.getUint8(body + 4) !== 1 || view.getUint8(body + 5) !== 42) {
21893
- return null;
21894
- }
21895
- return {
21896
- width: view.getUint16(body + 6, true) & 16383,
21897
- height: view.getUint16(body + 8, true) & 16383
21898
- };
21899
- }
21900
- if (id === "VP8L") {
21901
- if (size < 5 || body + 5 > b.byteLength || view.getUint8(body) !== 47)
21902
- return null;
21903
- const bits = view.getUint32(body + 1, true);
21904
- return { width: (bits & 16383) + 1, height: (bits >>> 14 & 16383) + 1 };
21905
- }
21906
- if (id === "VP8X") {
21907
- if (size < 10 || body + 10 > b.byteLength)
21908
- return null;
21909
- const width = view.getUint8(body + 4) | view.getUint8(body + 5) << 8 | view.getUint8(body + 6) << 16;
21910
- const height = view.getUint8(body + 7) | view.getUint8(body + 8) << 8 | view.getUint8(body + 9) << 16;
21911
- return { width: width + 1, height: height + 1 };
21912
- }
21913
- at = body + size + size % 2;
21914
- }
21915
- return null;
21916
- }
21917
- var init_bytes = () => {};
21918
-
21919
21812
  // ../../plugins/generations/image-gen/src/compose/card.ts
21920
21813
  function assertCoverage(input, fonts) {
21921
21814
  const headlineCover = fonts.get(input.compose.fonts.headline);
@@ -22040,6 +21933,7 @@ html, body {
22040
21933
  justify-content: flex-start;
22041
21934
  overflow: hidden;
22042
21935
  background: ${palette.background};
21936
+ border-top: 8px solid ${palette.accent};
22043
21937
  }
22044
21938
  .headline {
22045
21939
  font-family: 'NotoSansSC-Bold', sans-serif;
@@ -22047,6 +21941,8 @@ html, body {
22047
21941
  color: ${palette.text};
22048
21942
  line-height: 1.3;
22049
21943
  margin-bottom: ${Math.round(safeArea / 2)}px;
21944
+ padding-bottom: 12px;
21945
+ border-bottom: 4px solid ${palette.accent};
22050
21946
  word-break: break-all;
22051
21947
  white-space: normal;
22052
21948
  /* font-size is set inline with JS fit-step */
@@ -22055,15 +21951,27 @@ html, body {
22055
21951
  .points-container {
22056
21952
  display: flex;
22057
21953
  flex-direction: column;
22058
- gap: ${Math.round(bodyMinPx * 0.5)}px;
21954
+ gap: ${Math.round(bodyMinPx * 0.55)}px;
22059
21955
  }
22060
21956
  .point {
22061
21957
  font-family: 'NotoSansSC-Regular', sans-serif;
22062
21958
  font-weight: normal;
22063
21959
  color: ${palette.text};
22064
- line-height: 1.5;
21960
+ line-height: 1.45;
22065
21961
  word-break: break-all;
22066
21962
  white-space: normal;
21963
+ padding-left: 28px;
21964
+ position: relative;
21965
+ }
21966
+ .point::before {
21967
+ content: '';
21968
+ position: absolute;
21969
+ left: 0;
21970
+ top: 0.45em;
21971
+ width: 14px;
21972
+ height: 14px;
21973
+ border-radius: 50%;
21974
+ background: ${palette.accent};
22067
21975
  }
22068
21976
  .safe-area-sentinel {
22069
21977
  position: absolute;
@@ -22119,16 +22027,45 @@ __export(exports_chromium, {
22119
22027
  ChromiumComposer: () => ChromiumComposer
22120
22028
  });
22121
22029
  import { join as join3 } from "path";
22122
- function fontRouteUrls(fontNames) {
22123
- const map2 = new Map;
22124
- for (const name of fontNames) {
22125
- map2.set(name, `${FONT_ROUTE_BASE}${encodeURIComponent(name)}`);
22126
- }
22127
- return map2;
22030
+ function serveCard(input) {
22031
+ const fontNames = [input.compose.fonts.headline, input.compose.fonts.body];
22032
+ let html = "";
22033
+ const server = Bun.serve({
22034
+ hostname: "127.0.0.1",
22035
+ port: 0,
22036
+ fetch: (request) => {
22037
+ const path2 = decodeURIComponent(new URL(request.url).pathname);
22038
+ if (path2 === "/")
22039
+ return new Response(html, { headers: { "content-type": "text/html; charset=utf-8" } });
22040
+ const name = path2.slice("/fonts/".length);
22041
+ if (path2.startsWith("/fonts/") && fontNames.includes(name)) {
22042
+ return new Response(Bun.file(join3(FONTS_DIR, name)), { headers: { "content-type": "font/otf" } });
22043
+ }
22044
+ return new Response("not found", { status: 404 });
22045
+ }
22046
+ });
22047
+ const url2 = `http://127.0.0.1:${server.port}/`;
22048
+ html = cardHtml(input, new Map(fontNames.map((name) => [name, `${url2}fonts/${encodeURIComponent(name)}`])));
22049
+ return { url: url2, stop: () => server.stop(true) };
22128
22050
  }
22129
22051
 
22130
22052
  class ChromiumComposer {
22053
+ timeoutMs;
22054
+ constructor(options = {}) {
22055
+ this.timeoutMs = options.timeoutMs ?? COMPOSE_TIMEOUT_MS;
22056
+ }
22131
22057
  async compose(input) {
22058
+ let timer;
22059
+ const deadline = new Promise((_, reject) => {
22060
+ timer = setTimeout(() => reject(new Error(`compose: Chromium did not finish within ${this.timeoutMs}ms (stalled launch)`)), this.timeoutMs);
22061
+ });
22062
+ try {
22063
+ return await Promise.race([this.render(input), deadline]);
22064
+ } finally {
22065
+ clearTimeout(timer);
22066
+ }
22067
+ }
22068
+ async render(input) {
22132
22069
  let chromium;
22133
22070
  try {
22134
22071
  const pw = await import("playwright");
@@ -22137,9 +22074,7 @@ class ChromiumComposer {
22137
22074
  throw new Error(`compose: Playwright is not installed. Run: bunx playwright install chromium
22138
22075
  (${err instanceof Error ? err.message : String(err)})`);
22139
22076
  }
22140
- const fontNames = [input.compose.fonts.headline, input.compose.fonts.body];
22141
- const fontUrls = fontRouteUrls(fontNames);
22142
- const html = cardHtml(input, fontUrls);
22077
+ const card = serveCard(input);
22143
22078
  let browser;
22144
22079
  try {
22145
22080
  try {
@@ -22153,22 +22088,7 @@ class ChromiumComposer {
22153
22088
  viewport: { width: input.width, height: input.height },
22154
22089
  deviceScaleFactor: 1
22155
22090
  });
22156
- await page.route(`${FONT_ROUTE_BASE}**`, async (route) => {
22157
- const url2 = new URL(route.request().url());
22158
- const fontName = decodeURIComponent(url2.pathname.slice(1));
22159
- const fontPath = join3(FONTS_DIR, fontName);
22160
- try {
22161
- const bytes = await readBytes(fontPath);
22162
- await route.fulfill({
22163
- status: 200,
22164
- contentType: "font/otf",
22165
- body: Buffer.from(bytes)
22166
- });
22167
- } catch {
22168
- await route.abort();
22169
- }
22170
- });
22171
- await page.setContent(html, { waitUntil: "domcontentloaded" });
22091
+ await page.goto(card.url, { waitUntil: "domcontentloaded" });
22172
22092
  await page.evaluate("document.fonts.ready");
22173
22093
  const { safeArea, illustrationHeight } = input.compose;
22174
22094
  const safeLeft = safeArea;
@@ -22199,15 +22119,15 @@ class ChromiumComposer {
22199
22119
  return new Uint8Array(screenshot);
22200
22120
  } finally {
22201
22121
  await browser?.close();
22122
+ card.stop();
22202
22123
  }
22203
22124
  }
22204
22125
  }
22205
22126
  function makeChromiumComposer() {
22206
22127
  return new ChromiumComposer;
22207
22128
  }
22208
- var FONTS_DIR, FONT_ROUTE_BASE = "http://kk-fonts.local/";
22129
+ var FONTS_DIR, COMPOSE_TIMEOUT_MS = 120000;
22209
22130
  var init_chromium = __esm(() => {
22210
- init_bytes();
22211
22131
  FONTS_DIR = join3(import.meta.dir, "..", "..", "assets", "fonts");
22212
22132
  });
22213
22133
 
@@ -22298,11 +22218,12 @@ var PluginManifestSchema = exports_external.looseObject({
22298
22218
  name: exports_external.string().min(1),
22299
22219
  kind: PluginKindSchema,
22300
22220
  entry: exports_external.string().min(1),
22221
+ check: exports_external.string().min(1).optional(),
22301
22222
  version: exports_external.string().optional(),
22302
22223
  description: exports_external.string().optional(),
22303
22224
  operations: exports_external.record(exports_external.string(), PluginOperationSchema).optional()
22304
22225
  });
22305
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.15/node_modules/@gobing-ai/ts-runtime/dist/index.js
22226
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.21+44edd5c4d6372504/node_modules/@gobing-ai/ts-runtime/dist/index.js
22306
22227
  init_file_system_node();
22307
22228
  init_config();
22308
22229
 
@@ -22310,8 +22231,112 @@ init_config();
22310
22231
  if (false) {}
22311
22232
  // ../../plugins/generations/image-gen/src/index.ts
22312
22233
  init_dist();
22313
- init_bytes();
22314
22234
 
22235
+ // ../../plugins/generations/image-gen/src/bytes.ts
22236
+ import { readFile, writeFile } from "fs/promises";
22237
+ async function writeBytes(path2, bytes) {
22238
+ await writeFile(path2, bytes);
22239
+ }
22240
+ async function readBytes(path2) {
22241
+ return new Uint8Array(await readFile(path2));
22242
+ }
22243
+ function imageDimensions(bytes) {
22244
+ if (isPng(bytes))
22245
+ return pngDimensions(bytes);
22246
+ if (isJpeg(bytes))
22247
+ return jpegDimensions(bytes);
22248
+ if (isWebp(bytes))
22249
+ return webpDimensions(bytes);
22250
+ return null;
22251
+ }
22252
+ function isPng(b) {
22253
+ const PNG_SIG = [137, 80, 78, 71, 13, 10, 26, 10];
22254
+ if (b.byteLength < 24)
22255
+ return false;
22256
+ for (let i = 0;i < 8; i++) {
22257
+ if (b[i] !== PNG_SIG[i])
22258
+ return false;
22259
+ }
22260
+ return true;
22261
+ }
22262
+ function pngDimensions(b) {
22263
+ const view = new DataView(b.buffer, b.byteOffset, b.byteLength);
22264
+ const ihdrLength = view.getUint32(8, false);
22265
+ if (ihdrLength !== 13 || view.getUint32(12, false) !== 1229472850) {
22266
+ return null;
22267
+ }
22268
+ return { width: view.getUint32(16, false), height: view.getUint32(20, false) };
22269
+ }
22270
+ function isJpeg(b) {
22271
+ const view = new DataView(b.buffer, b.byteOffset, b.byteLength);
22272
+ return b.byteLength >= 4 && view.getUint16(0, false) === 65496 && view.getUint8(2) === 255;
22273
+ }
22274
+ function jpegDimensions(b) {
22275
+ const view = new DataView(b.buffer, b.byteOffset, b.byteLength);
22276
+ let at = 2;
22277
+ while (at + 4 <= b.byteLength) {
22278
+ if (view.getUint8(at) !== 255)
22279
+ return null;
22280
+ const marker = view.getUint8(at + 1);
22281
+ at += 2;
22282
+ if (marker === 1 || marker >= 208 && marker <= 215)
22283
+ continue;
22284
+ if (at + 2 > b.byteLength)
22285
+ return null;
22286
+ const length = view.getUint16(at, false);
22287
+ if (length < 2)
22288
+ return null;
22289
+ const isSof = marker >= 192 && marker <= 207 && marker !== 196 && marker !== 200 && marker !== 204;
22290
+ if (isSof) {
22291
+ if (at + 7 > b.byteLength)
22292
+ return null;
22293
+ return { height: view.getUint16(at + 3, false), width: view.getUint16(at + 5, false) };
22294
+ }
22295
+ at += length;
22296
+ }
22297
+ return null;
22298
+ }
22299
+ function isWebp(b) {
22300
+ if (b.byteLength < 20)
22301
+ return false;
22302
+ const view = new DataView(b.buffer, b.byteOffset, b.byteLength);
22303
+ return view.getUint32(0, true) === 1179011410 && view.getUint32(8, true) === 1346520407;
22304
+ }
22305
+ function webpDimensions(b) {
22306
+ const view = new DataView(b.buffer, b.byteOffset, b.byteLength);
22307
+ let at = 12;
22308
+ while (at + 8 <= b.byteLength) {
22309
+ const id = String.fromCharCode(view.getUint8(at), view.getUint8(at + 1), view.getUint8(at + 2), view.getUint8(at + 3));
22310
+ const size = view.getUint32(at + 4, true);
22311
+ const body = at + 8;
22312
+ if (id === "VP8 ") {
22313
+ if (size < 10 || body + 10 > b.byteLength)
22314
+ return null;
22315
+ if (view.getUint8(body + 3) !== 157 || view.getUint8(body + 4) !== 1 || view.getUint8(body + 5) !== 42) {
22316
+ return null;
22317
+ }
22318
+ return {
22319
+ width: view.getUint16(body + 6, true) & 16383,
22320
+ height: view.getUint16(body + 8, true) & 16383
22321
+ };
22322
+ }
22323
+ if (id === "VP8L") {
22324
+ if (size < 5 || body + 5 > b.byteLength || view.getUint8(body) !== 47)
22325
+ return null;
22326
+ const bits = view.getUint32(body + 1, true);
22327
+ return { width: (bits & 16383) + 1, height: (bits >>> 14 & 16383) + 1 };
22328
+ }
22329
+ if (id === "VP8X") {
22330
+ if (size < 10 || body + 10 > b.byteLength)
22331
+ return null;
22332
+ const width = view.getUint8(body + 4) | view.getUint8(body + 5) << 8 | view.getUint8(body + 6) << 16;
22333
+ const height = view.getUint8(body + 7) | view.getUint8(body + 8) << 8 | view.getUint8(body + 9) << 16;
22334
+ return { width: width + 1, height: height + 1 };
22335
+ }
22336
+ at = body + size + size % 2;
22337
+ }
22338
+ return null;
22339
+ }
22315
22340
  // ../../plugins/generations/image-gen/src/compose/cmap.ts
22316
22341
  function u16(view, offset) {
22317
22342
  return view.getUint16(offset, false);
@@ -22698,7 +22723,6 @@ function loadPresets() {
22698
22723
  import { Buffer as Buffer3 } from "buffer";
22699
22724
 
22700
22725
  // ../../plugins/generations/image-gen/src/providers/refs.ts
22701
- init_bytes();
22702
22726
  import { extname as extname2 } from "path";
22703
22727
  function mimeForPath(path2) {
22704
22728
  const ext = extname2(path2).toLowerCase();
@@ -22720,7 +22744,6 @@ async function refToDataUri(path2) {
22720
22744
  }
22721
22745
 
22722
22746
  // ../../plugins/generations/image-gen/src/providers/seedream.ts
22723
- init_bytes();
22724
22747
  import { Buffer as Buffer2 } from "buffer";
22725
22748
 
22726
22749
  // ../../plugins/generations/image-gen/src/providers/timeouts.ts
@@ -22919,11 +22942,9 @@ var createAgnes = (options) => {
22919
22942
  };
22920
22943
 
22921
22944
  // ../../plugins/generations/image-gen/src/providers/azure.ts
22922
- init_bytes();
22923
22945
  import { extname as extname3 } from "path";
22924
22946
 
22925
22947
  // ../../plugins/generations/image-gen/src/providers/openai.ts
22926
- init_bytes();
22927
22948
  import { Buffer as Buffer4 } from "buffer";
22928
22949
  import { basename as basename2 } from "path";
22929
22950
  var DEFAULT_MODEL3 = "gpt-image-2";
@@ -23333,7 +23354,6 @@ var createAzure = (options) => {
23333
23354
  };
23334
23355
 
23335
23356
  // ../../plugins/generations/image-gen/src/providers/codex-cli.ts
23336
- init_bytes();
23337
23357
  import { spawn } from "child_process";
23338
23358
  import { randomBytes } from "crypto";
23339
23359
  import { access as access2, mkdir, rm, writeFile as writeFile2 } from "fs/promises";
@@ -23858,7 +23878,6 @@ import { execFileSync } from "child_process";
23858
23878
  import { randomUUID } from "crypto";
23859
23879
  import { tmpdir as tmpdir2 } from "os";
23860
23880
  import { join as join2 } from "path";
23861
- init_bytes();
23862
23881
  var GOOGLE_MULTIMODAL_MODELS = [
23863
23882
  "gemini-3-pro-image",
23864
23883
  "gemini-3.1-flash-image",
@@ -24313,7 +24332,6 @@ var createJimeng = (options) => {
24313
24332
  };
24314
24333
 
24315
24334
  // ../../plugins/generations/image-gen/src/providers/minimax.ts
24316
- init_bytes();
24317
24335
  import { Buffer as Buffer7 } from "buffer";
24318
24336
  var DEFAULT_MODEL9 = "image-01";
24319
24337
  var MAX_REFERENCE_IMAGE_BYTES = 10 * 1024 * 1024;
@@ -1,20 +1,21 @@
1
1
  name: xhs-card
2
2
  description: >-
3
- Xiaohongshu (XHS) knowledge card — 3:4 portrait image-text card with large
4
- Chinese headline and short bullet points. Adapted from baoyu-xhs-images
5
- (MIT © Jim Liu); see plugins/kk/skills/xhs-images/references/card-layouts.md.
6
- Task 0180: card copy is typeset from Noto Sans SC via headless Chromium;
7
- the provider prompt generates the illustration only.
3
+ Xiaohongshu (XHS) knowledge card — 3:4 portrait card. Chinese headline and
4
+ bullets are typeset from Noto Sans SC via headless Chromium; the provider
5
+ prompt is the illustration only and must not ask for writing. Adapted from
6
+ baoyu-xhs-images (MIT © Jim Liu); see
7
+ plugins/kk/skills/xhs-images/references/card-layouts.md.
8
8
  job: free
9
9
  aspectRatio: '3:4'
10
10
  width: 1080
11
11
  height: 1440
12
12
  defaultStyle: xhs-knowledge
13
13
  keywords:
14
- - xiaohongshu-style
15
- - image-text card layout
14
+ - text-free flat illustration
15
+ - blank unlabeled surfaces
16
+ - empty screens and empty signs
16
17
  - fresh clean design
17
- - flat illustration accents with geometric decorations
18
+ - flat geometric accents
18
19
  - professional color grading
19
20
  outputFilename: 'card-{{index | 01}}.png'
20
21
  compose:
@@ -22,7 +23,7 @@ compose:
22
23
  safeArea: 72
23
24
  headlineMinPx: 64
24
25
  bodyMinPx: 36
25
- illustrationHeight: 640
26
+ illustrationHeight: 880
26
27
  palette:
27
28
  background: '#FFFFFF'
28
29
  text: '#1F2328'
@@ -53,11 +54,12 @@ variables:
53
54
  description: Additional context (use --content)
54
55
  default: ''
55
56
  template: |-
56
- Xiaohongshu-style knowledge card, portrait 3:4, for a card series.
57
+ Portrait illustration, 3:4, one scene for a card series.
57
58
  Card role: {{role | content}}. Layout: {{layout | definition}}.
58
59
  Visual scene: {{subject | clean flat illustration of the core concept}},
59
- rendered as flat illustration accents with subtle geometric decorations.
60
- Pure illustration, no text, no letters, no numerals, no captions — the text
61
- band is typeset separately. Fresh clean design, comfortable margins, no
62
- watermark, no extra UI chrome. 8K quality, crisp details, professional color
60
+ rendered as a flat illustration with subtle geometric decorations.
61
+ Illustration only. Every surface stays blank: empty screens, empty signs,
62
+ empty labels. No writing, no letters, no numerals, no captions, no logos,
63
+ no watermark, no UI chrome. Words are typeset later, outside this image.
64
+ Fresh clean design, comfortable margins, crisp details, professional color
63
65
  grading. {{content}}
@@ -4,5 +4,5 @@ description: >-
4
4
  background, clean information layout, soft accent colors, rounded card zones.
5
5
  Adapted from baoyu-xhs-images "knowledge card" style guidance (MIT © Jim Liu);
6
6
  see plugins/kk/skills/xhs-images/references/card-layouts.md.
7
- modifiers: simple clean light background, rounded rectangle card zones, soft pastel accent colors, generous whitespace, flat geometric decorations, subtle drop shadows, fresh and professional
8
- negative: text, letters, numbers, Chinese characters, captions, watermark, logo
7
+ modifiers: simple clean light background, soft pastel accent colors, generous whitespace, flat geometric decorations, subtle drop shadows, fresh and professional, unlabeled surfaces
8
+ negative: text, letters, words, numbers, Chinese characters, calligraphy, signage, captions, watermark, logo, screen glyphs, vertical script, stamps
@@ -220,6 +220,7 @@ html, body {
220
220
  justify-content: flex-start;
221
221
  overflow: hidden;
222
222
  background: ${palette.background};
223
+ border-top: 8px solid ${palette.accent};
223
224
  }
224
225
  .headline {
225
226
  font-family: 'NotoSansSC-Bold', sans-serif;
@@ -227,6 +228,8 @@ html, body {
227
228
  color: ${palette.text};
228
229
  line-height: 1.3;
229
230
  margin-bottom: ${Math.round(safeArea / 2)}px;
231
+ padding-bottom: 12px;
232
+ border-bottom: 4px solid ${palette.accent};
230
233
  word-break: break-all;
231
234
  white-space: normal;
232
235
  /* font-size is set inline with JS fit-step */
@@ -235,15 +238,27 @@ html, body {
235
238
  .points-container {
236
239
  display: flex;
237
240
  flex-direction: column;
238
- gap: ${Math.round(bodyMinPx * 0.5)}px;
241
+ gap: ${Math.round(bodyMinPx * 0.55)}px;
239
242
  }
240
243
  .point {
241
244
  font-family: 'NotoSansSC-Regular', sans-serif;
242
245
  font-weight: normal;
243
246
  color: ${palette.text};
244
- line-height: 1.5;
247
+ line-height: 1.45;
245
248
  word-break: break-all;
246
249
  white-space: normal;
250
+ padding-left: 28px;
251
+ position: relative;
252
+ }
253
+ .point::before {
254
+ content: '';
255
+ position: absolute;
256
+ left: 0;
257
+ top: 0.45em;
258
+ width: 14px;
259
+ height: 14px;
260
+ border-radius: 50%;
261
+ background: ${palette.accent};
247
262
  }
248
263
  .safe-area-sentinel {
249
264
  position: absolute;