@gobing-ai/knowledge-kit 0.0.23 → 0.0.25
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.
- package/.claude-plugin/marketplace.json +1 -1
- package/dist/index.js +137 -59
- package/package.json +4 -4
- package/plugins/generations/content-gen/dist/index.js +97 -45
- package/plugins/generations/core-facts-gen/dist/index.js +106 -57
- package/plugins/generations/daily-article-gen/dist/index.js +105 -56
- package/plugins/generations/dailynews-gen/dist/index.js +235 -57
- package/plugins/generations/dailynews-gen/src/index.ts +67 -2
- package/plugins/generations/dailynews-gen/src/script-builder.ts +36 -15
- package/plugins/generations/dailynews-gen/src/script-plan.ts +142 -0
- package/plugins/generations/episode-plan-gen/dist/index.js +115 -66
- package/plugins/generations/gemini-tts/README.md +24 -0
- package/plugins/generations/gemini-tts/dist/index.js +326 -260
- package/plugins/generations/gemini-tts/src/gemini-client.ts +41 -11
- package/plugins/generations/image-gen/dist/index.js +338 -117
- package/plugins/generations/image-gen/presets/formats/daily-news-cover.yaml +19 -0
- package/plugins/generations/image-gen/presets/formats/xhs-card.yaml +55 -0
- package/plugins/generations/image-gen/presets/styles/daily-news.yaml +9 -0
- package/plugins/generations/image-gen/presets/styles/xhs-knowledge.yaml +7 -0
- package/plugins/generations/image-gen/src/index.ts +148 -14
- package/plugins/generations/image-gen/src/job.ts +30 -0
- package/plugins/generations/image-gen/src/providers/errors.ts +91 -0
- package/plugins/generations/image-gen/src/providers/types.ts +79 -0
- package/plugins/generations/news-report-gen/dist/index.js +136 -55
- package/plugins/generations/news-report-gen/src/index.ts +57 -1
- package/plugins/generations/voice-gen/dist/index.js +119 -67
- package/plugins/ingestions/aihot-ingest/dist/index.js +103 -53
- package/plugins/ingestions/horizon-ingest/dist/index.js +102 -53
- package/plugins/ingestions/karakeep-local/dist/index.js +273 -224
- package/plugins/ingestions/last30days-ingest/dist/index.js +97 -48
- package/plugins/ingestions/web-search/dist/index.js +121 -72
- package/plugins/kk/config.example.yaml +13 -0
- package/plugins/kk/plugin.json +1 -1
- package/plugins/kk/scripts/daily-voice-style.zh.md +52 -0
- package/plugins/kk/scripts/kk-workflow-stages.ts +433 -16
- package/plugins/kk/skills/publish/SKILL.md +24 -1
- package/plugins/kk/skills/xhs-images/SKILL.md +89 -0
- package/plugins/kk/skills/xhs-images/references/card-layouts.md +35 -0
- package/plugins/kk/workflows/kk-daily-ai-voice.yaml +162 -11
- package/plugins/publishings/emdash-pub/dist/index.js +94 -45
- package/plugins/publishings/infoq-pub/dist/index.js +94 -45
- package/plugins/publishings/juejin-pub/dist/index.js +94 -45
- package/plugins/publishings/medium-pub/dist/index.js +94 -45
- package/plugins/publishings/podcast-pub/dist/index.js +115 -55
- package/plugins/publishings/podcast-pub/src/map.ts +30 -10
- package/plugins/publishings/podcast-pub/src/show-notes.ts +6 -1
- package/plugins/publishings/qiita-pub/dist/index.js +94 -45
- package/plugins/publishings/substack-pub/dist/index.js +94 -45
- package/plugins/publishings/surfdash-pub/dist/index.js +99 -63
- package/plugins/publishings/surfdash-pub/src/index.ts +10 -1
- package/plugins/publishings/wechatmp-pub/dist/index.js +94 -45
- package/plugins/publishings/x-pub/dist/index.js +94 -45
- package/plugins/publishings/xhs-pub/dist/index.js +8908 -229
- package/plugins/publishings/xhs-pub/package.json +1 -0
- package/plugins/publishings/xhs-pub/plugin.json +1 -1
- package/plugins/publishings/xhs-pub/src/automation-guard.ts +128 -0
- package/plugins/publishings/xhs-pub/src/index.ts +753 -24
- package/plugins/publishings/xhs-pub/src/profile-check.ts +133 -0
- package/plugins/publishings/zenn-pub/dist/index.js +94 -45
- package/plugins/sp/lib/env.ts +46 -0
- package/plugins/sp/lib/inline-run.generated.mjs +1489 -0
- package/plugins/sp/scripts/feature-verification-steps.ts +275 -0
- package/plugins/sp/scripts/inline-run-setup.ts +571 -47
- package/plugins/sp/scripts/wrapup-drift-probe.mjs +190 -0
- package/plugins/sp/scripts/wrapup-drift-probe.ts +258 -0
- package/plugins/sp/scripts/wrapup-steps.mjs +77 -6
- package/plugins/sp/scripts/wrapup-steps.ts +91 -5
|
@@ -3,5 +3,5 @@
|
|
|
3
3
|
"kind": "publish",
|
|
4
4
|
"entry": "./dist/index.js",
|
|
5
5
|
"version": "1.0.0",
|
|
6
|
-
"description": "Publish plugin for Xiaohongshu (xhs) via
|
|
6
|
+
"description": "Publish plugin for Xiaohongshu (xhs): ordered card images to draft or live post via Playwright script transport"
|
|
7
7
|
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* XHS automation-risk guard (ADR-025, 2026-09-28).
|
|
3
|
+
*
|
|
4
|
+
* XHS warned the operator about automated login/publish activity. This channel is the only target
|
|
5
|
+
* in the repo that drives an interactive creator console from a browser, so a repeated or runaway
|
|
6
|
+
* visit is an account-level risk rather than a failed run. The guard bounds console visits with two
|
|
7
|
+
* independent 24h budgets — one headed publish cycle and one read-only session check — recorded in
|
|
8
|
+
* a small state file.
|
|
9
|
+
*
|
|
10
|
+
* Semantics that matter:
|
|
11
|
+
* - The `publish` budget is consumed at the headed launch, never at the attempt: a refused session
|
|
12
|
+
* preflight leaves the window intact so the operator can log in and retry. What the cap bounds is
|
|
13
|
+
* headed console visits, not attempts.
|
|
14
|
+
* - `login` is deliberately uncapped. It is operator-interactive by construction (a human types the
|
|
15
|
+
* credentials into the opened window), so capping it would only block recovery.
|
|
16
|
+
* - An unreadable or unparsable state file is REFUSED, not treated as empty: the guard cannot prove
|
|
17
|
+
* the window is clean, and a silent reset is the one failure mode that defeats it.
|
|
18
|
+
*/
|
|
19
|
+
import { homedir } from 'node:os';
|
|
20
|
+
import { join, resolve } from 'node:path';
|
|
21
|
+
import { createNodeFileSystem } from '@gobing-ai/ts-runtime';
|
|
22
|
+
|
|
23
|
+
// File IO goes through the ts-runtime FileSystem seam (rule no-direct-fs-io). The node backend uses
|
|
24
|
+
// sync fs APIs and `writeFile` creates missing parents; the interface unions Promise for CF stubs,
|
|
25
|
+
// so pin the sync shape once here (same pin as image-gen's presets.ts).
|
|
26
|
+
const fs = createNodeFileSystem() as unknown as {
|
|
27
|
+
exists(path: string): boolean;
|
|
28
|
+
readFile(path: string): string;
|
|
29
|
+
writeFile(path: string, content: string): void;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/** The capped automation events. `login` is intentionally absent — see the module comment. */
|
|
33
|
+
export type XhsAutomationEvent = 'check' | 'publish';
|
|
34
|
+
|
|
35
|
+
/** One headed publish cycle and one read-only session check per window. */
|
|
36
|
+
export const CAP_WINDOW_MS = 24 * 60 * 60 * 1000;
|
|
37
|
+
|
|
38
|
+
/** State-file override for tests and multi-account machines; default is the shared kk config dir. */
|
|
39
|
+
export const AUTOMATION_STATE_ENV = 'KK_XHS_AUTOMATION_STATE';
|
|
40
|
+
|
|
41
|
+
export interface AutomationVerdict {
|
|
42
|
+
allowed: boolean;
|
|
43
|
+
/** Empty when allowed; the operator-facing refusal reason otherwise. */
|
|
44
|
+
reason: string;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface AutomationGuard {
|
|
48
|
+
/** Refuse when this event already ran inside the window. Reads only — never consumes. */
|
|
49
|
+
allow(event: XhsAutomationEvent): AutomationVerdict;
|
|
50
|
+
/** Consume the event's budget. Call immediately before the console visit it pays for. */
|
|
51
|
+
record(event: XhsAutomationEvent): void;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function resolveAutomationStatePath(override?: string): string {
|
|
55
|
+
const explicit = override ?? process.env[AUTOMATION_STATE_ENV];
|
|
56
|
+
if (explicit !== undefined && explicit !== '') return resolve(explicit);
|
|
57
|
+
// process.env.HOME directly: Bun snapshots os.homedir() at startup, so a runtime HOME override
|
|
58
|
+
// (tests) would be invisible through homedir(). Mirrors image-gen's preset-root resolution.
|
|
59
|
+
return join(process.env.HOME ?? homedir(), '.config', 'kk', 'xhs-automation.json');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
type AutomationState = Partial<Record<XhsAutomationEvent, string>>;
|
|
63
|
+
|
|
64
|
+
function resetHint(path: string): string {
|
|
65
|
+
return `delete ${path} to reset the automation window (the guard cannot prove the window is clean)`;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* `ok: true` only for an absent file (the legitimate first run) or a readable JSON object. Every
|
|
70
|
+
* other outcome is a refusal the operator can act on, so a corrupt file cannot silently grant a
|
|
71
|
+
* fresh budget.
|
|
72
|
+
*/
|
|
73
|
+
function readState(path: string): { ok: true; state: AutomationState } | { ok: false; reason: string } {
|
|
74
|
+
// An absent file is the first run; anything present but unreadable (a directory, a permission
|
|
75
|
+
// failure) is refused rather than treated as empty.
|
|
76
|
+
if (!fs.exists(path)) return { ok: true, state: {} };
|
|
77
|
+
let raw: string;
|
|
78
|
+
try {
|
|
79
|
+
raw = fs.readFile(path);
|
|
80
|
+
} catch (error) {
|
|
81
|
+
return { ok: false, reason: `state file ${path} is unreadable: ${(error as Error).message}` };
|
|
82
|
+
}
|
|
83
|
+
let parsed: unknown;
|
|
84
|
+
try {
|
|
85
|
+
parsed = JSON.parse(raw);
|
|
86
|
+
} catch {
|
|
87
|
+
return { ok: false, reason: `state file ${path} is not valid JSON` };
|
|
88
|
+
}
|
|
89
|
+
if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
90
|
+
return { ok: false, reason: `state file ${path} is not a JSON object` };
|
|
91
|
+
}
|
|
92
|
+
return { ok: true, state: parsed as AutomationState };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function createAutomationGuard(options?: { statePath?: string; now?: () => Date }): AutomationGuard {
|
|
96
|
+
const statePath = resolveAutomationStatePath(options?.statePath);
|
|
97
|
+
const now = options?.now ?? (() => new Date());
|
|
98
|
+
return {
|
|
99
|
+
allow(event) {
|
|
100
|
+
const read = readState(statePath);
|
|
101
|
+
if (!read.ok) return { allowed: false, reason: `${read.reason} — ${resetHint(statePath)}` };
|
|
102
|
+
const last = read.state[event];
|
|
103
|
+
if (last === undefined) return { allowed: true, reason: '' };
|
|
104
|
+
const lastMs = Date.parse(last);
|
|
105
|
+
if (!Number.isFinite(lastMs)) {
|
|
106
|
+
return {
|
|
107
|
+
allowed: false,
|
|
108
|
+
reason: `state file ${statePath} records an unparsable '${event}' timestamp ('${last}') — ${resetHint(statePath)}`,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
const elapsed = now().getTime() - lastMs;
|
|
112
|
+
if (elapsed >= CAP_WINDOW_MS) return { allowed: true, reason: '' };
|
|
113
|
+
const waitMinutes = Math.ceil((CAP_WINDOW_MS - elapsed) / 60_000);
|
|
114
|
+
return {
|
|
115
|
+
allowed: false,
|
|
116
|
+
reason: `'${event}' already ran ${Math.round(elapsed / 60_000)}min ago; the cap allows one per ${CAP_WINDOW_MS / 3_600_000}h — retry in ${waitMinutes}min, or set ${AUTOMATION_STATE_ENV} to a separate state file for a deliberate second profile`,
|
|
117
|
+
};
|
|
118
|
+
},
|
|
119
|
+
record(event) {
|
|
120
|
+
const read = readState(statePath);
|
|
121
|
+
// `allow` already gated this call, so a corrupt file reaching here is being repaired,
|
|
122
|
+
// not trusted: the new state replaces it wholesale.
|
|
123
|
+
const state: AutomationState = read.ok ? read.state : {};
|
|
124
|
+
state[event] = now().toISOString();
|
|
125
|
+
fs.writeFile(statePath, `${JSON.stringify(state, null, 2)}\n`);
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
}
|