@gobing-ai/knowledge-kit 0.1.13 → 0.1.15

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 (77) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/dist/index.js +796 -176
  3. package/package.json +1 -1
  4. package/plugins/generations/content-gen/dist/index.js +2 -2
  5. package/plugins/generations/core-facts-gen/dist/index.js +2 -2
  6. package/plugins/generations/daily-article-gen/dist/index.js +2 -2
  7. package/plugins/generations/dailynews-gen/dist/index.js +72 -9
  8. package/plugins/generations/dailynews-gen/src/index.ts +23 -1
  9. package/plugins/generations/dailynews-gen/src/script-plan.ts +103 -5
  10. package/plugins/generations/episode-plan-gen/dist/index.js +2 -2
  11. package/plugins/generations/gemini-tts/dist/index.js +2 -2
  12. package/plugins/generations/image-gen/dist/index.js +2 -2
  13. package/plugins/generations/news-report-gen/dist/index.js +2 -2
  14. package/plugins/generations/voice-gen/dist/index.js +2 -2
  15. package/plugins/generations/voxcpm-tts/dist/index.js +2 -2
  16. package/plugins/ingestions/aihot-ingest/dist/index.js +2 -2
  17. package/plugins/ingestions/horizon-ingest/dist/index.js +2 -2
  18. package/plugins/ingestions/last30days-ingest/dist/index.js +2 -2
  19. package/plugins/ingestions/web-search/dist/index.js +2 -2
  20. package/plugins/kk/plugin.json +1 -1
  21. package/plugins/kk/scripts/daily-scheduled-run.ts +53 -5
  22. package/plugins/kk/scripts/daily-stages.ts +476 -12
  23. package/plugins/kk/scripts/kk-workflow-stages.ts +20 -4
  24. package/plugins/kk/skills/content-judge/SKILL.md +5 -4
  25. package/plugins/kk/skills/content-judge/references/rubrics.md +14 -0
  26. package/plugins/kk/skills/news-editorial/SKILL.md +122 -0
  27. package/plugins/kk/skills/news-editorial/references/selection.md +47 -0
  28. package/plugins/kk/skills/news-editorial/references/style-contract.zh.md +99 -0
  29. package/plugins/kk/skills/publish/SKILL.md +3 -3
  30. package/plugins/kk/skills/web-automation/SKILL.md +229 -77
  31. package/plugins/kk/skills/web-automation/references/browser-launch.md +127 -36
  32. package/plugins/kk/workflows/kk-daily-ai-voice2.yaml +4 -6
  33. package/plugins/kk/workflows/kk-daily-ai-voice3.yaml +183 -222
  34. package/plugins/kk/workflows/kk-daily-publish3.yaml +16 -8
  35. package/plugins/publishings/bilibili-pub/dist/index.js +5 -3
  36. package/plugins/publishings/bilibili-pub/dist/profile-check.js +3 -1
  37. package/plugins/publishings/cnblogs-pub/dist/index.js +5 -3
  38. package/plugins/publishings/cnblogs-pub/dist/profile-check.js +3 -1
  39. package/plugins/publishings/csdn-pub/dist/index.js +5 -3
  40. package/plugins/publishings/csdn-pub/dist/profile-check.js +5 -3
  41. package/plugins/publishings/emdash-pub/dist/index.js +2 -2
  42. package/plugins/publishings/infoq-pub/dist/index.js +5 -3
  43. package/plugins/publishings/infoq-pub/dist/profile-check.js +5 -3
  44. package/plugins/publishings/jike-pub/dist/index.js +5 -3
  45. package/plugins/publishings/jike-pub/dist/profile-check.js +5 -3
  46. package/plugins/publishings/juejin-pub/dist/index.js +5 -3
  47. package/plugins/publishings/juejin-pub/dist/profile-check.js +5 -3
  48. package/plugins/publishings/linkedin-pub/dist/index.js +5 -3
  49. package/plugins/publishings/linkedin-pub/dist/profile-check.js +5 -3
  50. package/plugins/publishings/medium-pub/dist/index.js +2 -2
  51. package/plugins/publishings/podcast-pub/dist/index.js +147 -4
  52. package/plugins/publishings/podcast-pub/src/index.ts +71 -2
  53. package/plugins/publishings/podcast-pub/src/map.ts +3 -0
  54. package/plugins/publishings/podcast-pub/src/transcript.ts +195 -0
  55. package/plugins/publishings/qiita-pub/dist/index.js +2 -2
  56. package/plugins/publishings/shipinhao-pub/dist/index.js +5 -3
  57. package/plugins/publishings/shipinhao-pub/dist/profile-check.js +3 -1
  58. package/plugins/publishings/sspai-pub/dist/index.js +5 -3
  59. package/plugins/publishings/sspai-pub/dist/profile-check.js +3 -1
  60. package/plugins/publishings/substack-pub/dist/index.js +5 -3
  61. package/plugins/publishings/substack-pub/dist/profile-check.js +5 -3
  62. package/plugins/publishings/surfdash-pub/dist/index.js +2 -2
  63. package/plugins/publishings/threads-pub/dist/index.js +2 -2
  64. package/plugins/publishings/wechatmp-pub/dist/index.js +52 -33
  65. package/plugins/publishings/wechatmp-pub/dist/profile-check.js +5 -3
  66. package/plugins/publishings/wechatmp-pub/src/flow.ts +70 -33
  67. package/plugins/publishings/weibo-pub/dist/index.js +21 -6
  68. package/plugins/publishings/weibo-pub/dist/profile-check.js +5 -3
  69. package/plugins/publishings/weibo-pub/src/index.ts +31 -7
  70. package/plugins/publishings/x-pub/dist/index.js +5 -3
  71. package/plugins/publishings/x-pub/dist/profile-check.js +5 -3
  72. package/plugins/publishings/xhs-pub/dist/index.js +5 -3
  73. package/plugins/publishings/xhs-pub/dist/profile-check.js +5 -3
  74. package/plugins/publishings/xiaoyuzhou-pub/dist/index.js +5 -3
  75. package/plugins/publishings/xiaoyuzhou-pub/dist/profile-check.js +3 -1
  76. package/plugins/publishings/zenn-pub/dist/index.js +2 -2
  77. package/plugins/kk/scripts/daily-voice-style.zh.md +0 -70
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gobing-ai/knowledge-kit",
3
- "version": "0.1.13",
3
+ "version": "0.1.15",
4
4
  "description": "An ingest → create → publish content pipeline CLI (Bun).",
5
5
  "repository": {
6
6
  "type": "git",
@@ -12224,11 +12224,11 @@ var PluginManifestSchemaBase = looseObject({
12224
12224
  });
12225
12225
  var PluginManifestSchema = PluginManifestSchemaBase.superRefine((manifest, ctx) => {
12226
12226
  if (manifest.browserSession !== undefined) {
12227
- if (manifest.kind !== "publish") {
12227
+ if (manifest.kind !== "publish" && manifest.kind !== "ingestion") {
12228
12228
  ctx.addIssue({
12229
12229
  code: "custom",
12230
12230
  path: ["browserSession"],
12231
- message: `browserSession requires kind "publish", not "${manifest.kind}"`
12231
+ message: `browserSession requires kind "publish" or "ingestion", not "${manifest.kind}"`
12232
12232
  });
12233
12233
  }
12234
12234
  if (manifest.check === undefined) {
@@ -12225,11 +12225,11 @@ var PluginManifestSchemaBase = looseObject({
12225
12225
  });
12226
12226
  var PluginManifestSchema = PluginManifestSchemaBase.superRefine((manifest, ctx) => {
12227
12227
  if (manifest.browserSession !== undefined) {
12228
- if (manifest.kind !== "publish") {
12228
+ if (manifest.kind !== "publish" && manifest.kind !== "ingestion") {
12229
12229
  ctx.addIssue({
12230
12230
  code: "custom",
12231
12231
  path: ["browserSession"],
12232
- message: `browserSession requires kind "publish", not "${manifest.kind}"`
12232
+ message: `browserSession requires kind "publish" or "ingestion", not "${manifest.kind}"`
12233
12233
  });
12234
12234
  }
12235
12235
  if (manifest.check === undefined) {
@@ -12225,11 +12225,11 @@ var PluginManifestSchemaBase = looseObject({
12225
12225
  });
12226
12226
  var PluginManifestSchema = PluginManifestSchemaBase.superRefine((manifest, ctx) => {
12227
12227
  if (manifest.browserSession !== undefined) {
12228
- if (manifest.kind !== "publish") {
12228
+ if (manifest.kind !== "publish" && manifest.kind !== "ingestion") {
12229
12229
  ctx.addIssue({
12230
12230
  code: "custom",
12231
12231
  path: ["browserSession"],
12232
- message: `browserSession requires kind "publish", not "${manifest.kind}"`
12232
+ message: `browserSession requires kind "publish" or "ingestion", not "${manifest.kind}"`
12233
12233
  });
12234
12234
  }
12235
12235
  if (manifest.check === undefined) {
@@ -12225,11 +12225,11 @@ var PluginManifestSchemaBase = looseObject({
12225
12225
  });
12226
12226
  var PluginManifestSchema = PluginManifestSchemaBase.superRefine((manifest, ctx) => {
12227
12227
  if (manifest.browserSession !== undefined) {
12228
- if (manifest.kind !== "publish") {
12228
+ if (manifest.kind !== "publish" && manifest.kind !== "ingestion") {
12229
12229
  ctx.addIssue({
12230
12230
  code: "custom",
12231
12231
  path: ["browserSession"],
12232
- message: `browserSession requires kind "publish", not "${manifest.kind}"`
12232
+ message: `browserSession requires kind "publish" or "ingestion", not "${manifest.kind}"`
12233
12233
  });
12234
12234
  }
12235
12235
  if (manifest.check === undefined) {
@@ -12693,28 +12693,50 @@ function formatVoiceScriptToYaml(script) {
12693
12693
 
12694
12694
  // ../../plugins/generations/dailynews-gen/src/script-plan.ts
12695
12695
  init_zod();
12696
+ var ScriptPlanItemCardSchema = object({
12697
+ copy: string2().min(1),
12698
+ points: array(string2().min(1)).min(2).max(4),
12699
+ subject: string2().min(1)
12700
+ });
12696
12701
  var ScriptPlanItemSchema = object({
12697
12702
  id: string2().min(1),
12698
12703
  lead: string2().min(1),
12699
- insight: string2().min(1)
12704
+ insight: string2().min(1),
12705
+ card: ScriptPlanItemCardSchema.optional()
12700
12706
  });
12701
12707
  var ScriptPlanExclusionSchema = object({
12702
12708
  id: string2().min(1),
12703
12709
  reason: string2().min(1)
12704
12710
  });
12711
+ var ScriptPlanCardsSchema = object({
12712
+ title: string2().min(1),
12713
+ body: string2().min(1)
12714
+ });
12715
+ var ScriptPlanSocialSchema = object({
12716
+ short: string2().min(1),
12717
+ long: string2().min(1)
12718
+ });
12705
12719
  var ScriptPlanSchema = object({
12706
12720
  version: literal(1),
12707
12721
  intro: string2().min(1),
12708
12722
  outro: string2().min(1),
12709
12723
  items: array(ScriptPlanItemSchema),
12710
- excluded: array(ScriptPlanExclusionSchema).optional()
12724
+ excluded: array(ScriptPlanExclusionSchema).optional(),
12725
+ cover: string2().min(1).optional(),
12726
+ cards: ScriptPlanCardsSchema.optional(),
12727
+ social: ScriptPlanSocialSchema.optional()
12711
12728
  });
12712
12729
  var StyleContractSchema = object({
12713
12730
  caps: object({
12714
12731
  intro: number2().int().positive(),
12715
12732
  outro: number2().int().positive(),
12716
12733
  lead: number2().int().positive(),
12717
- insight: number2().int().positive()
12734
+ insight: number2().int().positive(),
12735
+ cover: number2().int().positive().optional(),
12736
+ cardCopy: number2().int().positive().optional(),
12737
+ cardTitle: number2().int().positive().optional(),
12738
+ socialShort: number2().int().positive().optional(),
12739
+ socialLong: number2().int().positive().optional()
12718
12740
  }),
12719
12741
  banned: array(string2().min(1))
12720
12742
  });
@@ -12750,7 +12772,7 @@ function redundantInsightClauses(insight, reference) {
12750
12772
  }
12751
12773
  return count;
12752
12774
  }
12753
- function validateScriptPlan(plan, docs, style) {
12775
+ function validateScriptPlan(plan, docs, style, preExcludedIds) {
12754
12776
  const parsed = ScriptPlanSchema.safeParse(plan);
12755
12777
  if (!parsed.success) {
12756
12778
  return { ok: false, errors: [{ itemId: "episode", rule: "schema" }] };
@@ -12765,8 +12787,9 @@ function validateScriptPlan(plan, docs, style) {
12765
12787
  const plannedIds = new Set(valid.items.map((item) => item.id));
12766
12788
  const excludedIds = new Set((valid.excluded ?? []).map((ex) => ex.id));
12767
12789
  for (const ex of valid.excluded ?? []) {
12768
- if (!docIds.has(ex.id))
12790
+ if (!docIds.has(ex.id) && !preExcludedIds?.has(ex.id)) {
12769
12791
  errors.push({ itemId: ex.id, rule: "unknown-id" });
12792
+ }
12770
12793
  if (plannedIds.has(ex.id))
12771
12794
  errors.push({ itemId: ex.id, rule: "conflict-id" });
12772
12795
  }
@@ -12778,11 +12801,28 @@ function validateScriptPlan(plan, docs, style) {
12778
12801
  errors.push({ itemId: "episode", rule: "cap:intro" });
12779
12802
  if (valid.outro.length > style.caps.outro)
12780
12803
  errors.push({ itemId: "episode", rule: "cap:outro" });
12804
+ if (valid.cover !== undefined && valid.cover.length > (style.caps.cover ?? 240)) {
12805
+ errors.push({ itemId: "episode", rule: "cap:cover" });
12806
+ }
12807
+ if (valid.cards !== undefined && valid.cards.title.length > (style.caps.cardTitle ?? 20)) {
12808
+ errors.push({ itemId: "episode", rule: "cap:cardTitle" });
12809
+ }
12810
+ if (valid.social !== undefined) {
12811
+ if (valid.social.short.length > (style.caps.socialShort ?? 140)) {
12812
+ errors.push({ itemId: "episode", rule: "cap:socialShort" });
12813
+ }
12814
+ if (valid.social.long.length > (style.caps.socialLong ?? 500)) {
12815
+ errors.push({ itemId: "episode", rule: "cap:socialLong" });
12816
+ }
12817
+ }
12781
12818
  for (const item of valid.items) {
12782
12819
  if (item.lead.length > style.caps.lead)
12783
12820
  errors.push({ itemId: item.id, rule: "cap:lead" });
12784
12821
  if (item.insight.length > style.caps.insight)
12785
12822
  errors.push({ itemId: item.id, rule: "cap:insight" });
12823
+ if (item.card !== undefined && item.card.copy.length > (style.caps.cardCopy ?? 12)) {
12824
+ errors.push({ itemId: item.id, rule: "cap:cardCopy" });
12825
+ }
12786
12826
  const doc = docs.find((entry) => entry.id === item.id);
12787
12827
  if (doc !== undefined && redundantInsightClauses(item.insight, `${item.lead}${doc.body}`) >= REDUNDANT_INSIGHT_CLAUSE_LIMIT) {
12788
12828
  errors.push({ itemId: item.id, rule: "redundant-insight" });
@@ -12791,9 +12831,22 @@ function validateScriptPlan(plan, docs, style) {
12791
12831
  const fields = [
12792
12832
  { itemId: "episode", text: valid.intro },
12793
12833
  { itemId: "episode", text: valid.outro },
12834
+ ...valid.cover !== undefined ? [{ itemId: "episode", text: valid.cover }] : [],
12835
+ ...valid.cards !== undefined ? [
12836
+ { itemId: "episode", text: valid.cards.title },
12837
+ { itemId: "episode", text: valid.cards.body }
12838
+ ] : [],
12839
+ ...valid.social !== undefined ? [
12840
+ { itemId: "episode", text: valid.social.short },
12841
+ { itemId: "episode", text: valid.social.long }
12842
+ ] : [],
12794
12843
  ...valid.items.flatMap((item) => [
12795
12844
  { itemId: item.id, text: item.lead },
12796
- { itemId: item.id, text: item.insight }
12845
+ { itemId: item.id, text: item.insight },
12846
+ ...item.card !== undefined ? [
12847
+ { itemId: item.id, text: item.card.copy },
12848
+ ...item.card.points.map((point) => ({ itemId: item.id, text: point }))
12849
+ ] : []
12797
12850
  ])
12798
12851
  ];
12799
12852
  for (const field of fields) {
@@ -12838,7 +12891,17 @@ async function resolveScriptPlan(fs, docs) {
12838
12891
  } catch {
12839
12892
  return fallback([{ itemId: "episode", rule: "schema" }]);
12840
12893
  }
12841
- const validated = validateScriptPlan(planJson, docs, style);
12894
+ let preExcludedIds;
12895
+ const curateExcludedPath = process.env.DAILYNEWS_CURATE_EXCLUDED;
12896
+ if (curateExcludedPath && await fs.exists(curateExcludedPath)) {
12897
+ try {
12898
+ const rawExcluded = JSON.parse(await fs.readFile(curateExcludedPath));
12899
+ if (Array.isArray(rawExcluded)) {
12900
+ preExcludedIds = new Set(rawExcluded.map((entry) => entry !== null && typeof entry === "object" && typeof entry.id === "string" ? entry.id : "").filter(Boolean));
12901
+ }
12902
+ } catch {}
12903
+ }
12904
+ const validated = validateScriptPlan(planJson, docs, style, preExcludedIds);
12842
12905
  if (!validated.ok) {
12843
12906
  return fallback(validated.errors);
12844
12907
  }
@@ -59,7 +59,29 @@ async function resolveScriptPlan(fs: FileSystem, docs: Doc[]): Promise<ScriptPla
59
59
  } catch {
60
60
  return fallback([{ itemId: 'episode', rule: 'schema' }]);
61
61
  }
62
- const validated = validateScriptPlan(planJson, docs, style);
62
+ let preExcludedIds: Set<string> | undefined;
63
+ const curateExcludedPath = process.env.DAILYNEWS_CURATE_EXCLUDED;
64
+ if (curateExcludedPath && (await fs.exists(curateExcludedPath))) {
65
+ try {
66
+ const rawExcluded = JSON.parse(await fs.readFile(curateExcludedPath));
67
+ if (Array.isArray(rawExcluded)) {
68
+ preExcludedIds = new Set(
69
+ rawExcluded
70
+ .map((entry: unknown) =>
71
+ entry !== null &&
72
+ typeof entry === 'object' &&
73
+ typeof (entry as { id?: unknown }).id === 'string'
74
+ ? (entry as { id: string }).id
75
+ : '',
76
+ )
77
+ .filter(Boolean),
78
+ );
79
+ }
80
+ } catch {
81
+ // Ignore malformed sidecar; validateScriptPlan will validate against docs.
82
+ }
83
+ }
84
+ const validated = validateScriptPlan(planJson, docs, style, preExcludedIds);
63
85
  if (!validated.ok) {
64
86
  return fallback(validated.errors);
65
87
  }
@@ -7,25 +7,55 @@ import { z } from 'zod';
7
7
  * (`docs/design/daily-voice-script-plan.md` §3). `version` is pinned so a future shape change
8
8
  * fails loud as `schema` instead of mis-substituting.
9
9
  */
10
+ export interface ScriptPlanItemCard {
11
+ copy: string;
12
+ points: string[];
13
+ subject: string;
14
+ }
15
+
16
+ export interface ScriptPlanCards {
17
+ title: string;
18
+ body: string;
19
+ }
20
+
21
+ export interface ScriptPlanSocial {
22
+ short: string;
23
+ long: string;
24
+ }
25
+
10
26
  export interface ScriptPlan {
11
27
  version: 1;
12
28
  intro: string;
13
29
  outro: string;
14
- items: { id: string; lead: string; insight: string }[];
30
+ items: { id: string; lead: string; insight: string; card?: ScriptPlanItemCard }[];
15
31
  /**
16
32
  * Docs deliberately not spoken (topic-boundary exclusions, task 0189). An id here is
17
33
  * exempt from `missing-item`; listing an id in both `items` and `excluded` is a
18
34
  * `conflict-id` error, and an unknown id is `unknown-id` like any plan item.
19
35
  */
20
36
  excluded?: { id: string; reason: string }[];
37
+ /** Optional master-artifact fields rendered deterministically by `daily-editorial-render` (0345 R10). */
38
+ cover?: string;
39
+ cards?: ScriptPlanCards;
40
+ social?: ScriptPlanSocial;
21
41
  }
22
42
 
23
43
  /**
24
- * Machine-readable part of the style sidecar `plugins/kk/scripts/daily-voice-style.zh.md` — the
44
+ * Machine-readable part of the style contract `plugins/kk/skills/news-editorial/references/style-contract.zh.md` (ADR-045) — the
25
45
  * same fenced `json` block the script-write prompt reads, so prompt and validator share one source.
26
46
  */
27
47
  export interface StyleContract {
28
- caps: { intro: number; outro: number; lead: number; insight: number };
48
+ caps: {
49
+ intro: number;
50
+ outro: number;
51
+ lead: number;
52
+ insight: number;
53
+ cover?: number;
54
+ cardCopy?: number;
55
+ cardTitle?: number;
56
+ socialShort?: number;
57
+ socialLong?: number;
58
+ };
29
59
  banned: string[];
30
60
  }
31
61
 
@@ -37,6 +67,12 @@ export interface ScriptPlanError {
37
67
 
38
68
  export type ScriptPlanValidation = { ok: true; plan: ScriptPlan } | { ok: false; errors: ScriptPlanError[] };
39
69
 
70
+ const ScriptPlanItemCardSchema = z.object({
71
+ copy: z.string().min(1),
72
+ points: z.array(z.string().min(1)).min(2).max(4),
73
+ subject: z.string().min(1),
74
+ });
75
+
40
76
  /**
41
77
  * Empty spoken text is a shape error (`schema`), not a cap/banned case: an empty intro or insight
42
78
  * would normalize to a bare 「。」 segment, which no valid episode contains.
@@ -45,6 +81,7 @@ const ScriptPlanItemSchema = z.object({
45
81
  id: z.string().min(1),
46
82
  lead: z.string().min(1),
47
83
  insight: z.string().min(1),
84
+ card: ScriptPlanItemCardSchema.optional(),
48
85
  });
49
86
 
50
87
  const ScriptPlanExclusionSchema = z.object({
@@ -52,12 +89,25 @@ const ScriptPlanExclusionSchema = z.object({
52
89
  reason: z.string().min(1),
53
90
  });
54
91
 
92
+ const ScriptPlanCardsSchema = z.object({
93
+ title: z.string().min(1),
94
+ body: z.string().min(1),
95
+ });
96
+
97
+ const ScriptPlanSocialSchema = z.object({
98
+ short: z.string().min(1),
99
+ long: z.string().min(1),
100
+ });
101
+
55
102
  const ScriptPlanSchema = z.object({
56
103
  version: z.literal(1),
57
104
  intro: z.string().min(1),
58
105
  outro: z.string().min(1),
59
106
  items: z.array(ScriptPlanItemSchema),
60
107
  excluded: z.array(ScriptPlanExclusionSchema).optional(),
108
+ cover: z.string().min(1).optional(),
109
+ cards: ScriptPlanCardsSchema.optional(),
110
+ social: ScriptPlanSocialSchema.optional(),
61
111
  });
62
112
 
63
113
  const StyleContractSchema = z.object({
@@ -66,6 +116,11 @@ const StyleContractSchema = z.object({
66
116
  outro: z.number().int().positive(),
67
117
  lead: z.number().int().positive(),
68
118
  insight: z.number().int().positive(),
119
+ cover: z.number().int().positive().optional(),
120
+ cardCopy: z.number().int().positive().optional(),
121
+ cardTitle: z.number().int().positive().optional(),
122
+ socialShort: z.number().int().positive().optional(),
123
+ socialLong: z.number().int().positive().optional(),
69
124
  }),
70
125
  banned: z.array(z.string().min(1)),
71
126
  });
@@ -131,7 +186,12 @@ function redundantInsightClauses(insight: string, reference: string): number {
131
186
  }
132
187
  return count;
133
188
  }
134
- export function validateScriptPlan(plan: unknown, docs: Doc[], style: StyleContract): ScriptPlanValidation {
189
+ export function validateScriptPlan(
190
+ plan: unknown,
191
+ docs: Doc[],
192
+ style: StyleContract,
193
+ preExcludedIds?: ReadonlySet<string>,
194
+ ): ScriptPlanValidation {
135
195
  const parsed = ScriptPlanSchema.safeParse(plan);
136
196
  if (!parsed.success) {
137
197
  return { ok: false, errors: [{ itemId: 'episode', rule: 'schema' }] };
@@ -146,7 +206,9 @@ export function validateScriptPlan(plan: unknown, docs: Doc[], style: StyleContr
146
206
  const plannedIds = new Set(valid.items.map((item) => item.id));
147
207
  const excludedIds = new Set((valid.excluded ?? []).map((ex) => ex.id));
148
208
  for (const ex of valid.excluded ?? []) {
149
- if (!docIds.has(ex.id)) errors.push({ itemId: ex.id, rule: 'unknown-id' });
209
+ if (!docIds.has(ex.id) && !preExcludedIds?.has(ex.id)) {
210
+ errors.push({ itemId: ex.id, rule: 'unknown-id' });
211
+ }
150
212
  if (plannedIds.has(ex.id)) errors.push({ itemId: ex.id, rule: 'conflict-id' });
151
213
  }
152
214
  for (const doc of docs) {
@@ -155,9 +217,26 @@ export function validateScriptPlan(plan: unknown, docs: Doc[], style: StyleContr
155
217
 
156
218
  if (valid.intro.length > style.caps.intro) errors.push({ itemId: 'episode', rule: 'cap:intro' });
157
219
  if (valid.outro.length > style.caps.outro) errors.push({ itemId: 'episode', rule: 'cap:outro' });
220
+ if (valid.cover !== undefined && valid.cover.length > (style.caps.cover ?? 240)) {
221
+ errors.push({ itemId: 'episode', rule: 'cap:cover' });
222
+ }
223
+ if (valid.cards !== undefined && valid.cards.title.length > (style.caps.cardTitle ?? 20)) {
224
+ errors.push({ itemId: 'episode', rule: 'cap:cardTitle' });
225
+ }
226
+ if (valid.social !== undefined) {
227
+ if (valid.social.short.length > (style.caps.socialShort ?? 140)) {
228
+ errors.push({ itemId: 'episode', rule: 'cap:socialShort' });
229
+ }
230
+ if (valid.social.long.length > (style.caps.socialLong ?? 500)) {
231
+ errors.push({ itemId: 'episode', rule: 'cap:socialLong' });
232
+ }
233
+ }
158
234
  for (const item of valid.items) {
159
235
  if (item.lead.length > style.caps.lead) errors.push({ itemId: item.id, rule: 'cap:lead' });
160
236
  if (item.insight.length > style.caps.insight) errors.push({ itemId: item.id, rule: 'cap:insight' });
237
+ if (item.card !== undefined && item.card.copy.length > (style.caps.cardCopy ?? 12)) {
238
+ errors.push({ itemId: item.id, rule: 'cap:cardCopy' });
239
+ }
161
240
  const doc = docs.find((entry) => entry.id === item.id);
162
241
  // unknown-id is already reported above; skip the redundancy check rather than double-report.
163
242
  if (
@@ -171,9 +250,28 @@ export function validateScriptPlan(plan: unknown, docs: Doc[], style: StyleContr
171
250
  const fields: { itemId: string; text: string }[] = [
172
251
  { itemId: 'episode', text: valid.intro },
173
252
  { itemId: 'episode', text: valid.outro },
253
+ ...(valid.cover !== undefined ? [{ itemId: 'episode', text: valid.cover }] : []),
254
+ ...(valid.cards !== undefined
255
+ ? [
256
+ { itemId: 'episode', text: valid.cards.title },
257
+ { itemId: 'episode', text: valid.cards.body },
258
+ ]
259
+ : []),
260
+ ...(valid.social !== undefined
261
+ ? [
262
+ { itemId: 'episode', text: valid.social.short },
263
+ { itemId: 'episode', text: valid.social.long },
264
+ ]
265
+ : []),
174
266
  ...valid.items.flatMap((item) => [
175
267
  { itemId: item.id, text: item.lead },
176
268
  { itemId: item.id, text: item.insight },
269
+ ...(item.card !== undefined
270
+ ? [
271
+ { itemId: item.id, text: item.card.copy },
272
+ ...item.card.points.map((point) => ({ itemId: item.id, text: point })),
273
+ ]
274
+ : []),
177
275
  ]),
178
276
  ];
179
277
  for (const field of fields) {
@@ -12225,11 +12225,11 @@ var PluginManifestSchemaBase = looseObject({
12225
12225
  });
12226
12226
  var PluginManifestSchema = PluginManifestSchemaBase.superRefine((manifest, ctx) => {
12227
12227
  if (manifest.browserSession !== undefined) {
12228
- if (manifest.kind !== "publish") {
12228
+ if (manifest.kind !== "publish" && manifest.kind !== "ingestion") {
12229
12229
  ctx.addIssue({
12230
12230
  code: "custom",
12231
12231
  path: ["browserSession"],
12232
- message: `browserSession requires kind "publish", not "${manifest.kind}"`
12232
+ message: `browserSession requires kind "publish" or "ingestion", not "${manifest.kind}"`
12233
12233
  });
12234
12234
  }
12235
12235
  if (manifest.check === undefined) {
@@ -12228,11 +12228,11 @@ var PluginManifestSchemaBase = looseObject({
12228
12228
  });
12229
12229
  var PluginManifestSchema = PluginManifestSchemaBase.superRefine((manifest, ctx) => {
12230
12230
  if (manifest.browserSession !== undefined) {
12231
- if (manifest.kind !== "publish") {
12231
+ if (manifest.kind !== "publish" && manifest.kind !== "ingestion") {
12232
12232
  ctx.addIssue({
12233
12233
  code: "custom",
12234
12234
  path: ["browserSession"],
12235
- message: `browserSession requires kind "publish", not "${manifest.kind}"`
12235
+ message: `browserSession requires kind "publish" or "ingestion", not "${manifest.kind}"`
12236
12236
  });
12237
12237
  }
12238
12238
  if (manifest.check === undefined) {
@@ -12566,11 +12566,11 @@ var PluginManifestSchemaBase = looseObject({
12566
12566
  });
12567
12567
  var PluginManifestSchema = PluginManifestSchemaBase.superRefine((manifest, ctx) => {
12568
12568
  if (manifest.browserSession !== undefined) {
12569
- if (manifest.kind !== "publish") {
12569
+ if (manifest.kind !== "publish" && manifest.kind !== "ingestion") {
12570
12570
  ctx.addIssue({
12571
12571
  code: "custom",
12572
12572
  path: ["browserSession"],
12573
- message: `browserSession requires kind "publish", not "${manifest.kind}"`
12573
+ message: `browserSession requires kind "publish" or "ingestion", not "${manifest.kind}"`
12574
12574
  });
12575
12575
  }
12576
12576
  if (manifest.check === undefined) {
@@ -12225,11 +12225,11 @@ var PluginManifestSchemaBase = looseObject({
12225
12225
  });
12226
12226
  var PluginManifestSchema = PluginManifestSchemaBase.superRefine((manifest, ctx) => {
12227
12227
  if (manifest.browserSession !== undefined) {
12228
- if (manifest.kind !== "publish") {
12228
+ if (manifest.kind !== "publish" && manifest.kind !== "ingestion") {
12229
12229
  ctx.addIssue({
12230
12230
  code: "custom",
12231
12231
  path: ["browserSession"],
12232
- message: `browserSession requires kind "publish", not "${manifest.kind}"`
12232
+ message: `browserSession requires kind "publish" or "ingestion", not "${manifest.kind}"`
12233
12233
  });
12234
12234
  }
12235
12235
  if (manifest.check === undefined) {
@@ -12225,11 +12225,11 @@ var PluginManifestSchemaBase = looseObject({
12225
12225
  });
12226
12226
  var PluginManifestSchema = PluginManifestSchemaBase.superRefine((manifest, ctx) => {
12227
12227
  if (manifest.browserSession !== undefined) {
12228
- if (manifest.kind !== "publish") {
12228
+ if (manifest.kind !== "publish" && manifest.kind !== "ingestion") {
12229
12229
  ctx.addIssue({
12230
12230
  code: "custom",
12231
12231
  path: ["browserSession"],
12232
- message: `browserSession requires kind "publish", not "${manifest.kind}"`
12232
+ message: `browserSession requires kind "publish" or "ingestion", not "${manifest.kind}"`
12233
12233
  });
12234
12234
  }
12235
12235
  if (manifest.check === undefined) {
@@ -12228,11 +12228,11 @@ var PluginManifestSchemaBase = looseObject({
12228
12228
  });
12229
12229
  var PluginManifestSchema = PluginManifestSchemaBase.superRefine((manifest, ctx) => {
12230
12230
  if (manifest.browserSession !== undefined) {
12231
- if (manifest.kind !== "publish") {
12231
+ if (manifest.kind !== "publish" && manifest.kind !== "ingestion") {
12232
12232
  ctx.addIssue({
12233
12233
  code: "custom",
12234
12234
  path: ["browserSession"],
12235
- message: `browserSession requires kind "publish", not "${manifest.kind}"`
12235
+ message: `browserSession requires kind "publish" or "ingestion", not "${manifest.kind}"`
12236
12236
  });
12237
12237
  }
12238
12238
  if (manifest.check === undefined) {
@@ -12477,11 +12477,11 @@ var PluginManifestSchemaBase = looseObject({
12477
12477
  });
12478
12478
  var PluginManifestSchema = PluginManifestSchemaBase.superRefine((manifest, ctx) => {
12479
12479
  if (manifest.browserSession !== undefined) {
12480
- if (manifest.kind !== "publish") {
12480
+ if (manifest.kind !== "publish" && manifest.kind !== "ingestion") {
12481
12481
  ctx.addIssue({
12482
12482
  code: "custom",
12483
12483
  path: ["browserSession"],
12484
- message: `browserSession requires kind "publish", not "${manifest.kind}"`
12484
+ message: `browserSession requires kind "publish" or "ingestion", not "${manifest.kind}"`
12485
12485
  });
12486
12486
  }
12487
12487
  if (manifest.check === undefined) {
@@ -12226,11 +12226,11 @@ var PluginManifestSchemaBase = looseObject({
12226
12226
  });
12227
12227
  var PluginManifestSchema = PluginManifestSchemaBase.superRefine((manifest, ctx) => {
12228
12228
  if (manifest.browserSession !== undefined) {
12229
- if (manifest.kind !== "publish") {
12229
+ if (manifest.kind !== "publish" && manifest.kind !== "ingestion") {
12230
12230
  ctx.addIssue({
12231
12231
  code: "custom",
12232
12232
  path: ["browserSession"],
12233
- message: `browserSession requires kind "publish", not "${manifest.kind}"`
12233
+ message: `browserSession requires kind "publish" or "ingestion", not "${manifest.kind}"`
12234
12234
  });
12235
12235
  }
12236
12236
  if (manifest.check === undefined) {
@@ -12227,11 +12227,11 @@ var PluginManifestSchemaBase = looseObject({
12227
12227
  });
12228
12228
  var PluginManifestSchema = PluginManifestSchemaBase.superRefine((manifest, ctx) => {
12229
12229
  if (manifest.browserSession !== undefined) {
12230
- if (manifest.kind !== "publish") {
12230
+ if (manifest.kind !== "publish" && manifest.kind !== "ingestion") {
12231
12231
  ctx.addIssue({
12232
12232
  code: "custom",
12233
12233
  path: ["browserSession"],
12234
- message: `browserSession requires kind "publish", not "${manifest.kind}"`
12234
+ message: `browserSession requires kind "publish" or "ingestion", not "${manifest.kind}"`
12235
12235
  });
12236
12236
  }
12237
12237
  if (manifest.check === undefined) {
@@ -12246,11 +12246,11 @@ var PluginManifestSchemaBase = looseObject({
12246
12246
  });
12247
12247
  var PluginManifestSchema = PluginManifestSchemaBase.superRefine((manifest, ctx) => {
12248
12248
  if (manifest.browserSession !== undefined) {
12249
- if (manifest.kind !== "publish") {
12249
+ if (manifest.kind !== "publish" && manifest.kind !== "ingestion") {
12250
12250
  ctx.addIssue({
12251
12251
  code: "custom",
12252
12252
  path: ["browserSession"],
12253
- message: `browserSession requires kind "publish", not "${manifest.kind}"`
12253
+ message: `browserSession requires kind "publish" or "ingestion", not "${manifest.kind}"`
12254
12254
  });
12255
12255
  }
12256
12256
  if (manifest.check === undefined) {
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "kk",
3
- "version": "0.1.13",
3
+ "version": "0.1.15",
4
4
  "description": "knowledge-kit Claude Code plugin: skills, commands, subagents, hooks, and rules"
5
5
  }