@gobing-ai/knowledge-kit 0.0.32 → 0.0.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/dist/index.js +32320 -15021
- package/package.json +4 -4
- package/plugins/generations/content-gen/dist/index.js +10 -9
- package/plugins/generations/core-facts-gen/dist/index.js +13 -12
- package/plugins/generations/daily-article-gen/dist/index.js +14 -13
- package/plugins/generations/daily-article-gen/src/index.ts +1 -1
- package/plugins/generations/dailynews-gen/dist/index.js +10 -9
- package/plugins/generations/episode-plan-gen/dist/index.js +58 -15
- package/plugins/generations/episode-plan-gen/src/index.ts +76 -6
- package/plugins/generations/gemini-tts/README.md +11 -0
- package/plugins/generations/gemini-tts/dist/index.js +10 -9
- package/plugins/generations/image-gen/dist/index.js +154 -151
- package/plugins/generations/image-gen/src/compose/chromium.ts +60 -42
- package/plugins/generations/news-report-gen/dist/index.js +13 -12
- package/plugins/generations/voice-gen/dist/index.js +10 -9
- package/plugins/ingestions/aihot-ingest/dist/index.js +13 -12
- package/plugins/ingestions/horizon-ingest/dist/index.js +13 -12
- package/plugins/ingestions/karakeep-local/dist/index.js +13 -13
- package/plugins/ingestions/last30days-ingest/dist/index.js +13 -12
- package/plugins/ingestions/web-search/dist/index.js +11 -10
- package/plugins/kk/README.md +38 -0
- package/plugins/kk/decisions/extract/ai-news.yaml +21 -0
- package/plugins/kk/decisions/kk-items.yaml +113 -0
- package/plugins/kk/plugin.json +1 -1
- package/plugins/kk/schedules/cron.tmpl +15 -0
- package/plugins/kk/schedules/launchd.plist.tmpl +77 -0
- package/plugins/kk/scripts/daily-stages.ts +1533 -0
- package/plugins/kk/scripts/kk-workflow-stages.ts +247 -1365
- package/plugins/kk/skills/content-safety/SKILL.md +38 -7
- package/plugins/kk/skills/web-automation/SKILL.md +100 -0
- package/plugins/kk/skills/web-automation/references/browser-launch.md +86 -0
- package/plugins/kk/workflows/kk-collect.yaml +258 -0
- package/plugins/kk/workflows/kk-daily-ai-voice.yaml +9 -3
- package/plugins/kk/workflows/kk-daily-ai-voice2.yaml +655 -0
- package/plugins/kk/workflows/kk-daily-safety.yaml +170 -0
- package/plugins/publishings/emdash-pub/dist/index.js +10 -9
- package/plugins/publishings/infoq-pub/dist/index.js +152 -59
- package/plugins/publishings/infoq-pub/plugin.json +1 -0
- package/plugins/publishings/infoq-pub/src/index.ts +167 -55
- package/plugins/publishings/infoq-pub/src/profile-check.ts +4 -2
- package/plugins/publishings/juejin-pub/dist/index.js +111 -30
- package/plugins/publishings/juejin-pub/plugin.json +1 -0
- package/plugins/publishings/juejin-pub/src/index.ts +49 -9
- package/plugins/publishings/medium-pub/dist/index.js +10 -9
- package/plugins/publishings/podcast-pub/dist/index.js +10 -9
- package/plugins/publishings/qiita-pub/dist/index.js +10 -9
- package/plugins/publishings/substack-pub/dist/index.js +105 -28
- package/plugins/publishings/substack-pub/plugin.json +1 -0
- package/plugins/publishings/substack-pub/src/index.ts +39 -8
- package/plugins/publishings/substack-pub/src/profile-check.ts +2 -0
- package/plugins/publishings/surfdash-pub/dist/index.js +10 -9
- package/plugins/publishings/wechatmp-pub/dist/index.js +115 -31
- package/plugins/publishings/wechatmp-pub/plugin.json +1 -0
- package/plugins/publishings/wechatmp-pub/src/index.ts +42 -9
- package/plugins/publishings/wechatmp-pub/src/profile-check.ts +84 -40
- package/plugins/publishings/x-pub/dist/index.js +114 -35
- package/plugins/publishings/x-pub/plugin.json +1 -0
- package/plugins/publishings/x-pub/src/index.ts +68 -14
- package/plugins/publishings/xhs-pub/dist/index.js +100 -54
- package/plugins/publishings/xhs-pub/plugin.json +1 -0
- package/plugins/publishings/xhs-pub/src/index.ts +8 -4
- package/plugins/publishings/xhs-pub/src/page.ts +4 -17
- package/plugins/publishings/xhs-pub/src/profile-check.ts +28 -15
- package/plugins/publishings/zenn-pub/dist/index.js +10 -9
|
@@ -14671,7 +14671,7 @@ var init_zod = __esm(() => {
|
|
|
14671
14671
|
init_external();
|
|
14672
14672
|
});
|
|
14673
14673
|
|
|
14674
|
-
// ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.
|
|
14674
|
+
// ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.18/node_modules/@gobing-ai/ts-utils/dist/errors.js
|
|
14675
14675
|
var ErrorCode;
|
|
14676
14676
|
var init_errors3 = __esm(() => {
|
|
14677
14677
|
ErrorCode = {
|
|
@@ -14682,7 +14682,7 @@ var init_errors3 = __esm(() => {
|
|
|
14682
14682
|
};
|
|
14683
14683
|
});
|
|
14684
14684
|
|
|
14685
|
-
// ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.
|
|
14685
|
+
// ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.18/node_modules/@gobing-ai/ts-utils/dist/api-response.js
|
|
14686
14686
|
var API_ERROR_CODES, ERROR_CODE_TO_HTTP, CLIENT_SAFE_CODES;
|
|
14687
14687
|
var init_api_response = __esm(() => {
|
|
14688
14688
|
init_errors3();
|
|
@@ -14705,10 +14705,10 @@ var init_api_response = __esm(() => {
|
|
|
14705
14705
|
CLIENT_SAFE_CODES = new Set([ErrorCode.NotFound, ErrorCode.Validation, ErrorCode.Conflict]);
|
|
14706
14706
|
});
|
|
14707
14707
|
|
|
14708
|
-
// ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.
|
|
14708
|
+
// ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.18/node_modules/@gobing-ai/ts-utils/dist/cursor.js
|
|
14709
14709
|
var init_cursor = () => {};
|
|
14710
14710
|
|
|
14711
|
-
// ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.
|
|
14711
|
+
// ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.18/node_modules/@gobing-ai/ts-utils/dist/env.js
|
|
14712
14712
|
function getEnvVar(name, fallback) {
|
|
14713
14713
|
const raw = process.env[name];
|
|
14714
14714
|
return raw === undefined ? fallback : raw;
|
|
@@ -14717,10 +14717,10 @@ function getEnvVars() {
|
|
|
14717
14717
|
return process.env;
|
|
14718
14718
|
}
|
|
14719
14719
|
|
|
14720
|
-
// ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.
|
|
14720
|
+
// ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.18/node_modules/@gobing-ai/ts-utils/dist/event-severity.js
|
|
14721
14721
|
var init_event_severity = () => {};
|
|
14722
14722
|
|
|
14723
|
-
// ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.
|
|
14723
|
+
// ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.18/node_modules/@gobing-ai/ts-utils/dist/object.js
|
|
14724
14724
|
function isPlainObject2(value) {
|
|
14725
14725
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
14726
14726
|
}
|
|
@@ -14738,7 +14738,7 @@ function deepMerge(target, source) {
|
|
|
14738
14738
|
return result;
|
|
14739
14739
|
}
|
|
14740
14740
|
|
|
14741
|
-
// ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.
|
|
14741
|
+
// ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.18/node_modules/@gobing-ai/ts-utils/dist/output.js
|
|
14742
14742
|
function processStream(name) {
|
|
14743
14743
|
const proc = globalThis.process;
|
|
14744
14744
|
const stream = proc?.[name];
|
|
@@ -14756,7 +14756,7 @@ function echoError(message, target = defaultStderrTarget ?? processStream("stder
|
|
|
14756
14756
|
}
|
|
14757
14757
|
var defaultStderrTarget;
|
|
14758
14758
|
|
|
14759
|
-
// ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.
|
|
14759
|
+
// ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.18/node_modules/@gobing-ai/ts-utils/dist/index.js
|
|
14760
14760
|
var init_dist = __esm(() => {
|
|
14761
14761
|
init_api_response();
|
|
14762
14762
|
init_cursor();
|
|
@@ -21754,7 +21754,7 @@ var init_dist2 = __esm(() => {
|
|
|
21754
21754
|
$visitAsync = visit.visitAsync;
|
|
21755
21755
|
});
|
|
21756
21756
|
|
|
21757
|
-
// ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.
|
|
21757
|
+
// ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.18+ea28d47622d670ff/node_modules/@gobing-ai/ts-runtime/dist/config.js
|
|
21758
21758
|
function getProcessEnv() {
|
|
21759
21759
|
return getEnvVars();
|
|
21760
21760
|
}
|
|
@@ -21832,7 +21832,7 @@ var init_config = __esm(() => {
|
|
|
21832
21832
|
};
|
|
21833
21833
|
});
|
|
21834
21834
|
|
|
21835
|
-
// ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.
|
|
21835
|
+
// ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.18+ea28d47622d670ff/node_modules/@gobing-ai/ts-runtime/dist/file-system-node.js
|
|
21836
21836
|
import { appendFileSync, cpSync, createReadStream, createWriteStream, existsSync, mkdirSync, readdirSync, readFileSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "fs";
|
|
21837
21837
|
import { dirname, resolve as resolvePath } from "path";
|
|
21838
21838
|
function createNodeFileSystem(root, paths) {
|
|
@@ -21919,7 +21919,7 @@ function findProjectRoot(startDir) {
|
|
|
21919
21919
|
}
|
|
21920
21920
|
var init_file_system_node = () => {};
|
|
21921
21921
|
|
|
21922
|
-
// ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.
|
|
21922
|
+
// ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.18+ea28d47622d670ff/node_modules/@gobing-ai/ts-runtime/dist/db-errors.js
|
|
21923
21923
|
var DbModuleNotInstalledError;
|
|
21924
21924
|
var init_db_errors = __esm(() => {
|
|
21925
21925
|
DbModuleNotInstalledError = class DbModuleNotInstalledError extends Error {
|
|
@@ -29130,7 +29130,7 @@ var init_execa = __esm(() => {
|
|
|
29130
29130
|
} = getIpcExport());
|
|
29131
29131
|
});
|
|
29132
29132
|
|
|
29133
|
-
// ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.
|
|
29133
|
+
// ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.18+ea28d47622d670ff/node_modules/@gobing-ai/ts-runtime/dist/process-group.js
|
|
29134
29134
|
function resolveDeadline(optionTimeout, defaultTimeout) {
|
|
29135
29135
|
if (optionTimeout === null)
|
|
29136
29136
|
return null;
|
|
@@ -29222,7 +29222,7 @@ function ownProcessGroupLifecycle(ownership) {
|
|
|
29222
29222
|
}
|
|
29223
29223
|
var MAX_TIMEOUT_MS = 2147483647, DEFAULT_KILL_GRACE_MS = 5000, GROUP_POLL_INTERVAL_MS = 25, GROUP_KILL_PATIENCE_MS = 2000;
|
|
29224
29224
|
|
|
29225
|
-
// ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.
|
|
29225
|
+
// ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.18+ea28d47622d670ff/node_modules/@gobing-ai/ts-runtime/dist/process-executor.js
|
|
29226
29226
|
import { isatty } from "tty";
|
|
29227
29227
|
function processEventSeverity(reason, exitCode) {
|
|
29228
29228
|
if (reason === "error")
|
|
@@ -29594,7 +29594,7 @@ var init_process_executor = __esm(() => {
|
|
|
29594
29594
|
init_config();
|
|
29595
29595
|
});
|
|
29596
29596
|
|
|
29597
|
-
// ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.
|
|
29597
|
+
// ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.18+ea28d47622d670ff/node_modules/@gobing-ai/ts-runtime/dist/runtime-node-bun.js
|
|
29598
29598
|
function getNodeFileSystem() {
|
|
29599
29599
|
if (!_nodeFileSystem)
|
|
29600
29600
|
_nodeFileSystem = createNodeFileSystem();
|
|
@@ -29740,15 +29740,16 @@ var PluginManifestSchema = exports_external.looseObject({
|
|
|
29740
29740
|
name: exports_external.string().min(1),
|
|
29741
29741
|
kind: PluginKindSchema,
|
|
29742
29742
|
entry: exports_external.string().min(1),
|
|
29743
|
+
check: exports_external.string().min(1).optional(),
|
|
29743
29744
|
version: exports_external.string().optional(),
|
|
29744
29745
|
description: exports_external.string().optional(),
|
|
29745
29746
|
operations: exports_external.record(exports_external.string(), PluginOperationSchema).optional()
|
|
29746
29747
|
});
|
|
29747
|
-
// ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.
|
|
29748
|
+
// ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.18+ea28d47622d670ff/node_modules/@gobing-ai/ts-runtime/dist/index.js
|
|
29748
29749
|
init_file_system_node();
|
|
29749
29750
|
init_config();
|
|
29750
29751
|
|
|
29751
|
-
// ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.
|
|
29752
|
+
// ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.18+ea28d47622d670ff/node_modules/@gobing-ai/ts-runtime/dist/path.js
|
|
29752
29753
|
function normalizeSeparators(path6) {
|
|
29753
29754
|
return path6.replaceAll("\\", "/");
|
|
29754
29755
|
}
|
|
@@ -29806,7 +29807,7 @@ function getProcessCwd() {
|
|
|
29806
29807
|
return globalThis.process?.cwd?.() ?? "/";
|
|
29807
29808
|
}
|
|
29808
29809
|
|
|
29809
|
-
// ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.
|
|
29810
|
+
// ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.18+ea28d47622d670ff/node_modules/@gobing-ai/ts-runtime/dist/index.js
|
|
29810
29811
|
init_runtime_node_bun();
|
|
29811
29812
|
|
|
29812
29813
|
// ../../packages/kk-core/src/render-md.ts
|
|
@@ -29919,7 +29920,10 @@ async function trySelectors(page, selectors, options = {}) {
|
|
|
29919
29920
|
return { found: false, selector: null };
|
|
29920
29921
|
}
|
|
29921
29922
|
|
|
29922
|
-
// ../../
|
|
29923
|
+
// ../../packages/publish-harness/src/browser.ts
|
|
29924
|
+
import { resolve as resolve2 } from "path";
|
|
29925
|
+
|
|
29926
|
+
// ../../node_modules/.bun/@gobing-ai+ts-browser-automation@0.5.18+1f5782d4d327a230/node_modules/@gobing-ai/ts-browser-automation/dist/errors.js
|
|
29923
29927
|
class BrowserAutomationError extends Error {
|
|
29924
29928
|
constructor(message, options) {
|
|
29925
29929
|
super(message, options);
|
|
@@ -29954,10 +29958,10 @@ class PlaywrightUnavailableError extends BrowserAutomationError {
|
|
|
29954
29958
|
this.name = "PlaywrightUnavailableError";
|
|
29955
29959
|
}
|
|
29956
29960
|
}
|
|
29957
|
-
// ../../node_modules/.bun/@gobing-ai+ts-browser-automation@0.5.
|
|
29961
|
+
// ../../node_modules/.bun/@gobing-ai+ts-browser-automation@0.5.18+1f5782d4d327a230/node_modules/@gobing-ai/ts-browser-automation/dist/launcher.js
|
|
29958
29962
|
import { mkdir } from "fs/promises";
|
|
29959
29963
|
|
|
29960
|
-
// ../../node_modules/.bun/@gobing-ai+ts-browser-automation@0.5.
|
|
29964
|
+
// ../../node_modules/.bun/@gobing-ai+ts-browser-automation@0.5.18+1f5782d4d327a230/node_modules/@gobing-ai/ts-browser-automation/dist/profile-dir.js
|
|
29961
29965
|
function resolveProfileDir(profileDir) {
|
|
29962
29966
|
if (profileDir.trim() === "") {
|
|
29963
29967
|
throw new InvalidProfileDirError;
|
|
@@ -29969,7 +29973,7 @@ function resolveProfileDir(profileDir) {
|
|
|
29969
29973
|
return resolved;
|
|
29970
29974
|
}
|
|
29971
29975
|
|
|
29972
|
-
// ../../node_modules/.bun/@gobing-ai+ts-browser-automation@0.5.
|
|
29976
|
+
// ../../node_modules/.bun/@gobing-ai+ts-browser-automation@0.5.18+1f5782d4d327a230/node_modules/@gobing-ai/ts-browser-automation/dist/launcher.js
|
|
29973
29977
|
var PROFILE_DIR_MODE = 448;
|
|
29974
29978
|
var BUSY_PROFILE_PATTERN = /singleton|already in use|in use by another/i;
|
|
29975
29979
|
var CHROMIUM_MISSING_PATTERN = /playwright install|executable doesn't exist/i;
|
|
@@ -30020,7 +30024,7 @@ function createPersistentLauncher(options = {}) {
|
|
|
30020
30024
|
};
|
|
30021
30025
|
}
|
|
30022
30026
|
|
|
30023
|
-
// ../../node_modules/.bun/@gobing-ai+ts-browser-automation@0.5.
|
|
30027
|
+
// ../../node_modules/.bun/@gobing-ai+ts-browser-automation@0.5.18+1f5782d4d327a230/node_modules/@gobing-ai/ts-browser-automation/dist/operations.js
|
|
30024
30028
|
var defaultLauncher;
|
|
30025
30029
|
function getDefaultLauncher() {
|
|
30026
30030
|
if (defaultLauncher === undefined)
|
|
@@ -30033,17 +30037,73 @@ async function openPersistentBrowser(options) {
|
|
|
30033
30037
|
headless: options.headless
|
|
30034
30038
|
});
|
|
30035
30039
|
}
|
|
30040
|
+
// ../../packages/publish-harness/src/profile-dir.ts
|
|
30041
|
+
import { mkdir as mkdir2, stat } from "fs/promises";
|
|
30042
|
+
async function ensureProfileDir2(profileDir, headless) {
|
|
30043
|
+
const existing = await stat(profileDir).catch(() => null);
|
|
30044
|
+
if (existing) {
|
|
30045
|
+
if (!existing.isDirectory())
|
|
30046
|
+
throw new InvalidProfileDirError(`profileDir is not a directory: "${profileDir}".`);
|
|
30047
|
+
return;
|
|
30048
|
+
}
|
|
30049
|
+
if (headless)
|
|
30050
|
+
throw new BrowserProfileMissingError(profileDir);
|
|
30051
|
+
await mkdir2(profileDir, { recursive: true, mode: 448 });
|
|
30052
|
+
}
|
|
30053
|
+
|
|
30036
30054
|
// ../../packages/publish-harness/src/browser.ts
|
|
30037
30055
|
var DEFAULT_STEP_TIMEOUT_MS = 30000;
|
|
30038
30056
|
var DEFAULT_POLL_MS = 500;
|
|
30039
30057
|
var ATTACH_POLL_MS = 100;
|
|
30058
|
+
function createKkBrowserLauncher(loadPlaywright = () => import("playwright")) {
|
|
30059
|
+
return {
|
|
30060
|
+
async launch(request) {
|
|
30061
|
+
if (request.profileDir.trim() === "")
|
|
30062
|
+
throw new InvalidProfileDirError;
|
|
30063
|
+
const profileDir = resolve2(request.profileDir);
|
|
30064
|
+
await ensureProfileDir2(profileDir, request.headless);
|
|
30065
|
+
let playwright;
|
|
30066
|
+
try {
|
|
30067
|
+
playwright = await loadPlaywright();
|
|
30068
|
+
} catch (error51) {
|
|
30069
|
+
throw new PlaywrightUnavailableError('The "playwright" dependency is not installed. Run `bunx playwright install chromium`.', { cause: error51 });
|
|
30070
|
+
}
|
|
30071
|
+
const channel = process.env.KK_BROWSER_CHANNEL?.trim() || "chromium";
|
|
30072
|
+
let context2;
|
|
30073
|
+
try {
|
|
30074
|
+
context2 = await playwright.chromium.launchPersistentContext(profileDir, {
|
|
30075
|
+
headless: request.headless,
|
|
30076
|
+
channel,
|
|
30077
|
+
args: ["--disable-blink-features=AutomationControlled"],
|
|
30078
|
+
ignoreDefaultArgs: ["--enable-automation"]
|
|
30079
|
+
});
|
|
30080
|
+
} catch (error51) {
|
|
30081
|
+
const message = errorMessage2(error51);
|
|
30082
|
+
if (/singleton|already in use|in use by another/i.test(message)) {
|
|
30083
|
+
throw new BrowserProfileBusyError(profileDir, error51);
|
|
30084
|
+
}
|
|
30085
|
+
if (/playwright install|executable doesn't exist/i.test(message)) {
|
|
30086
|
+
throw new PlaywrightUnavailableError(`Browser channel '${channel}' is not installed. Run \`bunx playwright install chromium\` (or install Google Chrome for KK_BROWSER_CHANNEL=chrome).`, { cause: error51 });
|
|
30087
|
+
}
|
|
30088
|
+
throw error51;
|
|
30089
|
+
}
|
|
30090
|
+
await context2.addInitScript(() => {
|
|
30091
|
+
Object.defineProperty(navigator, "webdriver", { get: () => {
|
|
30092
|
+
return;
|
|
30093
|
+
} });
|
|
30094
|
+
});
|
|
30095
|
+
return context2;
|
|
30096
|
+
}
|
|
30097
|
+
};
|
|
30098
|
+
}
|
|
30099
|
+
var kkBrowserLauncher = createKkBrowserLauncher();
|
|
30040
30100
|
async function waitUntil(predicate, timeoutMs, pollMs = DEFAULT_POLL_MS) {
|
|
30041
30101
|
const deadline = Date.now() + timeoutMs;
|
|
30042
30102
|
while (Date.now() < deadline) {
|
|
30043
30103
|
if (await predicate()) {
|
|
30044
30104
|
return true;
|
|
30045
30105
|
}
|
|
30046
|
-
await new Promise((
|
|
30106
|
+
await new Promise((resolve3) => setTimeout(resolve3, pollMs));
|
|
30047
30107
|
}
|
|
30048
30108
|
return predicate();
|
|
30049
30109
|
}
|
|
@@ -30121,6 +30181,9 @@ async function resolveSelector(page, selectors, opts = {}) {
|
|
|
30121
30181
|
}
|
|
30122
30182
|
return selector;
|
|
30123
30183
|
}
|
|
30184
|
+
function errorMessage2(error51) {
|
|
30185
|
+
return error51 instanceof Error ? error51.message : String(error51);
|
|
30186
|
+
}
|
|
30124
30187
|
function pasteScript(selector, html) {
|
|
30125
30188
|
const text = html.replace(/<[^>]*>/g, " ").replace(/\s+/g, " ").trim();
|
|
30126
30189
|
return `(() => {
|
|
@@ -30736,7 +30799,7 @@ function fail(error51) {
|
|
|
30736
30799
|
return ResultSchema.parse({ ok: false, target: TARGET, error: error51 });
|
|
30737
30800
|
}
|
|
30738
30801
|
function sleep(ms) {
|
|
30739
|
-
return new Promise((
|
|
30802
|
+
return new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
30740
30803
|
}
|
|
30741
30804
|
function titleOf(content) {
|
|
30742
30805
|
return (content.title ?? "").trim();
|
|
@@ -31218,22 +31281,42 @@ function isWechatLoggedIn(page) {
|
|
|
31218
31281
|
function storageStatePath(profileDir) {
|
|
31219
31282
|
return `${profileDir}/storage-state.json`;
|
|
31220
31283
|
}
|
|
31221
|
-
async function checkWechatSession(profileDir) {
|
|
31222
|
-
const { page, context: context2 } = await openWithState(profileDir, true);
|
|
31284
|
+
async function checkWechatSession(profileDir, opts = {}) {
|
|
31285
|
+
const { page, context: context2 } = await openWithState(profileDir, opts.headless ?? true);
|
|
31223
31286
|
try {
|
|
31224
|
-
await pollLogin(page);
|
|
31287
|
+
await pollLogin(page, opts.timeoutMs);
|
|
31225
31288
|
} finally {
|
|
31226
31289
|
await context2.close();
|
|
31227
31290
|
}
|
|
31228
31291
|
}
|
|
31229
|
-
async function pollLogin(page) {
|
|
31230
|
-
const
|
|
31292
|
+
async function pollLogin(page, timeoutMs) {
|
|
31293
|
+
const deadline = timeoutMs ?? CONSOLE_READY_TIMEOUT_MS;
|
|
31294
|
+
const ready = await waitUntil(() => Promise.resolve(isConsoleReady(page)), deadline, 1000);
|
|
31231
31295
|
if (ready)
|
|
31232
31296
|
return;
|
|
31233
|
-
throw new Error(`Authentication was not confirmed within ${
|
|
31297
|
+
throw new Error(`Authentication was not confirmed within ${deadline}ms \u2014 the saved session state has ` + "likely expired: re-run `bun src/profile-check.ts login` to sign in again.");
|
|
31298
|
+
}
|
|
31299
|
+
async function openWechatLogin(opts) {
|
|
31300
|
+
const timeoutMs = opts.timeoutMs ?? 180000;
|
|
31301
|
+
const context2 = await openPersistentBrowser({
|
|
31302
|
+
profileDir: opts.profileDir,
|
|
31303
|
+
headless: false,
|
|
31304
|
+
launcher: kkBrowserLauncher
|
|
31305
|
+
});
|
|
31306
|
+
try {
|
|
31307
|
+
const page = context2.pages()[0] ?? await context2.newPage();
|
|
31308
|
+
await page.goto(CONSOLE_URL);
|
|
31309
|
+
const ready = await waitUntil(() => Promise.resolve(page.url().includes(CONSOLE_HOME_FRAGMENT)), timeoutMs, 1000);
|
|
31310
|
+
if (!ready)
|
|
31311
|
+
throw new Error(`QR scan not completed within ${timeoutMs / 1000}s`);
|
|
31312
|
+
await page.waitForTimeout(1e4);
|
|
31313
|
+
await context2.storageState({ path: storageStatePath(opts.profileDir) });
|
|
31314
|
+
} finally {
|
|
31315
|
+
await context2.close();
|
|
31316
|
+
}
|
|
31234
31317
|
}
|
|
31235
31318
|
async function openWithState(profileDir, headless) {
|
|
31236
|
-
const context2 = await openPersistentBrowser({ profileDir, headless });
|
|
31319
|
+
const context2 = await openPersistentBrowser({ profileDir, headless, launcher: kkBrowserLauncher });
|
|
31237
31320
|
try {
|
|
31238
31321
|
const stateFile = storageStatePath(profileDir);
|
|
31239
31322
|
let state;
|
|
@@ -31390,6 +31473,7 @@ export {
|
|
|
31390
31473
|
storageStatePath,
|
|
31391
31474
|
runMode,
|
|
31392
31475
|
processPublishIO,
|
|
31476
|
+
openWechatLogin,
|
|
31393
31477
|
markdownToWechatHtml,
|
|
31394
31478
|
main2 as main,
|
|
31395
31479
|
isWechatLoggedIn,
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
"name": "wechatmp-pub",
|
|
3
3
|
"kind": "publish",
|
|
4
4
|
"entry": "./dist/index.js",
|
|
5
|
+
"check": "./src/profile-check.ts",
|
|
5
6
|
"version": "1.0.0",
|
|
6
7
|
"description": "Publish plugin for the WeChat MP console via ts-browser-automation: draft-box first (ADR-022), headed publish behind a session preflight"
|
|
7
8
|
}
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
type PublishTransportPayload,
|
|
7
7
|
resolveBrowserProfileDir,
|
|
8
8
|
} from '@gobing-ai/publish-harness';
|
|
9
|
-
import { waitUntil } from '@gobing-ai/publish-harness/browser';
|
|
9
|
+
import { kkBrowserLauncher, waitUntil } from '@gobing-ai/publish-harness/browser';
|
|
10
10
|
import { BrowserProfileMissingError, openPersistentBrowser } from '@gobing-ai/ts-browser-automation';
|
|
11
11
|
import { createNodeFileSystem } from '@gobing-ai/ts-runtime';
|
|
12
12
|
import { echoError } from '@gobing-ai/ts-utils';
|
|
@@ -74,28 +74,61 @@ export function storageStatePath(profileDir: string): string {
|
|
|
74
74
|
return `${profileDir}/storage-state.json`;
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
/** Headless session preflight: throws (incl. BrowserProfileMissingError) when the profile cannot drive the console.
|
|
78
|
-
|
|
79
|
-
|
|
77
|
+
/** Headless session preflight: throws (incl. BrowserProfileMissingError) when the profile cannot drive the console.
|
|
78
|
+
* 0216: `headless: false` probes headed only and `timeoutMs` overrides the ready deadline. */
|
|
79
|
+
export async function checkWechatSession(
|
|
80
|
+
profileDir: string,
|
|
81
|
+
opts: { headless?: boolean; timeoutMs?: number } = {},
|
|
82
|
+
): Promise<void> {
|
|
83
|
+
const { page, context } = await openWithState(profileDir, opts.headless ?? true);
|
|
80
84
|
try {
|
|
81
|
-
await pollLogin(page);
|
|
85
|
+
await pollLogin(page, opts.timeoutMs);
|
|
82
86
|
} finally {
|
|
83
87
|
await context.close();
|
|
84
88
|
}
|
|
85
89
|
}
|
|
86
90
|
|
|
87
|
-
async function pollLogin(page: Page): Promise<void> {
|
|
88
|
-
const
|
|
91
|
+
async function pollLogin(page: Page, timeoutMs?: number): Promise<void> {
|
|
92
|
+
const deadline = timeoutMs ?? CONSOLE_READY_TIMEOUT_MS;
|
|
93
|
+
const ready = await waitUntil(() => Promise.resolve(isConsoleReady(page)), deadline, 1000);
|
|
89
94
|
if (ready) return;
|
|
90
95
|
throw new Error(
|
|
91
|
-
`Authentication was not confirmed within ${
|
|
96
|
+
`Authentication was not confirmed within ${deadline}ms — the saved session state has ` +
|
|
92
97
|
'likely expired: re-run `bun src/profile-check.ts login` to sign in again.',
|
|
93
98
|
);
|
|
94
99
|
}
|
|
95
100
|
|
|
101
|
+
/** Headed one-time login: open the console, wait for the QR scan to land on `/cgi-bin/home`, let
|
|
102
|
+
* the console finish its post-auth Set-Cookies, then capture the durable storageState file —
|
|
103
|
+
* mp.weixin.qq.com grant cookies do not survive a Chromium restart, so the saved state (not the
|
|
104
|
+
* profile cookie store) is the session artifact the publish flow re-injects. Shared by the CLI
|
|
105
|
+
* (`profile-check login`, 0216) so the publish flow and the probe use one login path. */
|
|
106
|
+
export async function openWechatLogin(opts: { profileDir: string; timeoutMs?: number }): Promise<void> {
|
|
107
|
+
const timeoutMs = opts.timeoutMs ?? 180_000;
|
|
108
|
+
const context = await openPersistentBrowser({
|
|
109
|
+
profileDir: opts.profileDir,
|
|
110
|
+
headless: false,
|
|
111
|
+
launcher: kkBrowserLauncher,
|
|
112
|
+
});
|
|
113
|
+
try {
|
|
114
|
+
const page = context.pages()[0] ?? (await context.newPage());
|
|
115
|
+
await page.goto(CONSOLE_URL);
|
|
116
|
+
const ready = await waitUntil(
|
|
117
|
+
() => Promise.resolve(page.url().includes(CONSOLE_HOME_FRAGMENT)),
|
|
118
|
+
timeoutMs,
|
|
119
|
+
1000,
|
|
120
|
+
);
|
|
121
|
+
if (!ready) throw new Error(`QR scan not completed within ${timeoutMs / 1000}s`);
|
|
122
|
+
await page.waitForTimeout(10_000); // settle: let the console finish its post-auth Set-Cookies
|
|
123
|
+
await context.storageState({ path: storageStatePath(opts.profileDir) });
|
|
124
|
+
} finally {
|
|
125
|
+
await context.close();
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
96
129
|
/** Launch, inject the saved login cookies, and land on the console. Caller owns closing the context. */
|
|
97
130
|
async function openWithState(profileDir: string, headless: boolean): Promise<{ page: Page; context: BrowserContext }> {
|
|
98
|
-
const context = await openPersistentBrowser({ profileDir, headless });
|
|
131
|
+
const context = await openPersistentBrowser({ profileDir, headless, launcher: kkBrowserLauncher });
|
|
99
132
|
try {
|
|
100
133
|
const stateFile = storageStatePath(profileDir);
|
|
101
134
|
let state:
|
|
@@ -1,48 +1,92 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
/**
|
|
2
|
+
* WeChat MP profile-session capability (0216, ADR-032 probe contract).
|
|
3
|
+
*
|
|
4
|
+
* `login` opens the console headed and resolves once the QR scan lands on `/cgi-bin/home`, then
|
|
5
|
+
* captures the durable `storageState` file — mp.weixin.qq.com grant cookies do not survive a
|
|
6
|
+
* Chromium restart, so the saved state (not the profile cookie store) is the session artifact.
|
|
7
|
+
* `check` reopens the profile with that state re-injected and reports `verified` or `refused`
|
|
8
|
+
* as the LAST line on stdout, one JSON object — `kk plugin check` parses it. Exit codes:
|
|
9
|
+
* 0 verified, 1 refused, 2 usage error. No cookie, token or storageState value is ever printed;
|
|
10
|
+
* the profile directory is the only detail that leaves the process.
|
|
11
|
+
*/
|
|
12
|
+
import { parseArgs } from 'node:util';
|
|
13
|
+
import { resolveChannelProfileDir } from '@gobing-ai/publish-harness/browser';
|
|
14
|
+
import { echo, echoError } from '@gobing-ai/ts-utils';
|
|
15
|
+
import { CHANNEL, checkWechatSession, openWechatLogin } from './index';
|
|
6
16
|
|
|
7
|
-
const
|
|
17
|
+
const USAGE = 'usage: wechatmp profile-check [login|check] [--profile <dir>] [--timeout <ms>] [--headed]';
|
|
8
18
|
const LOGIN_TIMEOUT_MS = 180_000;
|
|
9
|
-
const LOGGED_IN_FRAGMENT = '/cgi-bin/home';
|
|
10
19
|
|
|
11
|
-
|
|
12
|
-
|
|
20
|
+
interface WechatVerdict {
|
|
21
|
+
status: 'verified' | 'refused';
|
|
22
|
+
profileDir: string;
|
|
23
|
+
detail: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export async function main(argv: string[] = process.argv.slice(2)): Promise<number> {
|
|
27
|
+
let command: string;
|
|
28
|
+
let profileDir: string;
|
|
29
|
+
let timeoutMs: number | undefined;
|
|
30
|
+
let headed = false;
|
|
31
|
+
try {
|
|
32
|
+
const { positionals, values } = parseArgs({
|
|
33
|
+
args: argv,
|
|
34
|
+
allowPositionals: true,
|
|
35
|
+
options: {
|
|
36
|
+
profile: { type: 'string' },
|
|
37
|
+
timeout: { type: 'string' },
|
|
38
|
+
headed: { type: 'boolean' },
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
command = positionals[0] ?? 'check';
|
|
42
|
+
if (command !== 'login' && command !== 'check') {
|
|
43
|
+
throw new Error(`unknown command '${command}'`);
|
|
44
|
+
}
|
|
45
|
+
headed = values.headed === true;
|
|
46
|
+
if (values.timeout !== undefined) {
|
|
47
|
+
timeoutMs = Number(values.timeout);
|
|
48
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs < 0) {
|
|
49
|
+
throw new Error(`--timeout must be a non-negative number of ms, got '${values.timeout}'`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
profileDir = resolveChannelProfileDir(CHANNEL, values.profile);
|
|
53
|
+
} catch (error) {
|
|
54
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
55
|
+
echoError(`wechatmp profile-check: ${message} — ${USAGE}`);
|
|
56
|
+
echo(JSON.stringify({ status: 'error', detail: message }));
|
|
57
|
+
return 2;
|
|
58
|
+
}
|
|
13
59
|
|
|
14
|
-
|
|
15
|
-
if (verb === 'login') {
|
|
16
|
-
echo(
|
|
17
|
-
`wechatmp login: opening the console in a headed browser — scan the QR once (timeout ${LOGIN_TIMEOUT_MS / 1000}s)`,
|
|
18
|
-
);
|
|
19
|
-
const context = await openPersistentBrowser({ profileDir, headless: false });
|
|
60
|
+
if (command === 'login') {
|
|
20
61
|
try {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
);
|
|
28
|
-
if (!ready) throw new Error(`QR scan not completed within ${LOGIN_TIMEOUT_MS / 1000}s`);
|
|
29
|
-
await page.waitForTimeout(10_000); // settle: let the console finish its post-auth Set-Cookies
|
|
30
|
-
// The Chromium profile store drops the grant cookies on restart even though they carry
|
|
31
|
-
// multi-day expiries — the durable session artifact is the captured storageState file,
|
|
32
|
-
// which the publish flow re-injects into every launch.
|
|
33
|
-
await context.storageState({ path: storageStatePath(profileDir) });
|
|
34
|
-
echo(`wechatmp login: session saved in ${storageStatePath(profileDir)}`);
|
|
35
|
-
} finally {
|
|
36
|
-
await context.close();
|
|
62
|
+
await openWechatLogin({ profileDir, timeoutMs: timeoutMs ?? LOGIN_TIMEOUT_MS });
|
|
63
|
+
echo(`wechatmp profile login verified: ${profileDir}`);
|
|
64
|
+
return 0;
|
|
65
|
+
} catch (error) {
|
|
66
|
+
echoError(`wechatmp profile login failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
67
|
+
return 1;
|
|
37
68
|
}
|
|
38
|
-
} else if (verb === 'check') {
|
|
39
|
-
await checkWechatSession(profileDir);
|
|
40
|
-
echo(`wechatmp session: OK (${profileDir})`);
|
|
41
|
-
} else {
|
|
42
|
-
echo('usage: bun src/profile-check.ts login|check');
|
|
43
|
-
process.exit(1);
|
|
44
69
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
70
|
+
|
|
71
|
+
let verdict: WechatVerdict;
|
|
72
|
+
try {
|
|
73
|
+
await checkWechatSession(profileDir, { headless: !headed, timeoutMs });
|
|
74
|
+
verdict = {
|
|
75
|
+
status: 'verified',
|
|
76
|
+
profileDir,
|
|
77
|
+
detail: `authenticated wechatmp console session observed ${headed ? 'via a headed pass' : 'headlessly'} via profile ${profileDir} (read-only)`,
|
|
78
|
+
};
|
|
79
|
+
} catch (error) {
|
|
80
|
+
verdict = {
|
|
81
|
+
status: 'refused',
|
|
82
|
+
profileDir,
|
|
83
|
+
detail: `wechatmp readiness refused: ${error instanceof Error ? error.message : String(error)}`,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
echo(JSON.stringify(verdict));
|
|
87
|
+
return verdict.status === 'verified' ? 0 : 1;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (import.meta.main) {
|
|
91
|
+
process.exit(await main());
|
|
48
92
|
}
|