@gobing-ai/knowledge-kit 0.0.32 → 0.0.34
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 +43047 -24724
- 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 +16 -21
- package/plugins/generations/daily-article-gen/src/index.ts +8 -12
- package/plugins/generations/dailynews-gen/dist/index.js +23 -21
- package/plugins/generations/dailynews-gen/src/script-builder.ts +25 -26
- 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 +171 -153
- package/plugins/generations/image-gen/presets/formats/xhs-card.yaml +16 -14
- package/plugins/generations/image-gen/presets/styles/xhs-knowledge.yaml +2 -2
- package/plugins/generations/image-gen/src/compose/card.ts +17 -2
- 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 +27 -0
- package/plugins/kk/decisions/kk-items.yaml +179 -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 +2023 -0
- package/plugins/kk/scripts/daily-voice-style.zh.md +15 -10
- package/plugins/kk/scripts/kk-workflow-stages.ts +253 -1368
- package/plugins/kk/skills/content-safety/SKILL.md +39 -8
- package/plugins/kk/skills/content-safety/references/platforms/apple-podcasts.md +2 -2
- 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 +256 -0
- package/plugins/kk/workflows/kk-daily-ai-voice.yaml +9 -3
- package/plugins/kk/workflows/kk-daily-ai-voice2.yaml +774 -0
- package/plugins/kk/workflows/kk-daily-safety.yaml +167 -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 +154 -59
- package/plugins/publishings/xhs-pub/plugin.json +1 -0
- package/plugins/publishings/xhs-pub/src/flow.ts +9 -3
- package/plugins/publishings/xhs-pub/src/index.ts +119 -9
- 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
|
@@ -10,10 +10,11 @@ import {
|
|
|
10
10
|
import {
|
|
11
11
|
checkChannelSession,
|
|
12
12
|
createShadowFinder,
|
|
13
|
+
kkBrowserLauncher,
|
|
13
14
|
resolveChannelProfileDir,
|
|
14
15
|
type ShadowCdpSession,
|
|
15
16
|
} from '@gobing-ai/publish-harness/browser';
|
|
16
|
-
import {
|
|
17
|
+
import type { BrowserLauncher } from '@gobing-ai/ts-browser-automation';
|
|
17
18
|
import { createNodeFileSystem } from '@gobing-ai/ts-runtime';
|
|
18
19
|
import { echoError } from '@gobing-ai/ts-utils';
|
|
19
20
|
import { type AutomationGuard, createAutomationGuard } from './automation-guard';
|
|
@@ -72,6 +73,71 @@ function fail(error: string): Result {
|
|
|
72
73
|
return ResultSchema.parse({ ok: false, target: TARGET, error });
|
|
73
74
|
}
|
|
74
75
|
|
|
76
|
+
/** One operation of a visit: its own Content and the mode input validated before any browser work. */
|
|
77
|
+
interface VisitOperation {
|
|
78
|
+
content: Content;
|
|
79
|
+
input: ModeInput;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* A follow-up operation of a visit: planned, or refused with the reason it never reached the console.
|
|
84
|
+
* A refused follow-up is reported as its own failed Result entry — it can never fail the note the
|
|
85
|
+
* visit was opened for (ADR-025 amendment 2026-10-09).
|
|
86
|
+
*/
|
|
87
|
+
type VisitFollowUp = { content: Content; operation: string; input: ModeInput } | { operation: string; error: string };
|
|
88
|
+
|
|
89
|
+
interface VisitPlan {
|
|
90
|
+
/** The requested operation, resolved and validated exactly as before task 0236. */
|
|
91
|
+
primary: VisitOperation;
|
|
92
|
+
/** The primary Content's `metadata.followUps`, in declared order. */
|
|
93
|
+
followUps: VisitFollowUp[];
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Plan a visit (ADR-025 amendment 2026-10-09, task 0236 option A): the requested operation plus the
|
|
98
|
+
* follow-ups the caller attached to the primary Content's `metadata.followUps`. One headed visit may
|
|
99
|
+
* compose several notes under ONE cap entry — the cap still counts visits, not notes.
|
|
100
|
+
*
|
|
101
|
+
* The primary is planned as it always was: an unplannable primary is a `fail` and no browser opens.
|
|
102
|
+
* A follow-up that cannot be planned (not a Content, an undeclared operation, a missing or unreadable
|
|
103
|
+
* artifact) is refused here, before any console work, and reported as its own entry instead. A
|
|
104
|
+
* `metadata.followUps` that is not an array is a caller error, so it fails loud before any browser.
|
|
105
|
+
*/
|
|
106
|
+
async function planVisit(
|
|
107
|
+
primary: VisitOperation,
|
|
108
|
+
content: Content,
|
|
109
|
+
): Promise<{ plan: VisitPlan; error?: undefined } | { plan?: undefined; error: string }> {
|
|
110
|
+
const raw = content.metadata?.followUps;
|
|
111
|
+
if (raw === undefined) return { plan: { primary, followUps: [] } };
|
|
112
|
+
if (!Array.isArray(raw)) {
|
|
113
|
+
return {
|
|
114
|
+
error: `followUps validation: Content.metadata.followUps must be an array of Content objects, got ${typeof raw}`,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
const followUps: VisitFollowUp[] = [];
|
|
118
|
+
for (const [index, entry] of raw.entries()) {
|
|
119
|
+
const label = `followUps[${index}]`;
|
|
120
|
+
const parsed = ContentSchema.safeParse(entry);
|
|
121
|
+
if (!parsed.success) {
|
|
122
|
+
followUps.push({ operation: label, error: `${label} is not a Content object` });
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
const operation = typeof parsed.data.metadata?.operation === 'string' ? parsed.data.metadata.operation : label;
|
|
126
|
+
const requested = resolveXhsOperation(undefined, parsed.data);
|
|
127
|
+
if (requested.error !== undefined) {
|
|
128
|
+
followUps.push({ operation, error: requested.error });
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
const validation = await validateModeInput(requested.operation, parsed.data);
|
|
132
|
+
if (validation.error !== undefined) {
|
|
133
|
+
followUps.push({ operation, error: validation.error });
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
followUps.push({ content: parsed.data, operation: requested.operation, input: validation.input });
|
|
137
|
+
}
|
|
138
|
+
return { plan: { primary, followUps } };
|
|
139
|
+
}
|
|
140
|
+
|
|
75
141
|
/** CDP is Chromium-only; when unavailable the submit step fails loud instead of guessing. */
|
|
76
142
|
export async function createShadowProbe(
|
|
77
143
|
context: { newCDPSession?(page: unknown): Promise<ShadowCdpSession> },
|
|
@@ -93,15 +159,15 @@ export async function isXhsConsoleReady(page: XhsPage): Promise<boolean> {
|
|
|
93
159
|
}
|
|
94
160
|
|
|
95
161
|
/**
|
|
96
|
-
* Production launcher: the
|
|
162
|
+
* Production launcher: the harness kk launcher (0214; full-Chromium channel + stealth). Named so the
|
|
97
163
|
* migration is provable offline — tests assert this binding, never launch a real browser.
|
|
98
164
|
*/
|
|
99
|
-
export const defaultLauncher =
|
|
165
|
+
export const defaultLauncher = kkBrowserLauncher.launch;
|
|
100
166
|
|
|
101
167
|
/**
|
|
102
168
|
* Build the default page opener. The launcher is injected so the seam (page wrapping, shadow
|
|
103
169
|
* probe wiring, context close, launch-failure message) is testable without launching a browser;
|
|
104
|
-
* production uses the
|
|
170
|
+
* production uses the harness `kkBrowserLauncher` (@gobing-ai/publish-harness/browser, 0214).
|
|
105
171
|
*/
|
|
106
172
|
export function makeDefaultOpenPage(
|
|
107
173
|
launch: (options: { profileDir: string; headless: boolean }) => Promise<unknown> = defaultLauncher,
|
|
@@ -147,6 +213,8 @@ export interface SessionCheckOptions {
|
|
|
147
213
|
profileDir: string;
|
|
148
214
|
timeoutMs?: number;
|
|
149
215
|
launcher?: BrowserLauncher;
|
|
216
|
+
/** 0216: skip the headless pass and probe headed only (manual `check --headed`). */
|
|
217
|
+
headedOnly?: boolean;
|
|
150
218
|
}
|
|
151
219
|
|
|
152
220
|
/**
|
|
@@ -173,6 +241,7 @@ export async function checkXhsProfileSession(opts: SessionCheckOptions): Promise
|
|
|
173
241
|
profileDir: opts.profileDir,
|
|
174
242
|
launcher: opts.launcher,
|
|
175
243
|
timeoutMs: opts.timeoutMs ?? PREFLIGHT_TIMEOUT_MS,
|
|
244
|
+
headedOnly: opts.headedOnly === true,
|
|
176
245
|
},
|
|
177
246
|
);
|
|
178
247
|
}
|
|
@@ -235,13 +304,20 @@ export class XhsBrowserTransport implements PublishTransport {
|
|
|
235
304
|
if (validation.error !== undefined) return fail(validation.error);
|
|
236
305
|
const input: ModeInput = validation.input;
|
|
237
306
|
|
|
307
|
+
// ADR-025 amendment (2026-10-09, task 0236 option A): one visit may compose more than one
|
|
308
|
+
// note. The follow-ups ride the primary Content's `metadata.followUps` and are planned here,
|
|
309
|
+
// with the primary, before any browser work.
|
|
310
|
+
const visited = await planVisit({ content: payload.content, input }, payload.content);
|
|
311
|
+
if (visited.error !== undefined) return fail(visited.error);
|
|
312
|
+
const visit = visited.plan;
|
|
313
|
+
|
|
238
314
|
const override = typeof payload.options?.profileDir === 'string' ? payload.options.profileDir : undefined;
|
|
239
315
|
const profileDir = resolveChannelProfileDir(CHANNEL, override);
|
|
240
|
-
const publishStatus = payload.content.metadata?.publishStatus === 'public' ? 'public' : 'draft';
|
|
241
316
|
|
|
242
317
|
// ADR-025 automation guard — both gates run before any browser opens.
|
|
243
318
|
// 1. Frequency cap: the operator's platform warning makes a repeated console visit an
|
|
244
|
-
// account-level risk, not merely a failed run.
|
|
319
|
+
// account-level risk, not merely a failed run. The cap counts VISITS: one allow/record
|
|
320
|
+
// per visit covers every note the visit composes.
|
|
245
321
|
const cap = this.automation.allow('publish');
|
|
246
322
|
if (!cap.allowed) return fail(`automation cap: ${cap.reason}`);
|
|
247
323
|
// 2. Headless session preflight: an unauthenticated profile must never produce a headed
|
|
@@ -262,6 +338,41 @@ export class XhsBrowserTransport implements PublishTransport {
|
|
|
262
338
|
return fail(error instanceof Error ? error.message : String(error));
|
|
263
339
|
}
|
|
264
340
|
const { page, close } = opened;
|
|
341
|
+
try {
|
|
342
|
+
// The visit's own Result is the primary operation's: a failed primary ends the visit, as
|
|
343
|
+
// it always did, and only a primary that stood reports its follow-ups.
|
|
344
|
+
const primary = await this.runStep(visit.primary.input, visit.primary.content, page, profileDir);
|
|
345
|
+
if (!primary.ok || visit.followUps.length === 0) return primary;
|
|
346
|
+
// One Result entry per operation, in declared order; a refused and a failed follow-up
|
|
347
|
+
// are the same kind of entry, and neither can fail the note the visit was opened for.
|
|
348
|
+
const followUps: Result[] = [];
|
|
349
|
+
for (const followUp of visit.followUps) {
|
|
350
|
+
const step =
|
|
351
|
+
'error' in followUp
|
|
352
|
+
? fail(`follow-up (${followUp.operation}): ${followUp.error}`)
|
|
353
|
+
: await this.runStep(followUp.input, followUp.content, page, profileDir);
|
|
354
|
+
// Every entry names the operation it was planned under — a failed or refused one too,
|
|
355
|
+
// so the caller can tell which note fell; the step's own metadata wins.
|
|
356
|
+
followUps.push(
|
|
357
|
+
ResultSchema.parse({ ...step, metadata: { operation: followUp.operation, ...step.metadata } }),
|
|
358
|
+
);
|
|
359
|
+
}
|
|
360
|
+
return ResultSchema.parse({ ...primary, metadata: { ...primary.metadata, followUps } });
|
|
361
|
+
} finally {
|
|
362
|
+
await close();
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Run one operation of the visit in the page the visit already opened. Every step enters the
|
|
368
|
+
* console from its landing view: the primary needs the login gate and the pre-entry draft
|
|
369
|
+
* baseline, and a follow-up needs both again — the previous note's editor replaces the header,
|
|
370
|
+
* and the baseline must be read before THIS note's mode is entered.
|
|
371
|
+
*
|
|
372
|
+
* A step never throws: its failure is that operation's own `ok:false` Result, which is what keeps
|
|
373
|
+
* a failed follow-up from failing the visit (ADR-025 amendment 2026-10-09).
|
|
374
|
+
*/
|
|
375
|
+
private async runStep(input: ModeInput, content: Content, page: XhsPage, profileDir: string): Promise<Result> {
|
|
265
376
|
const act = async <T>(what: string, fn: () => Promise<T>): Promise<T> => {
|
|
266
377
|
try {
|
|
267
378
|
return await fn();
|
|
@@ -279,6 +390,7 @@ export class XhsBrowserTransport implements PublishTransport {
|
|
|
279
390
|
);
|
|
280
391
|
}
|
|
281
392
|
|
|
393
|
+
const publishStatus = content.metadata?.publishStatus === 'public' ? 'public' : 'draft';
|
|
282
394
|
// The draft counter and any save timestamps exist only on the landing view, so the
|
|
283
395
|
// baseline is captured before the mode is entered (the editor replaces the header).
|
|
284
396
|
const draftBaseline =
|
|
@@ -286,7 +398,7 @@ export class XhsBrowserTransport implements PublishTransport {
|
|
|
286
398
|
|
|
287
399
|
return await runMode(input, {
|
|
288
400
|
page,
|
|
289
|
-
content
|
|
401
|
+
content,
|
|
290
402
|
publishStatus,
|
|
291
403
|
profileDir,
|
|
292
404
|
driver: this.driver,
|
|
@@ -297,8 +409,6 @@ export class XhsBrowserTransport implements PublishTransport {
|
|
|
297
409
|
});
|
|
298
410
|
} catch (error) {
|
|
299
411
|
return fail(error instanceof Error ? error.message : String(error));
|
|
300
|
-
} finally {
|
|
301
|
-
await close();
|
|
302
412
|
}
|
|
303
413
|
}
|
|
304
414
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { trySelectors } from '@gobing-ai/publish-harness';
|
|
2
|
+
import { waitUntil } from '@gobing-ai/publish-harness/browser';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* The console's page seam (ADR-029) and the helpers every xhs operation shares.
|
|
@@ -10,6 +11,9 @@ import { trySelectors } from '@gobing-ai/publish-harness';
|
|
|
10
11
|
*/
|
|
11
12
|
|
|
12
13
|
export const POLL_MS = 500;
|
|
14
|
+
|
|
15
|
+
// The shared poll (0184 R2); re-exported so flow/index keep importing it from here.
|
|
16
|
+
export { waitUntil };
|
|
13
17
|
export const STEP_TIMEOUT_MS = 30_000;
|
|
14
18
|
|
|
15
19
|
/** The console's mode tab bar; it mounts late and renders every tab several times over. */
|
|
@@ -120,23 +124,6 @@ export async function clickCreatorTab(
|
|
|
120
124
|
}
|
|
121
125
|
}
|
|
122
126
|
|
|
123
|
-
/**
|
|
124
|
-
* Poll `predicate` every `pollMs` until the deadline, then evaluate it one final time. The trailing
|
|
125
|
-
* call matters: the condition often becomes true exactly at the boundary.
|
|
126
|
-
*/
|
|
127
|
-
export async function waitUntil(
|
|
128
|
-
predicate: () => Promise<boolean>,
|
|
129
|
-
timeoutMs: number,
|
|
130
|
-
pollMs = POLL_MS,
|
|
131
|
-
): Promise<boolean> {
|
|
132
|
-
const deadline = Date.now() + timeoutMs;
|
|
133
|
-
while (Date.now() < deadline) {
|
|
134
|
-
if (await predicate()) return true;
|
|
135
|
-
await new Promise((resolve) => setTimeout(resolve, pollMs));
|
|
136
|
-
}
|
|
137
|
-
return predicate();
|
|
138
|
-
}
|
|
139
|
-
|
|
140
127
|
export function wrapPlaywrightPage(raw: unknown, shadow?: ShadowProbe): XhsPage {
|
|
141
128
|
const pw = raw as {
|
|
142
129
|
goto(url: string, options?: Record<string, unknown>): Promise<unknown>;
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
* - `login` recovers an absent/expired session headed via the upstream
|
|
7
7
|
* `loginWithProfile`, polled with the same XHS-owned readiness gate the publish
|
|
8
8
|
* flow uses;
|
|
9
|
-
* - `check` reopens the existing profile headless
|
|
9
|
+
* - `check` reopens the existing profile (headless by default; `--headed` skips the headless
|
|
10
|
+
* pass and probes headed only, 0216) and reports the session as
|
|
10
11
|
* `verified` or `refused` — a site refusal, expired session, or missing profile
|
|
11
12
|
* is an explicit failed readiness, never a success. The upstream launcher never
|
|
12
13
|
* creates a profile headless, so a check cannot fabricate a session from a
|
|
@@ -21,7 +22,7 @@
|
|
|
21
22
|
* the full recipe lives in docs/design/xhs-image-cards.md.
|
|
22
23
|
*/
|
|
23
24
|
import { parseArgs } from 'node:util';
|
|
24
|
-
import { resolveChannelProfileDir } from '@gobing-ai/publish-harness/browser';
|
|
25
|
+
import { kkBrowserLauncher, resolveChannelProfileDir } from '@gobing-ai/publish-harness/browser';
|
|
25
26
|
import { type BrowserLauncher, loginWithProfile } from '@gobing-ai/ts-browser-automation';
|
|
26
27
|
import { echo, echoError } from '@gobing-ai/ts-utils';
|
|
27
28
|
import { type AutomationGuard, createAutomationGuard } from './automation-guard';
|
|
@@ -60,11 +61,20 @@ export async function loginProfile(opts: ProfileLoginOptions): Promise<void> {
|
|
|
60
61
|
url: PUBLISH_URL,
|
|
61
62
|
isAuthenticated: (page) => isXhsConsoleReady(wrapPlaywrightPage(page)),
|
|
62
63
|
timeoutMs: opts.timeoutMs ?? LOGIN_TIMEOUT_MS,
|
|
63
|
-
launcher: opts.launcher,
|
|
64
|
+
launcher: opts.launcher ?? kkBrowserLauncher,
|
|
64
65
|
});
|
|
65
66
|
}
|
|
66
67
|
|
|
67
|
-
/**
|
|
68
|
+
/** Exit 2 with the human usage on stderr and the ADR-032 `error` verdict as the last stdout line. */
|
|
69
|
+
function usageError(message: string): number {
|
|
70
|
+
echoError(
|
|
71
|
+
`profile-check: ${message} — usage: profile-check.ts [login|check] [--profile <dir>] [--timeout <ms>] [--headed]`,
|
|
72
|
+
);
|
|
73
|
+
echo(JSON.stringify({ status: 'error', detail: message }));
|
|
74
|
+
return 2;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** `login|check [--profile <dir>] [--timeout <ms>] [--headed]`; profile precedence matches the publish flow. */
|
|
68
78
|
export async function main(
|
|
69
79
|
argv: string[] = process.argv.slice(2),
|
|
70
80
|
launcher?: BrowserLauncher,
|
|
@@ -73,13 +83,19 @@ export async function main(
|
|
|
73
83
|
let command: string;
|
|
74
84
|
let profileDir: string;
|
|
75
85
|
let timeoutMs: number | undefined;
|
|
86
|
+
let headed = false;
|
|
76
87
|
try {
|
|
77
88
|
const { positionals, values } = parseArgs({
|
|
78
89
|
args: argv,
|
|
79
90
|
allowPositionals: true,
|
|
80
|
-
options: {
|
|
91
|
+
options: {
|
|
92
|
+
profile: { type: 'string' },
|
|
93
|
+
timeout: { type: 'string' },
|
|
94
|
+
headed: { type: 'boolean' },
|
|
95
|
+
},
|
|
81
96
|
});
|
|
82
97
|
command = positionals[0] ?? 'check';
|
|
98
|
+
headed = values.headed === true;
|
|
83
99
|
if (values.timeout !== undefined) {
|
|
84
100
|
timeoutMs = Number(values.timeout);
|
|
85
101
|
if (!Number.isFinite(timeoutMs) || timeoutMs < 0) {
|
|
@@ -88,10 +104,7 @@ export async function main(
|
|
|
88
104
|
}
|
|
89
105
|
profileDir = resolveChannelProfileDir(CHANNEL, values.profile);
|
|
90
106
|
} catch (error) {
|
|
91
|
-
|
|
92
|
-
`profile-check: ${error instanceof Error ? error.message : String(error)} — usage: profile-check.ts [login|check] [--profile <dir>] [--timeout <ms>]`,
|
|
93
|
-
);
|
|
94
|
-
return 1;
|
|
107
|
+
return usageError(error instanceof Error ? error.message : String(error));
|
|
95
108
|
}
|
|
96
109
|
if (command === 'login') {
|
|
97
110
|
try {
|
|
@@ -104,21 +117,21 @@ export async function main(
|
|
|
104
117
|
}
|
|
105
118
|
}
|
|
106
119
|
if (command !== 'check') {
|
|
107
|
-
|
|
108
|
-
`profile-check: unknown command '${command}' — usage: profile-check.ts [login|check] [--profile <dir>] [--timeout <ms>]`,
|
|
109
|
-
);
|
|
110
|
-
return 1;
|
|
120
|
+
return usageError(`unknown command '${command}'`);
|
|
111
121
|
}
|
|
112
122
|
// ADR-025: a manual session check is a real console visit, so it draws on the shared 2h
|
|
113
123
|
// automation budget rather than a separate one. `login` is deliberately uncapped above: it is
|
|
114
124
|
// operator-interactive, so capping it would only block recovery from an expired session.
|
|
115
125
|
const cap = guard.allow('check');
|
|
116
126
|
if (!cap.allowed) {
|
|
117
|
-
|
|
127
|
+
// The budget refusal is still a readiness verdict (0216 contract): emit the JSON line so
|
|
128
|
+
// `kk plugin check` reports a refusal with the operator hint instead of a malformed probe.
|
|
129
|
+
echo(JSON.stringify({ status: 'refused', profileDir, detail: `xhs readiness refused: ${cap.reason}` }));
|
|
130
|
+
echoError(cap.reason);
|
|
118
131
|
return 1;
|
|
119
132
|
}
|
|
120
133
|
guard.record('check');
|
|
121
|
-
const outcome = await checkXhsProfileSession({ profileDir, timeoutMs, launcher });
|
|
134
|
+
const outcome = await checkXhsProfileSession({ profileDir, timeoutMs, launcher, headedOnly: headed });
|
|
122
135
|
echo(JSON.stringify(outcome));
|
|
123
136
|
if (outcome.status !== 'verified') {
|
|
124
137
|
echoError(outcome.detail);
|
|
@@ -14642,7 +14642,7 @@ var init_zod = __esm(() => {
|
|
|
14642
14642
|
init_external();
|
|
14643
14643
|
});
|
|
14644
14644
|
|
|
14645
|
-
// ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.
|
|
14645
|
+
// ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.21/node_modules/@gobing-ai/ts-utils/dist/errors.js
|
|
14646
14646
|
var ErrorCode;
|
|
14647
14647
|
var init_errors3 = __esm(() => {
|
|
14648
14648
|
ErrorCode = {
|
|
@@ -14653,7 +14653,7 @@ var init_errors3 = __esm(() => {
|
|
|
14653
14653
|
};
|
|
14654
14654
|
});
|
|
14655
14655
|
|
|
14656
|
-
// ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.
|
|
14656
|
+
// ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.21/node_modules/@gobing-ai/ts-utils/dist/api-response.js
|
|
14657
14657
|
var API_ERROR_CODES, ERROR_CODE_TO_HTTP, CLIENT_SAFE_CODES;
|
|
14658
14658
|
var init_api_response = __esm(() => {
|
|
14659
14659
|
init_errors3();
|
|
@@ -14676,13 +14676,13 @@ var init_api_response = __esm(() => {
|
|
|
14676
14676
|
CLIENT_SAFE_CODES = new Set([ErrorCode.NotFound, ErrorCode.Validation, ErrorCode.Conflict]);
|
|
14677
14677
|
});
|
|
14678
14678
|
|
|
14679
|
-
// ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.
|
|
14679
|
+
// ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.21/node_modules/@gobing-ai/ts-utils/dist/cursor.js
|
|
14680
14680
|
var init_cursor = () => {};
|
|
14681
14681
|
|
|
14682
|
-
// ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.
|
|
14682
|
+
// ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.21/node_modules/@gobing-ai/ts-utils/dist/event-severity.js
|
|
14683
14683
|
var init_event_severity = () => {};
|
|
14684
14684
|
|
|
14685
|
-
// ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.
|
|
14685
|
+
// ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.21/node_modules/@gobing-ai/ts-utils/dist/output.js
|
|
14686
14686
|
function processStream(name) {
|
|
14687
14687
|
const proc = globalThis.process;
|
|
14688
14688
|
const stream = proc?.[name];
|
|
@@ -14700,7 +14700,7 @@ function echoError(message, target = defaultStderrTarget ?? processStream("stder
|
|
|
14700
14700
|
}
|
|
14701
14701
|
var defaultStderrTarget;
|
|
14702
14702
|
|
|
14703
|
-
// ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.
|
|
14703
|
+
// ../../node_modules/.bun/@gobing-ai+ts-utils@0.5.21/node_modules/@gobing-ai/ts-utils/dist/index.js
|
|
14704
14704
|
var init_dist = __esm(() => {
|
|
14705
14705
|
init_api_response();
|
|
14706
14706
|
init_cursor();
|
|
@@ -21698,7 +21698,7 @@ var init_dist2 = __esm(() => {
|
|
|
21698
21698
|
$visitAsync = visit.visitAsync;
|
|
21699
21699
|
});
|
|
21700
21700
|
|
|
21701
|
-
// ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.
|
|
21701
|
+
// ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.21+44edd5c4d6372504/node_modules/@gobing-ai/ts-runtime/dist/config.js
|
|
21702
21702
|
var configSchema;
|
|
21703
21703
|
var init_config = __esm(() => {
|
|
21704
21704
|
init_dist2();
|
|
@@ -21722,7 +21722,7 @@ var init_config = __esm(() => {
|
|
|
21722
21722
|
});
|
|
21723
21723
|
});
|
|
21724
21724
|
|
|
21725
|
-
// ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.
|
|
21725
|
+
// ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.21+44edd5c4d6372504/node_modules/@gobing-ai/ts-runtime/dist/file-system-node.js
|
|
21726
21726
|
import { appendFileSync, cpSync, createReadStream, createWriteStream, existsSync, mkdirSync, readdirSync, readFileSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "fs";
|
|
21727
21727
|
import { dirname, resolve as resolvePath } from "path";
|
|
21728
21728
|
function createNodeFileSystem(root, paths) {
|
|
@@ -21897,11 +21897,12 @@ var PluginManifestSchema = exports_external.looseObject({
|
|
|
21897
21897
|
name: exports_external.string().min(1),
|
|
21898
21898
|
kind: PluginKindSchema,
|
|
21899
21899
|
entry: exports_external.string().min(1),
|
|
21900
|
+
check: exports_external.string().min(1).optional(),
|
|
21900
21901
|
version: exports_external.string().optional(),
|
|
21901
21902
|
description: exports_external.string().optional(),
|
|
21902
21903
|
operations: exports_external.record(exports_external.string(), PluginOperationSchema).optional()
|
|
21903
21904
|
});
|
|
21904
|
-
// ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.
|
|
21905
|
+
// ../../node_modules/.bun/@gobing-ai+ts-runtime@0.5.21+44edd5c4d6372504/node_modules/@gobing-ai/ts-runtime/dist/index.js
|
|
21905
21906
|
init_file_system_node();
|
|
21906
21907
|
init_config();
|
|
21907
21908
|
|