@gobing-ai/knowledge-kit 0.0.21 → 0.0.22

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 (59) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/dist/index.js +161 -142
  3. package/package.json +1 -1
  4. package/plugins/generations/content-gen/dist/index.js +20 -3
  5. package/plugins/generations/core-facts-gen/dist/index.js +20 -3
  6. package/plugins/generations/daily-article-gen/dist/index.js +20 -3
  7. package/plugins/generations/dailynews-gen/dist/index.js +20 -3
  8. package/plugins/generations/episode-plan-gen/dist/index.js +20 -3
  9. package/plugins/generations/image-gen/dist/index.js +147 -69
  10. package/plugins/generations/image-gen/src/presets.ts +2 -2
  11. package/plugins/generations/image-gen/src/providers/agnes.ts +6 -2
  12. package/plugins/generations/image-gen/src/providers/azure.ts +6 -2
  13. package/plugins/generations/image-gen/src/providers/dashscope.ts +10 -3
  14. package/plugins/generations/image-gen/src/providers/google.ts +70 -29
  15. package/plugins/generations/image-gen/src/providers/huggingface.ts +3 -0
  16. package/plugins/generations/image-gen/src/providers/jimeng.ts +9 -2
  17. package/plugins/generations/image-gen/src/providers/minimax.ts +10 -2
  18. package/plugins/generations/image-gen/src/providers/openai.ts +9 -3
  19. package/plugins/generations/image-gen/src/providers/openrouter.ts +16 -4
  20. package/plugins/generations/image-gen/src/providers/replicate.ts +13 -3
  21. package/plugins/generations/image-gen/src/providers/seedream.ts +4 -1
  22. package/plugins/generations/image-gen/src/providers/timeouts.ts +14 -0
  23. package/plugins/generations/image-gen/src/providers/types.ts +10 -0
  24. package/plugins/generations/image-gen/src/providers/zai.ts +4 -1
  25. package/plugins/generations/news-report-gen/dist/index.js +20 -3
  26. package/plugins/generations/voice-gen/dist/index.js +36 -10
  27. package/plugins/generations/voice-gen/src/voicebox-client.ts +18 -4
  28. package/plugins/generations/voice-gen/src/voicebox-server.ts +2 -1
  29. package/plugins/ingestions/aihot-ingest/dist/index.js +25 -5
  30. package/plugins/ingestions/aihot-ingest/src/client.ts +5 -0
  31. package/plugins/ingestions/horizon-ingest/dist/index.js +20 -3
  32. package/plugins/ingestions/last30days-ingest/dist/index.js +20 -3
  33. package/plugins/ingestions/web-search/dist/index.js +22 -3
  34. package/plugins/ingestions/web-search/src/index.ts +4 -0
  35. package/plugins/kk/plugin.json +1 -1
  36. package/plugins/kk/scripts/kk-workflow-stages.ts +35 -7
  37. package/plugins/kk/scripts/render-md.ts +7 -1
  38. package/plugins/publishings/emdash-pub/dist/index.js +76 -19
  39. package/plugins/publishings/emdash-pub/src/index.ts +4 -0
  40. package/plugins/publishings/infoq-pub/dist/index.js +74 -21
  41. package/plugins/publishings/juejin-pub/dist/index.js +74 -21
  42. package/plugins/publishings/medium-pub/dist/index.js +77 -19
  43. package/plugins/publishings/medium-pub/src/index.ts +5 -0
  44. package/plugins/publishings/podcast-pub/dist/index.js +130 -34
  45. package/plugins/publishings/podcast-pub/src/index.ts +20 -5
  46. package/plugins/publishings/podcast-pub/src/map.ts +11 -0
  47. package/plugins/publishings/podcast-pub/src/show-notes.ts +66 -13
  48. package/plugins/publishings/qiita-pub/dist/index.js +75 -18
  49. package/plugins/publishings/qiita-pub/src/index.ts +4 -0
  50. package/plugins/publishings/substack-pub/dist/index.js +74 -21
  51. package/plugins/publishings/surfdash-pub/dist/index.js +99 -62
  52. package/plugins/publishings/surfdash-pub/src/index.ts +60 -19
  53. package/plugins/publishings/wechatmp-pub/dist/index.js +79 -22
  54. package/plugins/publishings/wechatmp-pub/src/index.ts +12 -3
  55. package/plugins/publishings/x-pub/dist/index.js +56 -37
  56. package/plugins/publishings/x-pub/src/index.ts +4 -0
  57. package/plugins/publishings/xhs-pub/dist/index.js +74 -21
  58. package/plugins/publishings/zenn-pub/dist/index.js +103 -25
  59. package/plugins/publishings/zenn-pub/src/index.ts +43 -9
@@ -6,7 +6,7 @@
6
6
  },
7
7
  "plugins": [
8
8
  {
9
- "version": "0.0.21",
9
+ "version": "0.0.22",
10
10
  "name": "kk",
11
11
  "source": "./plugins/kk",
12
12
  "description": "knowledge-kit — a set of toolkit for knowledge management"
package/dist/index.js CHANGED
@@ -25984,6 +25984,22 @@ var ResultSchema = exports_external.object({
25984
25984
  error: exports_external.string().optional(),
25985
25985
  metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
25986
25986
  });
25987
+ var TargetOutcomeSchema = exports_external.object({
25988
+ target: exports_external.string(),
25989
+ ok: exports_external.boolean(),
25990
+ status: exports_external.enum(["published", "failed", "skipped"]),
25991
+ url: exports_external.string().optional(),
25992
+ id: exports_external.string().optional(),
25993
+ error: exports_external.string().optional(),
25994
+ durationMs: exports_external.number().optional(),
25995
+ metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
25996
+ });
25997
+ var AggregateResultSchema = exports_external.object({
25998
+ ok: exports_external.boolean(),
25999
+ summary: exports_external.object({ total: exports_external.number(), succeeded: exports_external.number(), failed: exports_external.number(), skipped: exports_external.number() }),
26000
+ targets: exports_external.array(TargetOutcomeSchema),
26001
+ metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
26002
+ });
25987
26003
  var DocListSchema = exports_external.array(DocSchema);
25988
26004
  var omniVoiceGenContentSchema = ContentSchema.extend({
25989
26005
  format: exports_external.literal("audio"),
@@ -26024,10 +26040,7 @@ function collectionForKind(kind) {
26024
26040
  return PLUGIN_KIND_COLLECTIONS[kind];
26025
26041
  }
26026
26042
  function kindForCollection(name) {
26027
- if (name in PLUGIN_COLLECTION_KINDS) {
26028
- return PLUGIN_COLLECTION_KINDS[name];
26029
- }
26030
- return;
26043
+ return Object.hasOwn(PLUGIN_COLLECTION_KINDS, name) ? PLUGIN_COLLECTION_KINDS[name] : undefined;
26031
26044
  }
26032
26045
  var CONTRACTS = {
26033
26046
  ingestion: { kind: "ingestion", input: null, output: DocListSchema },
@@ -26046,18 +26059,19 @@ function isPluginKind(value) {
26046
26059
  // ../../packages/kk-core/src/manifest.ts
26047
26060
  init_zod();
26048
26061
  var OperationIOSchema = exports_external.enum(["doc-list", "markdown"]);
26049
- var PluginManifestSchema = exports_external.object({
26062
+ var PluginOperationSchema = exports_external.object({ input: OperationIOSchema, output: OperationIOSchema });
26063
+ var PluginManifestSchema = exports_external.looseObject({
26050
26064
  name: exports_external.string().min(1),
26051
26065
  kind: PluginKindSchema,
26052
26066
  entry: exports_external.string().min(1),
26053
26067
  version: exports_external.string().optional(),
26054
26068
  description: exports_external.string().optional(),
26055
- operations: exports_external.record(exports_external.string(), exports_external.object({ input: OperationIOSchema, output: OperationIOSchema })).optional()
26056
- }).passthrough();
26069
+ operations: exports_external.record(exports_external.string(), PluginOperationSchema).optional()
26070
+ });
26057
26071
  // ../../packages/kk-core/src/registry.ts
26058
26072
  import { existsSync, readdirSync, readFileSync, realpathSync, statSync } from "fs";
26059
26073
  import { homedir } from "os";
26060
- import { basename, dirname, join, resolve } from "path";
26074
+ import { basename, delimiter, dirname, join, resolve } from "path";
26061
26075
  import { fileURLToPath } from "url";
26062
26076
  function discoverPlugins(pluginsRoot, origin = "path") {
26063
26077
  const absRoot = resolve(pluginsRoot);
@@ -26106,23 +26120,29 @@ function resolvePluginRoots(opts = {}) {
26106
26120
  if (builtinRoot !== undefined) {
26107
26121
  roots.push({ origin: "builtin", root: builtinRoot });
26108
26122
  }
26123
+ const base = opts.cwd ?? process.cwd();
26109
26124
  const userRoot = join(opts.homeDir ?? homedir(), ".config", "kk", "plugins");
26110
26125
  if (isDirectory(userRoot)) {
26111
26126
  roots.push({ origin: "user", root: userRoot });
26112
26127
  }
26113
- const projectRoot = join(opts.cwd ?? process.cwd(), "plugins");
26128
+ const projectRoot = join(base, "plugins");
26114
26129
  if (isDirectory(projectRoot) && !(builtinRoot !== undefined && sameRealpath(projectRoot, builtinRoot))) {
26115
26130
  roots.push({ origin: "project", root: projectRoot });
26116
26131
  }
26117
26132
  const env = opts.env ?? process.env;
26118
- for (const entry of (env.KK_PLUGIN_PATH ?? "").split(":").filter((e) => e !== "")) {
26119
- if (isDirectory(entry)) {
26120
- roots.push({ origin: "path", root: entry });
26133
+ for (const entry of (env.KK_PLUGIN_PATH ?? "").split(delimiter).filter((e) => e !== "")) {
26134
+ const abs = resolve(base, entry);
26135
+ if (isDirectory(abs)) {
26136
+ roots.push({ origin: "path", root: abs });
26121
26137
  }
26122
26138
  }
26123
26139
  for (const extra of opts.extraPaths ?? []) {
26124
- if (extra !== "" && isDirectory(extra)) {
26125
- roots.push({ origin: "path", root: extra });
26140
+ if (extra === "") {
26141
+ continue;
26142
+ }
26143
+ const abs = resolve(base, extra);
26144
+ if (isDirectory(abs)) {
26145
+ roots.push({ origin: "path", root: abs });
26126
26146
  }
26127
26147
  }
26128
26148
  return roots;
@@ -26173,13 +26193,13 @@ function mergeByName(record2, byName, diagnostics) {
26173
26193
  byName.set(record2.name, record2);
26174
26194
  }
26175
26195
  function resolveBuiltinRoot(injected) {
26176
- if (injected !== undefined) {
26177
- return injected;
26178
- }
26179
- let dir = dirname(fileURLToPath(import.meta.url));
26196
+ return injected ?? findBuiltinRoot(dirname(fileURLToPath(import.meta.url)));
26197
+ }
26198
+ function findBuiltinRoot(startDir) {
26199
+ let dir = startDir;
26180
26200
  for (;; ) {
26181
26201
  const candidate = join(dir, "plugins");
26182
- if (isPluginsTree(candidate)) {
26202
+ if (existsSync(join(dir, "package.json")) && isPluginsTree(candidate)) {
26183
26203
  return candidate;
26184
26204
  }
26185
26205
  const parent = dirname(dir);
@@ -26344,6 +26364,25 @@ if (false) {}
26344
26364
  import { existsSync as existsSync3, readFileSync as readFileSync3, statSync as statSync3, unlinkSync } from "fs";
26345
26365
  import { homedir as homedir2 } from "os";
26346
26366
  import { isAbsolute, join as join2, resolve as resolve2 } from "path";
26367
+
26368
+ // src/plugin-output.ts
26369
+ function formatIssues(error51) {
26370
+ return error51.issues.map((i) => `${i.path.map(String).join(".") || "root"}: ${i.message}`).join("; ");
26371
+ }
26372
+ async function readPluginJson(fs2, path3, schema, label, violation) {
26373
+ let json2;
26374
+ try {
26375
+ json2 = JSON.parse(await fs2.readFile(path3));
26376
+ } catch (err) {
26377
+ throw new Error(`${label} wrote invalid JSON: ${err instanceof Error ? err.message : String(err)}`);
26378
+ }
26379
+ const parsed = schema.safeParse(json2);
26380
+ if (!parsed.success)
26381
+ throw new Error(`${label} ${violation}: ${formatIssues(parsed.error)}`);
26382
+ return parsed.data;
26383
+ }
26384
+
26385
+ // src/invoke.ts
26347
26386
  function resolveKkConfigPath() {
26348
26387
  return process.env.KK_CONFIG || join2(homedir2(), ".config/kk/config.yaml");
26349
26388
  }
@@ -26479,6 +26518,13 @@ async function spawnPluginEntryAsync(opts) {
26479
26518
  ...timedOut ? { timedOut: true } : {}
26480
26519
  };
26481
26520
  }
26521
+ function isSameFile(a, b) {
26522
+ if (!existsSync3(b))
26523
+ return false;
26524
+ const sa = statSync3(a);
26525
+ const sb = statSync3(b);
26526
+ return sa.dev === sb.dev && sa.ino === sb.ino;
26527
+ }
26482
26528
  async function runInvoke(opts) {
26483
26529
  const discovery = discoverAllPlugins({ pluginsRoot: opts.pluginsRoot, extraPaths: opts.pluginsPath });
26484
26530
  const record2 = getByName(discovery, opts.plugin);
@@ -26494,7 +26540,7 @@ async function runInvoke(opts) {
26494
26540
  const contract = kindContract(record2.kind);
26495
26541
  const absInPath = resolve2(opts.inPath);
26496
26542
  const absOutPath = resolve2(opts.outPath);
26497
- if (existsSync3(absInPath) && absInPath === absOutPath) {
26543
+ if (existsSync3(absInPath) && (absInPath === absOutPath || isSameFile(absInPath, absOutPath))) {
26498
26544
  echoError(`--in and --out alias the same path (${absInPath}); refusing to overwrite the input`);
26499
26545
  return 1;
26500
26546
  }
@@ -26526,16 +26572,14 @@ async function runInvoke(opts) {
26526
26572
  }
26527
26573
  const docs = DocListSchema.safeParse(json2);
26528
26574
  if (!docs.success) {
26529
- const issues = docs.error.issues.map((i) => `${i.path.join(".") || "root"}: ${i.message}`).join("; ");
26530
- echoError(`Input schema violation for the declared doc-list operation of '${record2.name}': ${issues}`);
26575
+ echoError(`Input schema violation for the declared doc-list operation of '${record2.name}': ${formatIssues(docs.error)}`);
26531
26576
  return 1;
26532
26577
  }
26533
26578
  artifactOutput = op.output === "markdown";
26534
26579
  } else {
26535
26580
  const parseResult = contract.input.safeParse(json2);
26536
26581
  if (!parseResult.success) {
26537
- const issues = parseResult.error.issues.map((i) => `${i.path.join(".") || "root"}: ${i.message}`).join("; ");
26538
- echoError(`Input schema violation for kind '${record2.kind}': ${issues}`);
26582
+ echoError(`Input schema violation for kind '${record2.kind}': ${formatIssues(parseResult.error)}`);
26539
26583
  return 1;
26540
26584
  }
26541
26585
  }
@@ -26569,8 +26613,7 @@ async function runInvoke(opts) {
26569
26613
  if (proc.exitCode !== 0) {
26570
26614
  const errMsg = proc.stderr || proc.stdout || `Plugin entry exited with code ${proc.exitCode}`;
26571
26615
  echoError(`Plugin entry '${record2.name}' failed (exit code ${proc.exitCode}): ${errMsg}`);
26572
- const exitCode = proc.exitCode !== 0 ? proc.exitCode : 1;
26573
- return exitCode;
26616
+ return proc.exitCode;
26574
26617
  }
26575
26618
  if (!existsSync3(absOutPath)) {
26576
26619
  echoError(`Plugin entry succeeded but did not write output file: ${absOutPath}`);
@@ -26599,8 +26642,7 @@ async function runInvoke(opts) {
26599
26642
  }
26600
26643
  const outResult = contract.output.safeParse(outJson);
26601
26644
  if (!outResult.success) {
26602
- const issues = outResult.error.issues.map((i) => `${i.path.join(".") || "root"}: ${i.message}`).join("; ");
26603
- echoError(`Output schema violation for kind '${record2.kind}': ${issues}`);
26645
+ echoError(`Output schema violation for kind '${record2.kind}': ${formatIssues(outResult.error)}`);
26604
26646
  return 1;
26605
26647
  }
26606
26648
  const parsed = outResult.data;
@@ -26672,8 +26714,7 @@ async function readDocList(fs2, path3) {
26672
26714
  }
26673
26715
  const result = DocListSchema.safeParse(json2);
26674
26716
  if (!result.success) {
26675
- const issues = result.error.issues.map((i) => `${i.path.join(".") || "root"}: ${i.message}`).join("; ");
26676
- echoError(`Input file ${path3} violates the Doc list schema: ${issues}`);
26717
+ echoError(`Input file ${path3} violates the Doc list schema: ${formatIssues(result.error)}`);
26677
26718
  return null;
26678
26719
  }
26679
26720
  return result.data;
@@ -26684,6 +26725,8 @@ function parseArgs(argv) {
26684
26725
  let outPath;
26685
26726
  let sourceTimeoutMs;
26686
26727
  const sourceTimeoutOverrides = {};
26728
+ let pluginsRoot;
26729
+ const pluginsPath = [];
26687
26730
  for (let i = 0;i < argv.length; i++) {
26688
26731
  const arg = argv[i];
26689
26732
  if (arg === "--in") {
@@ -26742,6 +26785,21 @@ function parseArgs(argv) {
26742
26785
  throw new Error("--out may be specified only once");
26743
26786
  }
26744
26787
  outPath = value;
26788
+ } else if (arg === "--plugins-root") {
26789
+ const value = argv[++i];
26790
+ if (value === undefined) {
26791
+ throw new Error("--plugins-root requires a directory path");
26792
+ }
26793
+ if (pluginsRoot !== undefined) {
26794
+ throw new Error("--plugins-root may be specified only once");
26795
+ }
26796
+ pluginsRoot = value;
26797
+ } else if (arg === "--plugins-path") {
26798
+ const value = argv[++i];
26799
+ if (value === undefined) {
26800
+ throw new Error("--plugins-path requires a directory path");
26801
+ }
26802
+ pluginsPath.push(value);
26745
26803
  } else {
26746
26804
  throw new Error(`Unknown argument: ${arg}`);
26747
26805
  }
@@ -26768,7 +26826,9 @@ function parseArgs(argv) {
26768
26826
  outPath,
26769
26827
  ...sources.length > 0 ? { sources } : {},
26770
26828
  ...sourceTimeoutMs !== undefined ? { sourceTimeoutMs } : {},
26771
- ...Object.keys(sourceTimeoutOverrides).length > 0 ? { sourceTimeoutOverrides } : {}
26829
+ ...Object.keys(sourceTimeoutOverrides).length > 0 ? { sourceTimeoutOverrides } : {},
26830
+ ...pluginsRoot !== undefined ? { pluginsRoot } : {},
26831
+ ...pluginsPath.length > 0 ? { pluginsPath } : {}
26772
26832
  };
26773
26833
  }
26774
26834
  async function collectSourceDocs(discovery, source, timeoutMs) {
@@ -26806,18 +26866,7 @@ async function collectSourceDocs(discovery, source, timeoutMs) {
26806
26866
  if (!await fs2.exists(outTmp)) {
26807
26867
  throw new Error(`Plugin '${source.plugin}' succeeded but did not write an output file`);
26808
26868
  }
26809
- let json2;
26810
- try {
26811
- json2 = JSON.parse(await fs2.readFile(outTmp));
26812
- } catch (err) {
26813
- throw new Error(`Plugin '${source.plugin}' wrote invalid JSON: ${err instanceof Error ? err.message : String(err)}`);
26814
- }
26815
- const parsed = DocListSchema.safeParse(json2);
26816
- if (!parsed.success) {
26817
- const issues = parsed.error.issues.map((i) => `${i.path.join(".") || "root"}: ${i.message}`).join("; ");
26818
- throw new Error(`Plugin '${source.plugin}' output violates the Doc list schema: ${issues}`);
26819
- }
26820
- return parsed.data;
26869
+ return readPluginJson(fs2, outTmp, DocListSchema, `Plugin '${source.plugin}'`, "output violates the Doc list schema");
26821
26870
  } finally {
26822
26871
  await fs2.deleteFile(outTmp);
26823
26872
  }
@@ -26830,6 +26879,10 @@ async function runFanin(argv) {
26830
26879
  echoError(`fanin: ${err instanceof Error ? err.message : String(err)}`);
26831
26880
  return EXIT_USAGE;
26832
26881
  }
26882
+ if (opts.pluginsRoot !== undefined && (opts.pluginsPath?.length ?? 0) > 0) {
26883
+ echoError("fanin: --plugins-root and --plugins-path are mutually exclusive (ADR-012 R6)");
26884
+ return EXIT_USAGE;
26885
+ }
26833
26886
  const fs2 = createNodeFileSystem();
26834
26887
  const inputs = [];
26835
26888
  const sources = [];
@@ -26843,7 +26896,7 @@ async function runFanin(argv) {
26843
26896
  sources.push(inPath);
26844
26897
  }
26845
26898
  if (opts.sources !== undefined && opts.sources.length > 0) {
26846
- const discovery = discoverAllPlugins({});
26899
+ const discovery = discoverAllPlugins({ pluginsRoot: opts.pluginsRoot, extraPaths: opts.pluginsPath });
26847
26900
  const settled = await Promise.allSettled(opts.sources.map(async (source) => {
26848
26901
  const started = Date.now();
26849
26902
  try {
@@ -26973,12 +27026,34 @@ async function readContent(fs2, path3) {
26973
27026
  }
26974
27027
  const result = ContentSchema.safeParse(json2);
26975
27028
  if (!result.success) {
26976
- const issues = result.error.issues.map((i) => `${i.path.join(".") || "root"}: ${i.message}`).join("; ");
26977
- echoError(`Content file ${path3} violates the Content schema: ${issues}`);
27029
+ echoError(`Content file ${path3} violates the Content schema: ${formatIssues(result.error)}`);
26978
27030
  return null;
26979
27031
  }
26980
27032
  return result.data;
26981
27033
  }
27034
+ function describeAggregateIssue(json2, issue2) {
27035
+ if (issue2 === undefined)
27036
+ return " (ok/summary/targets)";
27037
+ const path3 = issue2.path.map(String);
27038
+ const targets = json2.targets;
27039
+ const targetName = (index) => {
27040
+ const entry = Array.isArray(targets) ? targets[index] : undefined;
27041
+ if (typeof entry !== "object" || entry === null)
27042
+ return "undefined";
27043
+ return String(entry.target);
27044
+ };
27045
+ if (path3[0] === "targets" && path3.length >= 2) {
27046
+ const index = Number(path3[1]);
27047
+ if (path3.length === 2)
27048
+ return " (target entry)";
27049
+ if (path3[2] === "metadata")
27050
+ return `: target '${targetName(index)}' metadata must be an object`;
27051
+ return ` (target ${targetName(index)})`;
27052
+ }
27053
+ if (path3[0] === "summary" && path3.length >= 2)
27054
+ return ` (summary.${path3[1]})`;
27055
+ return " (ok/summary/targets)";
27056
+ }
26982
27057
  async function readAggregateResult(fs2, path3) {
26983
27058
  if (!await fs2.exists(path3)) {
26984
27059
  echoError(`Result file does not exist: ${path3}`);
@@ -26998,63 +27073,16 @@ async function readAggregateResult(fs2, path3) {
26998
27073
  echoError(`Result file ${path3} is invalid JSON: ${err instanceof Error ? err.message : String(err)}`);
26999
27074
  return null;
27000
27075
  }
27001
- if (typeof json2 !== "object" || json2 === null) {
27076
+ if (typeof json2 !== "object" || json2 === null || Array.isArray(json2)) {
27002
27077
  echoError(`Result file ${path3} is not an aggregate result object`);
27003
27078
  return null;
27004
27079
  }
27005
- const obj = json2;
27006
- const summary = obj.summary;
27007
- if (typeof obj.ok !== "boolean" || typeof summary !== "object" || summary === null || !Array.isArray(obj.targets)) {
27008
- echoError(`Result file ${path3} violates the aggregate result schema (ok/summary/targets)`);
27080
+ const parsed = AggregateResultSchema.safeParse(json2);
27081
+ if (!parsed.success) {
27082
+ echoError(`Result file ${path3} violates the aggregate result schema${describeAggregateIssue(json2, parsed.error.issues[0])}`);
27009
27083
  return null;
27010
27084
  }
27011
- const sum = summary;
27012
- for (const key of ["total", "succeeded", "failed", "skipped"]) {
27013
- if (typeof sum[key] !== "number") {
27014
- echoError(`Result file ${path3} violates the aggregate result schema (summary.${key})`);
27015
- return null;
27016
- }
27017
- }
27018
- const targets = [];
27019
- for (const entry of obj.targets) {
27020
- if (typeof entry !== "object" || entry === null) {
27021
- echoError(`Result file ${path3} violates the aggregate result schema (target entry)`);
27022
- return null;
27023
- }
27024
- const t = entry;
27025
- if (typeof t.target !== "string" || typeof t.ok !== "boolean" || t.status !== "published" && t.status !== "failed" && t.status !== "skipped") {
27026
- echoError(`Result file ${path3} violates the aggregate result schema (target ${String(t.target)})`);
27027
- return null;
27028
- }
27029
- let metadata;
27030
- if (t.metadata !== undefined) {
27031
- if (typeof t.metadata !== "object" || t.metadata === null || Array.isArray(t.metadata)) {
27032
- echoError(`Result file ${path3} violates the aggregate result schema: target '${String(t.target)}' metadata must be an object`);
27033
- return null;
27034
- }
27035
- metadata = t.metadata;
27036
- }
27037
- targets.push({
27038
- target: t.target,
27039
- ok: t.ok,
27040
- status: t.status,
27041
- ...typeof t.url === "string" ? { url: t.url } : {},
27042
- ...typeof t.id === "string" ? { id: t.id } : {},
27043
- ...typeof t.error === "string" ? { error: t.error } : {},
27044
- ...typeof t.durationMs === "number" ? { durationMs: t.durationMs } : {},
27045
- ...metadata !== undefined ? { metadata } : {}
27046
- });
27047
- }
27048
- return {
27049
- ok: obj.ok,
27050
- summary: {
27051
- total: sum.total,
27052
- succeeded: sum.succeeded,
27053
- failed: sum.failed,
27054
- skipped: sum.skipped
27055
- },
27056
- targets
27057
- };
27085
+ return parsed.data;
27058
27086
  }
27059
27087
  function parseArgs2(argv) {
27060
27088
  const targets = [];
@@ -27161,12 +27189,7 @@ async function pluginDispatch(target, contentPath, discovery) {
27161
27189
  if (!await fs2.exists(outTmp)) {
27162
27190
  throw new Error(`Plugin '${target}' succeeded but did not write a result file`);
27163
27191
  }
27164
- const parsed = ResultSchema.safeParse(JSON.parse(await fs2.readFile(outTmp)));
27165
- if (!parsed.success) {
27166
- const issues = parsed.error.issues.map((i) => `${i.path.join(".") || "root"}: ${i.message}`).join("; ");
27167
- throw new Error(`Plugin '${target}' wrote an invalid Result: ${issues}`);
27168
- }
27169
- return parsed.data;
27192
+ return readPluginJson(fs2, outTmp, ResultSchema, `Plugin '${target}'`, "wrote an invalid Result");
27170
27193
  } finally {
27171
27194
  await fs2.deleteFile(outTmp);
27172
27195
  }
@@ -27209,7 +27232,7 @@ async function runFanout(argv, deps = {}) {
27209
27232
  const discovery = discoverAllPlugins({ pluginsRoot, extraPaths: opts.pluginsPath });
27210
27233
  let prior;
27211
27234
  let skipped = [];
27212
- let targets = opts.targets;
27235
+ let targets = [...new Set(opts.targets)];
27213
27236
  let retainedFailed = [];
27214
27237
  if (opts.retryFromPath !== undefined) {
27215
27238
  const parsed = await readAggregateResult(fs2, opts.retryFromPath);
@@ -27253,7 +27276,7 @@ async function runFanout(argv, deps = {}) {
27253
27276
  }
27254
27277
 
27255
27278
  // src/commands/executor.ts
27256
- function collectPath(value, acc) {
27279
+ function collectRepeatable(value, acc) {
27257
27280
  acc.push(value);
27258
27281
  return acc;
27259
27282
  }
@@ -27272,14 +27295,6 @@ async function runInvokeAction(plugin, options) {
27272
27295
  throw new CommanderError(code, "kk.executor.run.failed", `invoke failed with exit code ${code}`);
27273
27296
  }
27274
27297
  }
27275
- function collectIn(value, acc) {
27276
- acc.push(value);
27277
- return acc;
27278
- }
27279
- function collectSource(value, acc) {
27280
- acc.push(value);
27281
- return acc;
27282
- }
27283
27298
  async function runFaninAction(options) {
27284
27299
  const argv = [];
27285
27300
  for (const inPath of options.in) {
@@ -27295,19 +27310,17 @@ async function runFaninAction(options) {
27295
27310
  argv.push("--source-timeout-override", override);
27296
27311
  }
27297
27312
  argv.push("--out", options.out);
27313
+ if (options.pluginsRoot !== undefined) {
27314
+ argv.push("--plugins-root", options.pluginsRoot);
27315
+ }
27316
+ for (const path3 of options.pluginsPath ?? []) {
27317
+ argv.push("--plugins-path", path3);
27318
+ }
27298
27319
  const code = await runFanin(argv);
27299
27320
  if (code !== 0) {
27300
27321
  throw new CommanderError(code, "kk.executor.fanin.failed", `fan-in failed with exit code ${code}`);
27301
27322
  }
27302
27323
  }
27303
- function collectTarget(value, acc) {
27304
- acc.push(value);
27305
- return acc;
27306
- }
27307
- function collectOverride(value, acc) {
27308
- acc.push(value);
27309
- return acc;
27310
- }
27311
27324
  async function runFanoutAction(options) {
27312
27325
  const argv = ["--content", options.content, "--out", options.out];
27313
27326
  for (const target of options.target) {
@@ -27327,14 +27340,23 @@ async function runFanoutAction(options) {
27327
27340
  throw new CommanderError(code, "kk.executor.fanout.failed", `fan-out failed with exit code ${code}`);
27328
27341
  }
27329
27342
  }
27343
+ function withRunOptions(cmd) {
27344
+ return cmd.requiredOption("--in <path>", "Input file path (or source path for ingestion)").requiredOption("--out <path>", "Output file path").option("--plugins-root <dir>", "Exclusive root containing plugins (isolation/tests only)").option("--plugins-path <dir>", "Extra plugin root to union with defaults (repeatable)", collectRepeatable, []);
27345
+ }
27346
+ function withFaninOptions(cmd) {
27347
+ return cmd.option("--in <path>", "Input Doc[] JSON file (repeatable)", collectRepeatable, []).option("--source <plugin>:<file>", "Ingestion source to spawn concurrently: plugin name and its input file (repeatable)", collectRepeatable, []).option("--source-timeout <ms>", "Per-source timeout in milliseconds (default 1800000)").option("--source-timeout-override <plugin>:<ms>", "Per-source timeout override for one named --source plugin, e.g. horizon-ingest:2700000 (repeatable; wins over --source-timeout/default)", collectRepeatable, []).requiredOption("--out <path>", "Output merged Doc[] JSON file path").option("--plugins-root <dir>", "Exclusive root containing plugins (isolation/tests only)").option("--plugins-path <dir>", "Extra plugin root to union with defaults (repeatable)", collectRepeatable, []);
27348
+ }
27349
+ function withFanoutOptions(cmd) {
27350
+ return cmd.requiredOption("--content <path>", "Source ContentSchema JSON file path").option("--target <plugin>", "Target publish plugin name (repeatable)", collectRepeatable, []).requiredOption("--out <path>", "Aggregate Result JSON file path").option("--retry-from <path>", "Prior Result JSON file to retry only previously failed targets").option("--plugins-root <dir>", "Exclusive root containing plugins (isolation/tests only)").option("--plugins-path <dir>", "Extra plugin root to union with defaults (repeatable)", collectRepeatable, []);
27351
+ }
27330
27352
  function registerExecutorCommand(program2) {
27331
27353
  const executor = program2.command("executor").description("Run knowledge-kit plugin steps (invoke, fan-in, fan-out)");
27332
- executor.command("run").description("Invoke a plugin with input/output files and contract validation").argument("<plugin>", "Name of the plugin to invoke").requiredOption("--in <path>", "Input file path (or source path for ingestion)").requiredOption("--out <path>", "Output file path").option("--plugins-root <dir>", "Exclusive root containing plugins (isolation/tests only)").option("--plugins-path <dir>", "Extra plugin root to union with defaults (repeatable)", collectPath, []).action(runInvokeAction);
27333
- executor.command("fan-in").alias("fanin").description("Merge N Doc[] JSON inputs into one deduplicated Doc[] output").option("--in <path>", "Input Doc[] JSON file (repeatable)", collectIn, []).option("--source <plugin>:<file>", "Ingestion source to spawn concurrently: plugin name and its input file (repeatable)", collectSource, []).option("--source-timeout <ms>", "Per-source timeout in milliseconds (default 1800000)").option("--source-timeout-override <plugin>:<ms>", "Per-source timeout override for one named --source plugin, e.g. horizon-ingest:2700000 (repeatable; wins over --source-timeout/default)", collectOverride, []).requiredOption("--out <path>", "Output merged Doc[] JSON file path").action(runFaninAction);
27334
- executor.command("fan-out").alias("fanout").description("Publish one Content JSON to N targets, aggregating per-target results").requiredOption("--content <path>", "Source ContentSchema JSON file path").option("--target <plugin>", "Target publish plugin name (repeatable)", collectTarget, []).requiredOption("--out <path>", "Aggregate Result JSON file path").option("--retry-from <path>", "Prior Result JSON file to retry only previously failed targets").option("--plugins-root <dir>", "Exclusive root containing plugins (isolation/tests only)").option("--plugins-path <dir>", "Extra plugin root to union with defaults (repeatable)", collectPath, []).action(runFanoutAction);
27335
- program2.command("invoke", { hidden: true }).description("Alias for `executor run` (deprecated)").argument("<plugin>", "Name of the plugin to invoke").requiredOption("--in <path>", "Input file path (or source path for ingestion)").requiredOption("--out <path>", "Output file path").option("--plugins-root <dir>", "Exclusive root containing plugins (isolation/tests only)").option("--plugins-path <dir>", "Extra plugin root to union with defaults (repeatable)", collectPath, []).action(runInvokeAction);
27336
- program2.command("fanin", { hidden: true }).description("Alias for `executor fan-in` (deprecated)").option("--in <path>", "Input Doc[] JSON file (repeatable)", collectIn, []).option("--source <plugin>:<file>", "Ingestion source to spawn concurrently: plugin name and its input file (repeatable)", collectSource, []).option("--source-timeout <ms>", "Per-source timeout in milliseconds (default 1800000)").option("--source-timeout-override <plugin>:<ms>", "Per-source timeout override for one named --source plugin, e.g. horizon-ingest:2700000 (repeatable; wins over --source-timeout/default)", collectOverride, []).requiredOption("--out <path>", "Output merged Doc[] JSON file path").action(runFaninAction);
27337
- program2.command("fanout", { hidden: true }).description("Alias for `executor fan-out` (deprecated)").requiredOption("--content <path>", "Source ContentSchema JSON file path").option("--target <plugin>", "Target publish plugin name (repeatable)", collectTarget, []).requiredOption("--out <path>", "Aggregate Result JSON file path").option("--retry-from <path>", "Prior Result JSON file to retry only previously failed targets").option("--plugins-root <dir>", "Exclusive root containing plugins (isolation/tests only)").option("--plugins-path <dir>", "Extra plugin root to union with defaults (repeatable)", collectPath, []).action(runFanoutAction);
27354
+ withRunOptions(executor.command("run").description("Invoke a plugin with input/output files and contract validation").argument("<plugin>", "Name of the plugin to invoke")).action(runInvokeAction);
27355
+ withFaninOptions(executor.command("fan-in").alias("fanin").description("Merge N Doc[] JSON inputs into one deduplicated Doc[] output")).action(runFaninAction);
27356
+ withFanoutOptions(executor.command("fan-out").alias("fanout").description("Publish one Content JSON to N targets, aggregating per-target results")).action(runFanoutAction);
27357
+ withRunOptions(program2.command("invoke", { hidden: true }).description("Alias for `executor run` (deprecated)").argument("<plugin>", "Name of the plugin to invoke")).action(runInvokeAction);
27358
+ withFaninOptions(program2.command("fanin", { hidden: true }).description("Alias for `executor fan-in` (deprecated)")).action(runFaninAction);
27359
+ withFanoutOptions(program2.command("fanout", { hidden: true }).description("Alias for `executor fan-out` (deprecated)")).action(runFanoutAction);
27338
27360
  }
27339
27361
 
27340
27362
  // src/commands/plugin.ts
@@ -27355,7 +27377,7 @@ var consoleOutput = {
27355
27377
  };
27356
27378
 
27357
27379
  // src/commands/plugin.ts
27358
- function collectPath2(value, acc) {
27380
+ function collectPath(value, acc) {
27359
27381
  acc.push(value);
27360
27382
  return acc;
27361
27383
  }
@@ -27384,25 +27406,21 @@ function printDiagnostics(report) {
27384
27406
  for (const p of report.plugins) {
27385
27407
  all.push(...p.diagnostics);
27386
27408
  }
27387
- echoError(`Found ${all.length} diagnostic issue(s):
27388
- `);
27409
+ echoError(`Found ${all.length} diagnostic issue(s):`);
27389
27410
  for (const d of all) {
27390
- echoError(` [${d.code}] ${d.path}: ${d.reason}
27391
- `);
27411
+ echoError(` [${d.code}] ${d.path}: ${d.reason}`);
27392
27412
  }
27393
27413
  }
27394
27414
  function statusAction(options) {
27395
27415
  if (options.pluginsRoot !== undefined && (options.pluginsPath?.length ?? 0) > 0) {
27396
- echoError(`--plugins-root and --plugins-path are mutually exclusive (ADR-012 R6)
27397
- `);
27416
+ echoError("--plugins-root and --plugins-path are mutually exclusive (ADR-012 R6)");
27398
27417
  throw new CommanderError(2, "kk.plugin.root-path-conflict", "--plugins-root and --plugins-path are mutually exclusive");
27399
27418
  }
27400
27419
  const report = buildStatusReport({ pluginsRoot: options.pluginsRoot, pluginsPath: options.pluginsPath });
27401
27420
  let records = report.plugins;
27402
27421
  if (options.kind) {
27403
27422
  if (!isPluginKind(options.kind)) {
27404
- echoError(`Invalid plugin kind: ${options.kind}
27405
- `);
27423
+ echoError(`Invalid plugin kind: ${options.kind}`);
27406
27424
  throw new CommanderError(1, "kk.plugin.invalid-kind", `invalid plugin kind: ${options.kind}`);
27407
27425
  }
27408
27426
  records = report.plugins.filter((p) => p.kind === options.kind);
@@ -27446,7 +27464,7 @@ function statusAction(options) {
27446
27464
  }
27447
27465
  }
27448
27466
  function registerStatusVerb(parent, name, description, hidden) {
27449
- parent.command(name, { hidden }).description(description).option("--kind <kind>", "Filter plugins by kind (ingestion, generator, publish)").option("--json", "Output machine-readable unified health report").option("--plugins-root <dir>", "Exclusive root containing plugins (isolation/tests only)").option("--plugins-path <dir>", "Extra plugin root to union with defaults (repeatable)", collectPath2, []).action(statusAction);
27467
+ parent.command(name, { hidden }).description(description).option("--kind <kind>", "Filter plugins by kind (ingestion, generator, publish)").option("--json", "Output machine-readable unified health report").option("--plugins-root <dir>", "Exclusive root containing plugins (isolation/tests only)").option("--plugins-path <dir>", "Extra plugin root to union with defaults (repeatable)", collectPath, []).action(statusAction);
27450
27468
  }
27451
27469
  function registerPluginCommand(program2) {
27452
27470
  const plugin = program2.command("plugin").description("Inspect and validate knowledge-kit plugins");
@@ -27464,7 +27482,8 @@ import { spawnSync } from "child_process";
27464
27482
  import { existsSync as existsSync5, realpathSync as realpathSync3 } from "fs";
27465
27483
  import { dirname as dirname3, join as join5, resolve as resolve6 } from "path";
27466
27484
  var STAGES_REL = "plugins/kk/scripts/kk-workflow-stages.ts";
27467
- function resolveStagesScript(argv1 = process.argv[1]) {
27485
+ var CHECKOUT_ROOT = resolve6(import.meta.dir, "../../..");
27486
+ function resolveStagesScript(argv1 = process.argv[1], checkoutRoot = CHECKOUT_ROOT) {
27468
27487
  let fromPkg = "";
27469
27488
  if (argv1) {
27470
27489
  try {
@@ -27475,9 +27494,9 @@ function resolveStagesScript(argv1 = process.argv[1]) {
27475
27494
  }
27476
27495
  if (fromPkg && existsSync5(fromPkg))
27477
27496
  return fromPkg;
27478
- const fromCwd = resolve6(STAGES_REL);
27479
- if (existsSync5(fromCwd))
27480
- return fromCwd;
27497
+ const fromCheckout = join5(checkoutRoot, STAGES_REL);
27498
+ if (existsSync5(fromCheckout))
27499
+ return fromCheckout;
27481
27500
  throw new Error(`kk-workflow-stages.ts not found at ${fromPkg || STAGES_REL} \u2014 install or refresh the kk package (bun link in a checkout)`);
27482
27501
  }
27483
27502
  function runStage(args, execPath = process.execPath, argv1) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gobing-ai/knowledge-kit",
3
- "version": "0.0.21",
3
+ "version": "0.0.22",
4
4
  "description": "An ingest → create → publish content pipeline CLI (Bun).",
5
5
  "repository": {
6
6
  "type": "git",
@@ -21780,6 +21780,22 @@ var ResultSchema = exports_external.object({
21780
21780
  error: exports_external.string().optional(),
21781
21781
  metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
21782
21782
  });
21783
+ var TargetOutcomeSchema = exports_external.object({
21784
+ target: exports_external.string(),
21785
+ ok: exports_external.boolean(),
21786
+ status: exports_external.enum(["published", "failed", "skipped"]),
21787
+ url: exports_external.string().optional(),
21788
+ id: exports_external.string().optional(),
21789
+ error: exports_external.string().optional(),
21790
+ durationMs: exports_external.number().optional(),
21791
+ metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
21792
+ });
21793
+ var AggregateResultSchema = exports_external.object({
21794
+ ok: exports_external.boolean(),
21795
+ summary: exports_external.object({ total: exports_external.number(), succeeded: exports_external.number(), failed: exports_external.number(), skipped: exports_external.number() }),
21796
+ targets: exports_external.array(TargetOutcomeSchema),
21797
+ metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
21798
+ });
21783
21799
  var DocListSchema = exports_external.array(DocSchema);
21784
21800
  var omniVoiceGenContentSchema = ContentSchema.extend({
21785
21801
  format: exports_external.literal("audio"),
@@ -21808,14 +21824,15 @@ var PluginKindSchema = exports_external.enum(PLUGIN_KINDS);
21808
21824
  // ../../packages/kk-core/src/manifest.ts
21809
21825
  init_zod();
21810
21826
  var OperationIOSchema = exports_external.enum(["doc-list", "markdown"]);
21811
- var PluginManifestSchema = exports_external.object({
21827
+ var PluginOperationSchema = exports_external.object({ input: OperationIOSchema, output: OperationIOSchema });
21828
+ var PluginManifestSchema = exports_external.looseObject({
21812
21829
  name: exports_external.string().min(1),
21813
21830
  kind: PluginKindSchema,
21814
21831
  entry: exports_external.string().min(1),
21815
21832
  version: exports_external.string().optional(),
21816
21833
  description: exports_external.string().optional(),
21817
- operations: exports_external.record(exports_external.string(), exports_external.object({ input: OperationIOSchema, output: OperationIOSchema })).optional()
21818
- }).passthrough();
21834
+ operations: exports_external.record(exports_external.string(), PluginOperationSchema).optional()
21835
+ });
21819
21836
  // ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.39/node_modules/@gobing-ai/ts-runtime/dist/index.js
21820
21837
  init_file_system_node();
21821
21838
  init_config();