@gobing-ai/knowledge-kit 0.0.32 → 0.0.33

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 (65) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/dist/index.js +32320 -15021
  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 +14 -13
  7. package/plugins/generations/daily-article-gen/src/index.ts +1 -1
  8. package/plugins/generations/dailynews-gen/dist/index.js +10 -9
  9. package/plugins/generations/episode-plan-gen/dist/index.js +58 -15
  10. package/plugins/generations/episode-plan-gen/src/index.ts +76 -6
  11. package/plugins/generations/gemini-tts/README.md +11 -0
  12. package/plugins/generations/gemini-tts/dist/index.js +10 -9
  13. package/plugins/generations/image-gen/dist/index.js +154 -151
  14. package/plugins/generations/image-gen/src/compose/chromium.ts +60 -42
  15. package/plugins/generations/news-report-gen/dist/index.js +13 -12
  16. package/plugins/generations/voice-gen/dist/index.js +10 -9
  17. package/plugins/ingestions/aihot-ingest/dist/index.js +13 -12
  18. package/plugins/ingestions/horizon-ingest/dist/index.js +13 -12
  19. package/plugins/ingestions/karakeep-local/dist/index.js +13 -13
  20. package/plugins/ingestions/last30days-ingest/dist/index.js +13 -12
  21. package/plugins/ingestions/web-search/dist/index.js +11 -10
  22. package/plugins/kk/README.md +38 -0
  23. package/plugins/kk/decisions/extract/ai-news.yaml +21 -0
  24. package/plugins/kk/decisions/kk-items.yaml +113 -0
  25. package/plugins/kk/plugin.json +1 -1
  26. package/plugins/kk/schedules/cron.tmpl +15 -0
  27. package/plugins/kk/schedules/launchd.plist.tmpl +77 -0
  28. package/plugins/kk/scripts/daily-stages.ts +1533 -0
  29. package/plugins/kk/scripts/kk-workflow-stages.ts +247 -1365
  30. package/plugins/kk/skills/content-safety/SKILL.md +38 -7
  31. package/plugins/kk/skills/web-automation/SKILL.md +100 -0
  32. package/plugins/kk/skills/web-automation/references/browser-launch.md +86 -0
  33. package/plugins/kk/workflows/kk-collect.yaml +258 -0
  34. package/plugins/kk/workflows/kk-daily-ai-voice.yaml +9 -3
  35. package/plugins/kk/workflows/kk-daily-ai-voice2.yaml +655 -0
  36. package/plugins/kk/workflows/kk-daily-safety.yaml +170 -0
  37. package/plugins/publishings/emdash-pub/dist/index.js +10 -9
  38. package/plugins/publishings/infoq-pub/dist/index.js +152 -59
  39. package/plugins/publishings/infoq-pub/plugin.json +1 -0
  40. package/plugins/publishings/infoq-pub/src/index.ts +167 -55
  41. package/plugins/publishings/infoq-pub/src/profile-check.ts +4 -2
  42. package/plugins/publishings/juejin-pub/dist/index.js +111 -30
  43. package/plugins/publishings/juejin-pub/plugin.json +1 -0
  44. package/plugins/publishings/juejin-pub/src/index.ts +49 -9
  45. package/plugins/publishings/medium-pub/dist/index.js +10 -9
  46. package/plugins/publishings/podcast-pub/dist/index.js +10 -9
  47. package/plugins/publishings/qiita-pub/dist/index.js +10 -9
  48. package/plugins/publishings/substack-pub/dist/index.js +105 -28
  49. package/plugins/publishings/substack-pub/plugin.json +1 -0
  50. package/plugins/publishings/substack-pub/src/index.ts +39 -8
  51. package/plugins/publishings/substack-pub/src/profile-check.ts +2 -0
  52. package/plugins/publishings/surfdash-pub/dist/index.js +10 -9
  53. package/plugins/publishings/wechatmp-pub/dist/index.js +115 -31
  54. package/plugins/publishings/wechatmp-pub/plugin.json +1 -0
  55. package/plugins/publishings/wechatmp-pub/src/index.ts +42 -9
  56. package/plugins/publishings/wechatmp-pub/src/profile-check.ts +84 -40
  57. package/plugins/publishings/x-pub/dist/index.js +114 -35
  58. package/plugins/publishings/x-pub/plugin.json +1 -0
  59. package/plugins/publishings/x-pub/src/index.ts +68 -14
  60. package/plugins/publishings/xhs-pub/dist/index.js +100 -54
  61. package/plugins/publishings/xhs-pub/plugin.json +1 -0
  62. package/plugins/publishings/xhs-pub/src/index.ts +8 -4
  63. package/plugins/publishings/xhs-pub/src/page.ts +4 -17
  64. package/plugins/publishings/xhs-pub/src/profile-check.ts +28 -15
  65. package/plugins/publishings/zenn-pub/dist/index.js +10 -9
@@ -19,7 +19,10 @@ import { echoError } from '@gobing-ai/ts-utils';
19
19
  * out — survivors to `--out`, rejection audit to `<out>.rejected.json`; env
20
20
  * `QC_CATEGORIES` (default 'ai-news,ai-industry'),
21
21
  * `QC_MIN_QUALITY/IMPORTANCE/URGENCY/IMPACT` (defaults 2/3/2/1 — 0099 recalibration);
22
- * invalid values exit 1 (fail loud, no clamping).
22
+ * invalid values exit 1 (fail loud, no clamping). `--mode label` (0209) is the
23
+ * labelling contract for `kk store label`: every input doc annotated
24
+ * (`metadata.category`, `metadata.scores`, `metadata.needs_model`), no cap, dedup or
25
+ * filter, written to `--out` with no audit sidecar.
23
26
  */
24
27
 
25
28
  /** Tunable scoring knobs (kept here so the shape is greppable, not config-filed). */
@@ -415,6 +418,41 @@ export function scoreDimensions(doc: Doc, planDate: string): DimensionScores {
415
418
  return { quality, importance, urgency, impact };
416
419
  }
417
420
 
421
+ /**
422
+ * Does the keyword heuristic want a model second opinion on this doc?
423
+ *
424
+ * True exactly when the deterministic scan proves an AI signal (an AI-mapped tag, a
425
+ * curated AI source, or an AI keyword in the title/body head) but
426
+ * {@link classifyCategory} still files the doc `non-ai` — a deny rule (non-AI tag, junk
427
+ * phrase, non-AI source) outvoted the signal. Everything else is either confidently
428
+ * categorized or confidently non-AI, so `kk store label` keeps its heuristic rows and
429
+ * spends no model call (0209 R5).
430
+ */
431
+ export function needsModelLabel(doc: Doc): boolean {
432
+ return classifyCategory(doc) === 'non-ai' && hasAiSignal(doc);
433
+ }
434
+
435
+ /**
436
+ * Any AI-side signal matches — the mirror of `classifyCategory`'s positive proof, so the
437
+ * two never disagree about what counts as evidence. `CATEGORY_KEYWORDS` holds AI
438
+ * categories only; the tag map and the curated-source set are filtered to non-`non-ai`.
439
+ */
440
+ function hasAiSignal(doc: Doc): boolean {
441
+ const meta = asRecord(doc.metadata);
442
+ const tags = Array.isArray(meta.tags) ? meta.tags.filter((t): t is string => typeof t === 'string') : [];
443
+ for (const tag of tags) {
444
+ const hit = TAG_CATEGORY[tag.toLowerCase()];
445
+ if (hit !== undefined && hit !== 'non-ai') return true;
446
+ }
447
+ const source = typeof meta.source === 'string' ? meta.source : '';
448
+ if (AI_DEFAULT_SOURCES.has(source)) return true;
449
+ const title = (doc.title ?? '').toLowerCase();
450
+ const bodyHead = (doc.body ?? '').slice(0, 200).toLowerCase();
451
+ return CATEGORY_KEYWORDS.some((row) =>
452
+ row.words.some((w) => matchesKeyword(title, w) || matchesKeyword(bodyHead, w)),
453
+ );
454
+ }
455
+
418
456
  /** Composite 0..100-ish score; ordering matters more than absolute value. */
419
457
  export function planScore(doc: Doc): number {
420
458
  const meta = asRecord(doc.metadata);
@@ -638,8 +676,8 @@ function resolvePlanDate(): string {
638
676
  // kept/rejected split out (ADR-019 D3: QC is a visible, threshold-driven node).
639
677
  // ---------------------------------------------------------------------------
640
678
 
641
- /** Run modes: `plan` (default — the gated selection pipeline, unchanged) or `filter` (the QC gate). */
642
- export type GeneratorMode = 'plan' | 'filter';
679
+ /** Run modes: `plan` (default — the gated selection pipeline, unchanged), `filter` (the QC gate) or `label` (annotation only, 0209). */
680
+ export type GeneratorMode = 'plan' | 'filter' | 'label';
643
681
 
644
682
  /** The closed MECE taxonomy (the values `classifyCategory` emits) — filter allowlists validate against it. */
645
683
  const MECE_CATEGORIES: readonly Category[] = ['ai-news', 'ai-technical', 'ai-research', 'ai-industry', 'non-ai'];
@@ -862,7 +900,39 @@ export async function processGeneratorIO(
862
900
  outputPath: string,
863
901
  mode: GeneratorMode = 'plan',
864
902
  ): Promise<Content> {
865
- return mode === 'filter' ? processFilterIO(inputPath, outputPath) : processPlanIO(inputPath, outputPath);
903
+ if (mode === 'filter') return processFilterIO(inputPath, outputPath);
904
+ if (mode === 'label') return processLabelIO(inputPath, outputPath);
905
+ return processPlanIO(inputPath, outputPath);
906
+ }
907
+
908
+ /**
909
+ * Label mode (0209 R3): annotate EVERY input doc — `metadata.category` and
910
+ * `metadata.scores` exactly as `planEpisode` writes them, plus `metadata.needs_model`
911
+ * ({@link needsModelLabel}) — with no cap, dedup, category gate or top-N selection.
912
+ *
913
+ * `kk store label` reads `metadata.docs` back and writes one `labels` row per decision,
914
+ * so this array IS the labelling contract; `planContent` is reused only as the Content
915
+ * wrapper (no audit sidecar — nothing was selected or rejected).
916
+ */
917
+ export function labelDocs(docs: Doc[], planDate: string): Doc[] {
918
+ return docs.map((doc) => ({
919
+ ...doc,
920
+ metadata: {
921
+ ...asRecord(doc.metadata),
922
+ category: classifyCategory(doc),
923
+ scores: scoreDimensions(doc, planDate),
924
+ needs_model: needsModelLabel(doc),
925
+ },
926
+ }));
927
+ }
928
+
929
+ /** Label mode (0209): every input doc annotated, input order preserved → Content at `--out`. */
930
+ async function processLabelIO(inputPath: string, outputPath: string): Promise<Content> {
931
+ const docs = DocListSchema.parse(await readJsonFile(inputPath));
932
+ const planDate = resolvePlanDate();
933
+ const content = planContent(labelDocs(docs, planDate), planDate);
934
+ await atomicWrite(outputPath, content);
935
+ return content;
866
936
  }
867
937
 
868
938
  /** Plan mode (default, behavior unchanged): blended `Doc[]` → gated/annotated plan Content + `<out>.audit.json` selection trail. */
@@ -915,9 +985,9 @@ export async function main(): Promise<number> {
915
985
  // The env rung exists because `kk executor run` spawns plugin entries with --in/--out only
916
986
  // (ADR-006, apps/cli/src/invoke.ts) and cannot forward extra CLI args.
917
987
  const mode = values.mode ?? process.env.EPISODE_PLAN_MODE ?? 'plan';
918
- if (mode !== 'plan' && mode !== 'filter') {
988
+ if (mode !== 'plan' && mode !== 'filter' && mode !== 'label') {
919
989
  echoError(
920
- `episode-plan-gen failed: unknown mode '${mode}' (from --mode flag or EPISODE_PLAN_MODE env; valid: plan, filter)`,
990
+ `episode-plan-gen failed: unknown mode '${mode}' (from --mode flag or EPISODE_PLAN_MODE env; valid: plan, filter, label)`,
921
991
  );
922
992
  return 1;
923
993
  }
@@ -123,3 +123,14 @@ exceeds that (it used to sleep out the ~19h horizon, which looked like a wedged
123
123
  A stored voice lasts 1 year (200 stored voices per project, shared with prompted voices). Before
124
124
  `expire_time`, repeat export → create → replace the id in the operator map. Delete the scratch
125
125
  clips when the new id is wired. Do not commit the wavs or the voice id.
126
+
127
+ > **2026-10-07 observed:** that 1-year figure did not hold — the 2026-09-24 voice
128
+ > (`voice_e6zevk798ecg`) started returning HTTP 404 "The voice was not found or the caller does not
129
+ > have access/permission to access it" on 10-06/10-07, 13 days after creation (built-in voices kept
130
+ > working, so key/model/request shape were fine). Treat a mid-life 404 as **voice death, not a bug**:
131
+ > re-create via the en-pair path above (zh pair still 500s on 2026-10-07), swap the id in the
132
+ > operator map, and smoke-test one zh segment before the next daily run. Symptom in the daily log:
133
+ > `kk stage daily-generate` exit 1 with the 404 on segment 1 of ~23 queued.
134
+ >
135
+ > Renewal log: 2026-09-24 created → 2026-10-07 re-created (en pair, `voice_gl10j67aaj7j`). Consider
136
+ > a weekly one-segment probe if this recurs; no automated probe today.
@@ -17,7 +17,7 @@ var __export = (target, all) => {
17
17
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
18
18
  var __require = import.meta.require;
19
19
 
20
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.15/node_modules/@gobing-ai/ts-utils/dist/errors.js
20
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.18/node_modules/@gobing-ai/ts-utils/dist/errors.js
21
21
  var ErrorCode;
22
22
  var init_errors = __esm(() => {
23
23
  ErrorCode = {
@@ -28,7 +28,7 @@ var init_errors = __esm(() => {
28
28
  };
29
29
  });
30
30
 
31
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.15/node_modules/@gobing-ai/ts-utils/dist/api-response.js
31
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.18/node_modules/@gobing-ai/ts-utils/dist/api-response.js
32
32
  var API_ERROR_CODES, ERROR_CODE_TO_HTTP, CLIENT_SAFE_CODES;
33
33
  var init_api_response = __esm(() => {
34
34
  init_errors();
@@ -51,13 +51,13 @@ var init_api_response = __esm(() => {
51
51
  CLIENT_SAFE_CODES = new Set([ErrorCode.NotFound, ErrorCode.Validation, ErrorCode.Conflict]);
52
52
  });
53
53
 
54
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.15/node_modules/@gobing-ai/ts-utils/dist/cursor.js
54
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.18/node_modules/@gobing-ai/ts-utils/dist/cursor.js
55
55
  var init_cursor = () => {};
56
56
 
57
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.15/node_modules/@gobing-ai/ts-utils/dist/event-severity.js
57
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.18/node_modules/@gobing-ai/ts-utils/dist/event-severity.js
58
58
  var init_event_severity = () => {};
59
59
 
60
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.15/node_modules/@gobing-ai/ts-utils/dist/output.js
60
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.18/node_modules/@gobing-ai/ts-utils/dist/output.js
61
61
  function processStream(name) {
62
62
  const proc = globalThis.process;
63
63
  const stream = proc?.[name];
@@ -75,7 +75,7 @@ function echoError(message, target = defaultStderrTarget ?? processStream("stder
75
75
  }
76
76
  var defaultStderrTarget;
77
77
 
78
- // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.15/node_modules/@gobing-ai/ts-utils/dist/index.js
78
+ // ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.18/node_modules/@gobing-ai/ts-utils/dist/index.js
79
79
  var init_dist = __esm(() => {
80
80
  init_api_response();
81
81
  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.18+ea28d47622d670ff/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.18+ea28d47622d670ff/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) {
@@ -21899,11 +21899,12 @@ var PluginManifestSchema = exports_external.looseObject({
21899
21899
  name: exports_external.string().min(1),
21900
21900
  kind: PluginKindSchema,
21901
21901
  entry: exports_external.string().min(1),
21902
+ check: exports_external.string().min(1).optional(),
21902
21903
  version: exports_external.string().optional(),
21903
21904
  description: exports_external.string().optional(),
21904
21905
  operations: exports_external.record(exports_external.string(), PluginOperationSchema).optional()
21905
21906
  });
21906
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.15/node_modules/@gobing-ai/ts-runtime/dist/index.js
21907
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.18+ea28d47622d670ff/node_modules/@gobing-ai/ts-runtime/dist/index.js
21907
21908
  init_file_system_node();
21908
21909
  init_config();
21909
21910
 
@@ -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.18/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.18/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.18/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.18/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.18/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.18/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.18+ea28d47622d670ff/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.18+ea28d47622d670ff/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);
@@ -22119,16 +22012,45 @@ __export(exports_chromium, {
22119
22012
  ChromiumComposer: () => ChromiumComposer
22120
22013
  });
22121
22014
  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;
22015
+ function serveCard(input) {
22016
+ const fontNames = [input.compose.fonts.headline, input.compose.fonts.body];
22017
+ let html = "";
22018
+ const server = Bun.serve({
22019
+ hostname: "127.0.0.1",
22020
+ port: 0,
22021
+ fetch: (request) => {
22022
+ const path2 = decodeURIComponent(new URL(request.url).pathname);
22023
+ if (path2 === "/")
22024
+ return new Response(html, { headers: { "content-type": "text/html; charset=utf-8" } });
22025
+ const name = path2.slice("/fonts/".length);
22026
+ if (path2.startsWith("/fonts/") && fontNames.includes(name)) {
22027
+ return new Response(Bun.file(join3(FONTS_DIR, name)), { headers: { "content-type": "font/otf" } });
22028
+ }
22029
+ return new Response("not found", { status: 404 });
22030
+ }
22031
+ });
22032
+ const url2 = `http://127.0.0.1:${server.port}/`;
22033
+ html = cardHtml(input, new Map(fontNames.map((name) => [name, `${url2}fonts/${encodeURIComponent(name)}`])));
22034
+ return { url: url2, stop: () => server.stop(true) };
22128
22035
  }
22129
22036
 
22130
22037
  class ChromiumComposer {
22038
+ timeoutMs;
22039
+ constructor(options = {}) {
22040
+ this.timeoutMs = options.timeoutMs ?? COMPOSE_TIMEOUT_MS;
22041
+ }
22131
22042
  async compose(input) {
22043
+ let timer;
22044
+ const deadline = new Promise((_, reject) => {
22045
+ timer = setTimeout(() => reject(new Error(`compose: Chromium did not finish within ${this.timeoutMs}ms (stalled launch)`)), this.timeoutMs);
22046
+ });
22047
+ try {
22048
+ return await Promise.race([this.render(input), deadline]);
22049
+ } finally {
22050
+ clearTimeout(timer);
22051
+ }
22052
+ }
22053
+ async render(input) {
22132
22054
  let chromium;
22133
22055
  try {
22134
22056
  const pw = await import("playwright");
@@ -22137,9 +22059,7 @@ class ChromiumComposer {
22137
22059
  throw new Error(`compose: Playwright is not installed. Run: bunx playwright install chromium
22138
22060
  (${err instanceof Error ? err.message : String(err)})`);
22139
22061
  }
22140
- const fontNames = [input.compose.fonts.headline, input.compose.fonts.body];
22141
- const fontUrls = fontRouteUrls(fontNames);
22142
- const html = cardHtml(input, fontUrls);
22062
+ const card = serveCard(input);
22143
22063
  let browser;
22144
22064
  try {
22145
22065
  try {
@@ -22153,22 +22073,7 @@ class ChromiumComposer {
22153
22073
  viewport: { width: input.width, height: input.height },
22154
22074
  deviceScaleFactor: 1
22155
22075
  });
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" });
22076
+ await page.goto(card.url, { waitUntil: "domcontentloaded" });
22172
22077
  await page.evaluate("document.fonts.ready");
22173
22078
  const { safeArea, illustrationHeight } = input.compose;
22174
22079
  const safeLeft = safeArea;
@@ -22199,15 +22104,15 @@ class ChromiumComposer {
22199
22104
  return new Uint8Array(screenshot);
22200
22105
  } finally {
22201
22106
  await browser?.close();
22107
+ card.stop();
22202
22108
  }
22203
22109
  }
22204
22110
  }
22205
22111
  function makeChromiumComposer() {
22206
22112
  return new ChromiumComposer;
22207
22113
  }
22208
- var FONTS_DIR, FONT_ROUTE_BASE = "http://kk-fonts.local/";
22114
+ var FONTS_DIR, COMPOSE_TIMEOUT_MS = 120000;
22209
22115
  var init_chromium = __esm(() => {
22210
- init_bytes();
22211
22116
  FONTS_DIR = join3(import.meta.dir, "..", "..", "assets", "fonts");
22212
22117
  });
22213
22118
 
@@ -22298,11 +22203,12 @@ var PluginManifestSchema = exports_external.looseObject({
22298
22203
  name: exports_external.string().min(1),
22299
22204
  kind: PluginKindSchema,
22300
22205
  entry: exports_external.string().min(1),
22206
+ check: exports_external.string().min(1).optional(),
22301
22207
  version: exports_external.string().optional(),
22302
22208
  description: exports_external.string().optional(),
22303
22209
  operations: exports_external.record(exports_external.string(), PluginOperationSchema).optional()
22304
22210
  });
22305
- // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.15/node_modules/@gobing-ai/ts-runtime/dist/index.js
22211
+ // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.18+ea28d47622d670ff/node_modules/@gobing-ai/ts-runtime/dist/index.js
22306
22212
  init_file_system_node();
22307
22213
  init_config();
22308
22214
 
@@ -22310,8 +22216,112 @@ init_config();
22310
22216
  if (false) {}
22311
22217
  // ../../plugins/generations/image-gen/src/index.ts
22312
22218
  init_dist();
22313
- init_bytes();
22314
22219
 
22220
+ // ../../plugins/generations/image-gen/src/bytes.ts
22221
+ import { readFile, writeFile } from "fs/promises";
22222
+ async function writeBytes(path2, bytes) {
22223
+ await writeFile(path2, bytes);
22224
+ }
22225
+ async function readBytes(path2) {
22226
+ return new Uint8Array(await readFile(path2));
22227
+ }
22228
+ function imageDimensions(bytes) {
22229
+ if (isPng(bytes))
22230
+ return pngDimensions(bytes);
22231
+ if (isJpeg(bytes))
22232
+ return jpegDimensions(bytes);
22233
+ if (isWebp(bytes))
22234
+ return webpDimensions(bytes);
22235
+ return null;
22236
+ }
22237
+ function isPng(b) {
22238
+ const PNG_SIG = [137, 80, 78, 71, 13, 10, 26, 10];
22239
+ if (b.byteLength < 24)
22240
+ return false;
22241
+ for (let i = 0;i < 8; i++) {
22242
+ if (b[i] !== PNG_SIG[i])
22243
+ return false;
22244
+ }
22245
+ return true;
22246
+ }
22247
+ function pngDimensions(b) {
22248
+ const view = new DataView(b.buffer, b.byteOffset, b.byteLength);
22249
+ const ihdrLength = view.getUint32(8, false);
22250
+ if (ihdrLength !== 13 || view.getUint32(12, false) !== 1229472850) {
22251
+ return null;
22252
+ }
22253
+ return { width: view.getUint32(16, false), height: view.getUint32(20, false) };
22254
+ }
22255
+ function isJpeg(b) {
22256
+ const view = new DataView(b.buffer, b.byteOffset, b.byteLength);
22257
+ return b.byteLength >= 4 && view.getUint16(0, false) === 65496 && view.getUint8(2) === 255;
22258
+ }
22259
+ function jpegDimensions(b) {
22260
+ const view = new DataView(b.buffer, b.byteOffset, b.byteLength);
22261
+ let at = 2;
22262
+ while (at + 4 <= b.byteLength) {
22263
+ if (view.getUint8(at) !== 255)
22264
+ return null;
22265
+ const marker = view.getUint8(at + 1);
22266
+ at += 2;
22267
+ if (marker === 1 || marker >= 208 && marker <= 215)
22268
+ continue;
22269
+ if (at + 2 > b.byteLength)
22270
+ return null;
22271
+ const length = view.getUint16(at, false);
22272
+ if (length < 2)
22273
+ return null;
22274
+ const isSof = marker >= 192 && marker <= 207 && marker !== 196 && marker !== 200 && marker !== 204;
22275
+ if (isSof) {
22276
+ if (at + 7 > b.byteLength)
22277
+ return null;
22278
+ return { height: view.getUint16(at + 3, false), width: view.getUint16(at + 5, false) };
22279
+ }
22280
+ at += length;
22281
+ }
22282
+ return null;
22283
+ }
22284
+ function isWebp(b) {
22285
+ if (b.byteLength < 20)
22286
+ return false;
22287
+ const view = new DataView(b.buffer, b.byteOffset, b.byteLength);
22288
+ return view.getUint32(0, true) === 1179011410 && view.getUint32(8, true) === 1346520407;
22289
+ }
22290
+ function webpDimensions(b) {
22291
+ const view = new DataView(b.buffer, b.byteOffset, b.byteLength);
22292
+ let at = 12;
22293
+ while (at + 8 <= b.byteLength) {
22294
+ const id = String.fromCharCode(view.getUint8(at), view.getUint8(at + 1), view.getUint8(at + 2), view.getUint8(at + 3));
22295
+ const size = view.getUint32(at + 4, true);
22296
+ const body = at + 8;
22297
+ if (id === "VP8 ") {
22298
+ if (size < 10 || body + 10 > b.byteLength)
22299
+ return null;
22300
+ if (view.getUint8(body + 3) !== 157 || view.getUint8(body + 4) !== 1 || view.getUint8(body + 5) !== 42) {
22301
+ return null;
22302
+ }
22303
+ return {
22304
+ width: view.getUint16(body + 6, true) & 16383,
22305
+ height: view.getUint16(body + 8, true) & 16383
22306
+ };
22307
+ }
22308
+ if (id === "VP8L") {
22309
+ if (size < 5 || body + 5 > b.byteLength || view.getUint8(body) !== 47)
22310
+ return null;
22311
+ const bits = view.getUint32(body + 1, true);
22312
+ return { width: (bits & 16383) + 1, height: (bits >>> 14 & 16383) + 1 };
22313
+ }
22314
+ if (id === "VP8X") {
22315
+ if (size < 10 || body + 10 > b.byteLength)
22316
+ return null;
22317
+ const width = view.getUint8(body + 4) | view.getUint8(body + 5) << 8 | view.getUint8(body + 6) << 16;
22318
+ const height = view.getUint8(body + 7) | view.getUint8(body + 8) << 8 | view.getUint8(body + 9) << 16;
22319
+ return { width: width + 1, height: height + 1 };
22320
+ }
22321
+ at = body + size + size % 2;
22322
+ }
22323
+ return null;
22324
+ }
22315
22325
  // ../../plugins/generations/image-gen/src/compose/cmap.ts
22316
22326
  function u16(view, offset) {
22317
22327
  return view.getUint16(offset, false);
@@ -22698,7 +22708,6 @@ function loadPresets() {
22698
22708
  import { Buffer as Buffer3 } from "buffer";
22699
22709
 
22700
22710
  // ../../plugins/generations/image-gen/src/providers/refs.ts
22701
- init_bytes();
22702
22711
  import { extname as extname2 } from "path";
22703
22712
  function mimeForPath(path2) {
22704
22713
  const ext = extname2(path2).toLowerCase();
@@ -22720,7 +22729,6 @@ async function refToDataUri(path2) {
22720
22729
  }
22721
22730
 
22722
22731
  // ../../plugins/generations/image-gen/src/providers/seedream.ts
22723
- init_bytes();
22724
22732
  import { Buffer as Buffer2 } from "buffer";
22725
22733
 
22726
22734
  // ../../plugins/generations/image-gen/src/providers/timeouts.ts
@@ -22919,11 +22927,9 @@ var createAgnes = (options) => {
22919
22927
  };
22920
22928
 
22921
22929
  // ../../plugins/generations/image-gen/src/providers/azure.ts
22922
- init_bytes();
22923
22930
  import { extname as extname3 } from "path";
22924
22931
 
22925
22932
  // ../../plugins/generations/image-gen/src/providers/openai.ts
22926
- init_bytes();
22927
22933
  import { Buffer as Buffer4 } from "buffer";
22928
22934
  import { basename as basename2 } from "path";
22929
22935
  var DEFAULT_MODEL3 = "gpt-image-2";
@@ -23333,7 +23339,6 @@ var createAzure = (options) => {
23333
23339
  };
23334
23340
 
23335
23341
  // ../../plugins/generations/image-gen/src/providers/codex-cli.ts
23336
- init_bytes();
23337
23342
  import { spawn } from "child_process";
23338
23343
  import { randomBytes } from "crypto";
23339
23344
  import { access as access2, mkdir, rm, writeFile as writeFile2 } from "fs/promises";
@@ -23858,7 +23863,6 @@ import { execFileSync } from "child_process";
23858
23863
  import { randomUUID } from "crypto";
23859
23864
  import { tmpdir as tmpdir2 } from "os";
23860
23865
  import { join as join2 } from "path";
23861
- init_bytes();
23862
23866
  var GOOGLE_MULTIMODAL_MODELS = [
23863
23867
  "gemini-3-pro-image",
23864
23868
  "gemini-3.1-flash-image",
@@ -24313,7 +24317,6 @@ var createJimeng = (options) => {
24313
24317
  };
24314
24318
 
24315
24319
  // ../../plugins/generations/image-gen/src/providers/minimax.ts
24316
- init_bytes();
24317
24320
  import { Buffer as Buffer7 } from "buffer";
24318
24321
  var DEFAULT_MODEL9 = "image-01";
24319
24322
  var MAX_REFERENCE_IMAGE_BYTES = 10 * 1024 * 1024;