@gobing-ai/knowledge-kit 0.0.17 → 0.0.19

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 (76) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/README.md +74 -0
  3. package/dist/index.js +108 -107
  4. package/package.json +19 -1
  5. package/plugins/generations/content-gen/dist/index.js +42 -94
  6. package/plugins/generations/core-facts-gen/dist/index.js +51 -100
  7. package/plugins/generations/daily-article-gen/dist/index.js +57 -99
  8. package/plugins/generations/daily-article-gen/src/index.ts +12 -4
  9. package/plugins/generations/dailynews-gen/dist/index.js +57 -102
  10. package/plugins/generations/dailynews-gen/src/script-builder.ts +9 -1
  11. package/plugins/generations/episode-plan-gen/dist/index.js +120 -113
  12. package/plugins/generations/episode-plan-gen/src/index.ts +102 -22
  13. package/plugins/generations/image-gen/dist/index.js +63 -115
  14. package/plugins/generations/news-report-gen/dist/index.js +117 -99
  15. package/plugins/generations/news-report-gen/src/index.ts +117 -1
  16. package/plugins/generations/omni-voice-gen/src/omni_voice_gen/pipeline.py +1 -1
  17. package/plugins/generations/omni-voice-gen/src/omni_voice_gen/voicescript.py +8 -0
  18. package/plugins/generations/voice-gen/dist/index.js +161 -120
  19. package/plugins/generations/voice-gen/src/concat.ts +34 -0
  20. package/plugins/generations/voice-gen/src/index.ts +14 -4
  21. package/plugins/generations/voice-gen/src/voicebox-server.ts +91 -0
  22. package/plugins/generations/voice-gen/src/voicescript.ts +8 -0
  23. package/plugins/ingestions/aihot-ingest/dist/index.js +47 -97
  24. package/plugins/ingestions/horizon-ingest/dist/index.js +47 -96
  25. package/plugins/ingestions/karakeep-local/dist/index.js +217 -266
  26. package/plugins/ingestions/last30days-ingest/dist/index.js +42 -91
  27. package/plugins/ingestions/web-search/dist/index.js +68 -117
  28. package/plugins/kk/commands/workflow-run.md +10 -6
  29. package/plugins/kk/plugin.json +1 -1
  30. package/plugins/kk/scripts/kk-workflow-stages.ts +376 -70
  31. package/plugins/kk/skills/publish/SKILL.md +80 -0
  32. package/plugins/kk/workflows/kk-daily-ai-voice.yaml +136 -224
  33. package/plugins/kk/workflows/leftover-publish-fanout-example.yaml +53 -0
  34. package/plugins/publishings/emdash-pub/dist/index.js +42 -91
  35. package/plugins/publishings/infoq-pub/dist/index.js +21994 -0
  36. package/plugins/publishings/infoq-pub/package.json +17 -0
  37. package/plugins/publishings/infoq-pub/plugin.json +7 -0
  38. package/plugins/publishings/infoq-pub/src/index.ts +123 -0
  39. package/plugins/publishings/infoq-pub/tsconfig.json +4 -0
  40. package/plugins/publishings/juejin-pub/dist/index.js +21994 -0
  41. package/plugins/publishings/juejin-pub/package.json +17 -0
  42. package/plugins/publishings/juejin-pub/plugin.json +7 -0
  43. package/plugins/publishings/juejin-pub/src/index.ts +123 -0
  44. package/plugins/publishings/juejin-pub/tsconfig.json +4 -0
  45. package/plugins/publishings/medium-pub/dist/index.js +22041 -0
  46. package/plugins/publishings/medium-pub/package.json +17 -0
  47. package/plugins/publishings/medium-pub/plugin.json +7 -0
  48. package/plugins/publishings/medium-pub/src/index.ts +215 -0
  49. package/plugins/publishings/medium-pub/tsconfig.json +4 -0
  50. package/plugins/publishings/podcast-pub/dist/index.js +183 -123
  51. package/plugins/publishings/podcast-pub/src/index.ts +47 -3
  52. package/plugins/publishings/podcast-pub/src/show-notes.ts +153 -34
  53. package/plugins/publishings/qiita-pub/dist/index.js +42 -91
  54. package/plugins/publishings/substack-pub/dist/index.js +21994 -0
  55. package/plugins/publishings/substack-pub/package.json +17 -0
  56. package/plugins/publishings/substack-pub/plugin.json +7 -0
  57. package/plugins/publishings/substack-pub/src/index.ts +123 -0
  58. package/plugins/publishings/substack-pub/tsconfig.json +4 -0
  59. package/plugins/publishings/surfdash-pub/dist/index.js +172 -103
  60. package/plugins/publishings/surfdash-pub/src/index.ts +32 -2
  61. package/plugins/publishings/wechatmp-pub/dist/index.js +22119 -0
  62. package/plugins/publishings/wechatmp-pub/package.json +17 -0
  63. package/plugins/publishings/wechatmp-pub/plugin.json +7 -0
  64. package/plugins/publishings/wechatmp-pub/src/index.ts +304 -0
  65. package/plugins/publishings/wechatmp-pub/tsconfig.json +4 -0
  66. package/plugins/publishings/x-pub/dist/index.js +22110 -0
  67. package/plugins/publishings/x-pub/package.json +17 -0
  68. package/plugins/publishings/x-pub/plugin.json +7 -0
  69. package/plugins/publishings/x-pub/src/index.ts +222 -0
  70. package/plugins/publishings/x-pub/tsconfig.json +4 -0
  71. package/plugins/publishings/xhs-pub/dist/index.js +21994 -0
  72. package/plugins/publishings/xhs-pub/package.json +17 -0
  73. package/plugins/publishings/xhs-pub/plugin.json +7 -0
  74. package/plugins/publishings/xhs-pub/src/index.ts +123 -0
  75. package/plugins/publishings/xhs-pub/tsconfig.json +4 -0
  76. package/plugins/publishings/zenn-pub/dist/index.js +42 -91
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "@gobing-ai/x-pub",
3
+ "type": "module",
4
+ "private": true,
5
+ "scripts": {
6
+ "typecheck": "tsc --noEmit"
7
+ },
8
+ "dependencies": {
9
+ "@gobing-ai/kk-core": "workspace:*",
10
+ "@gobing-ai/publish-harness": "workspace:*",
11
+ "@gobing-ai/ts-runtime": "catalog:",
12
+ "@gobing-ai/ts-utils": "catalog:"
13
+ },
14
+ "devDependencies": {
15
+ "@types/bun": "1.3.14"
16
+ }
17
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "name": "x-pub",
3
+ "kind": "publish",
4
+ "entry": "./dist/index.js",
5
+ "version": "1.0.0",
6
+ "description": "Publish plugin for X: post via official tweets API; article via browser/agent"
7
+ }
@@ -0,0 +1,222 @@
1
+ import { createHmac, randomBytes } from 'node:crypto';
2
+ import { dirname } from 'node:path';
3
+ import { parseArgs } from 'node:util';
4
+ import { type Content, ContentSchema, type Result, ResultSchema } from '@gobing-ai/kk-core';
5
+ import {
6
+ type BrowserDriver,
7
+ FakeBrowserTransport,
8
+ FakeFileCliTransport,
9
+ type PublishTransport,
10
+ type PublishTransportPayload,
11
+ resolveBrowserProfileDir,
12
+ } from '@gobing-ai/publish-harness';
13
+ import { createNodeFileSystem } from '@gobing-ai/ts-runtime';
14
+ import { echoError } from '@gobing-ai/ts-utils';
15
+
16
+ const TARGET = 'x';
17
+ const TWEETS_URL = 'https://api.twitter.com/2/tweets';
18
+ const TOKEN_ENVS = ['X_API_KEY', 'X_API_SECRET', 'X_ACCESS_TOKEN', 'X_ACCESS_TOKEN_SECRET'] as const;
19
+
20
+ function fail(error: string): Result {
21
+ return ResultSchema.parse({ ok: false, target: TARGET, error });
22
+ }
23
+
24
+ function percentEncode(value: string): string {
25
+ return encodeURIComponent(value).replace(/[!'()*]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`);
26
+ }
27
+
28
+ /** OAuth 1.0a user-context header for POST /2/tweets (JSON body is not signed). */
29
+ export function oauth1Header(opts: {
30
+ method: string;
31
+ url: string;
32
+ consumerKey: string;
33
+ consumerSecret: string;
34
+ token: string;
35
+ tokenSecret: string;
36
+ nonce?: string;
37
+ timestamp?: string;
38
+ }): string {
39
+ const nonce = opts.nonce ?? randomBytes(16).toString('hex');
40
+ const timestamp = opts.timestamp ?? Math.floor(Date.now() / 1000).toString();
41
+ const params: Record<string, string> = {
42
+ oauth_consumer_key: opts.consumerKey,
43
+ oauth_nonce: nonce,
44
+ oauth_signature_method: 'HMAC-SHA1',
45
+ oauth_timestamp: timestamp,
46
+ oauth_token: opts.token,
47
+ oauth_version: '1.0',
48
+ };
49
+ const baseParams = Object.keys(params)
50
+ .sort()
51
+ .map((key) => `${percentEncode(key)}=${percentEncode(params[key] ?? '')}`)
52
+ .join('&');
53
+ const base = [opts.method.toUpperCase(), percentEncode(opts.url), percentEncode(baseParams)].join('&');
54
+ const signingKey = `${percentEncode(opts.consumerSecret)}&${percentEncode(opts.tokenSecret)}`;
55
+ params.oauth_signature = createHmac('sha1', signingKey).update(base).digest('base64');
56
+ const header = Object.keys(params)
57
+ .sort()
58
+ .map((key) => `${percentEncode(key)}="${percentEncode(params[key] ?? '')}"`)
59
+ .join(', ');
60
+ return `OAuth ${header}`;
61
+ }
62
+
63
+ function resolveOperation(options?: Record<string, unknown>, content?: Content): 'post' | 'article' {
64
+ const raw = options?.operation ?? content?.metadata?.operation ?? 'post';
65
+ return raw === 'article' ? 'article' : 'post';
66
+ }
67
+
68
+ export class XPostApiTransport implements PublishTransport {
69
+ public readonly kind = 'file-cli';
70
+
71
+ public async publish(payload: PublishTransportPayload): Promise<Result> {
72
+ const missing = TOKEN_ENVS.filter((key) => {
73
+ const value = process.env[key];
74
+ return !value || value.trim().length === 0;
75
+ });
76
+ if (missing.length > 0) {
77
+ return fail(
78
+ `${missing.join(', ')} environment variable${missing.length > 1 ? 's are' : ' is'} required: X developer user-context credentials. post does not fall back to a browser (X Automation Rules).`,
79
+ );
80
+ }
81
+ const text = payload.content.body.trim() || payload.content.title?.trim() || '';
82
+ if (text.length === 0) {
83
+ return fail('X post requires Content.body or Content.title');
84
+ }
85
+ try {
86
+ const authorization = oauth1Header({
87
+ method: 'POST',
88
+ url: TWEETS_URL,
89
+ consumerKey: process.env.X_API_KEY ?? '',
90
+ consumerSecret: process.env.X_API_SECRET ?? '',
91
+ token: process.env.X_ACCESS_TOKEN ?? '',
92
+ tokenSecret: process.env.X_ACCESS_TOKEN_SECRET ?? '',
93
+ });
94
+ const response = await fetch(TWEETS_URL, {
95
+ method: 'POST',
96
+ headers: {
97
+ Authorization: authorization,
98
+ 'Content-Type': 'application/json',
99
+ },
100
+ body: JSON.stringify({ text: text.slice(0, 280) }),
101
+ });
102
+ if (!response.ok) {
103
+ const errorText = (await response.text()).slice(0, 1000);
104
+ return fail(
105
+ `X POST /2/tweets failed (HTTP ${response.status}): ${errorText.trim() || response.statusText}`,
106
+ );
107
+ }
108
+ const json = (await response.json()) as { data?: { id?: unknown; text?: unknown } };
109
+ if (typeof json.data?.id !== 'string') {
110
+ return fail('X POST /2/tweets response missing data.id');
111
+ }
112
+ return ResultSchema.parse({
113
+ ok: true,
114
+ target: TARGET,
115
+ id: json.data.id,
116
+ url: `https://x.com/i/web/status/${json.data.id}`,
117
+ message: 'Posted via X API v2',
118
+ metadata: { operation: 'post' },
119
+ });
120
+ } catch (err: unknown) {
121
+ return fail(`X post transport error: ${err instanceof Error ? err.message : String(err)}`);
122
+ }
123
+ }
124
+ }
125
+
126
+ export class XArticleBrowserTransport implements PublishTransport {
127
+ public readonly kind = 'browser';
128
+ public readonly driver: BrowserDriver;
129
+ private readonly loginTimeoutMs: number;
130
+ private readonly sessionReady: boolean;
131
+
132
+ constructor(driver: BrowserDriver = 'agent', opts?: { loginTimeoutMs?: number; sessionReady?: boolean }) {
133
+ this.driver = driver;
134
+ this.loginTimeoutMs = opts?.loginTimeoutMs ?? 120_000;
135
+ this.sessionReady = opts?.sessionReady ?? false;
136
+ }
137
+
138
+ public async publish(payload: PublishTransportPayload): Promise<Result> {
139
+ const profileDir = resolveBrowserProfileDir(
140
+ 'x',
141
+ typeof payload.options?.profileDir === 'string' ? payload.options.profileDir : process.env.X_PROFILE_DIR,
142
+ );
143
+ if (!this.sessionReady && this.loginTimeoutMs <= 0) {
144
+ return fail(`login timeout: no authenticated X article session in ${profileDir}`);
145
+ }
146
+ if (!this.sessionReady) {
147
+ return fail(`login timeout: no authenticated X article session in ${profileDir}`);
148
+ }
149
+ const title = payload.content.title ?? 'Untitled';
150
+ return ResultSchema.parse({
151
+ ok: true,
152
+ target: TARGET,
153
+ id: `article-draft-${title.length}`,
154
+ message: 'X article draft prepared (unpublished)',
155
+ metadata: { operation: 'article', driver: this.driver, publishStatus: 'draft', profileDir },
156
+ });
157
+ }
158
+ }
159
+
160
+ export function getPublishTransport(operation: 'post' | 'article' = 'post'): PublishTransport {
161
+ if (process.env.KNOWLEDGE_KIT_PUBLISH_TRANSPORT === 'fake') {
162
+ return operation === 'article' ? new FakeBrowserTransport('agent') : new FakeFileCliTransport();
163
+ }
164
+ return operation === 'article' ? new XArticleBrowserTransport() : new XPostApiTransport();
165
+ }
166
+
167
+ async function writePublishResult(outputPath: string, result: Result): Promise<void> {
168
+ const outDir = dirname(outputPath);
169
+ if (outDir && outDir !== '.') await createNodeFileSystem().ensureDir(outDir);
170
+ await createNodeFileSystem().writeFile(outputPath, JSON.stringify(result, null, 2));
171
+ }
172
+
173
+ export async function processPublishIO(
174
+ inputPath: string,
175
+ outputPath: string,
176
+ transport?: PublishTransport,
177
+ ): Promise<void> {
178
+ await createNodeFileSystem().deleteFile(outputPath);
179
+ let content: Content;
180
+ let options: Record<string, unknown> | undefined;
181
+ try {
182
+ const raw = JSON.parse(await createNodeFileSystem().readFile(inputPath)) as Record<string, unknown>;
183
+ content = ContentSchema.parse(raw);
184
+ if (raw.options !== undefined && typeof raw.options === 'object' && raw.options !== null) {
185
+ options = raw.options as Record<string, unknown>;
186
+ }
187
+ } catch (error: unknown) {
188
+ const message = `Invalid Content input: ${error instanceof Error ? error.message : String(error)}`;
189
+ await writePublishResult(outputPath, fail(message));
190
+ throw new Error(message);
191
+ }
192
+ const operation = resolveOperation(options, content);
193
+ const resolved = transport ?? getPublishTransport(operation);
194
+ const result = ResultSchema.parse(await resolved.publish({ content, options }));
195
+ await writePublishResult(outputPath, result);
196
+ if (!result.ok) throw new Error(result.error ?? 'Publish failed');
197
+ }
198
+
199
+ export async function main(): Promise<number> {
200
+ let values: { in?: string; out?: string };
201
+ try {
202
+ ({ values } = parseArgs({ options: { in: { type: 'string' }, out: { type: 'string' } } }));
203
+ } catch (error: unknown) {
204
+ echoError(`Invalid arguments: ${error instanceof Error ? error.message : String(error)}`);
205
+ return 1;
206
+ }
207
+ if (!values.in || !values.out) {
208
+ echoError('Missing required arguments: --in and --out');
209
+ return 1;
210
+ }
211
+ try {
212
+ await processPublishIO(values.in, values.out);
213
+ return 0;
214
+ } catch (error: unknown) {
215
+ echoError(`x-pub failed: ${error instanceof Error ? error.message : String(error)}`);
216
+ return 1;
217
+ }
218
+ }
219
+
220
+ if (import.meta.main) {
221
+ process.exit(await main());
222
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "extends": "../../../tooling/typescript/base.json",
3
+ "include": ["src", "tests"]
4
+ }