job-pro 0.9.3 → 0.9.5

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/dist/alibaba.js CHANGED
@@ -476,3 +476,33 @@ export async function matchResume(text, opts = {}) {
476
476
  "The only authority on selection is HR.",
477
477
  };
478
478
  }
479
+ import { buildBespokeApplySchema as _buildBespokeApplySchema_alibaba } from "./apply.js";
480
+ export async function fetchApplicationSchema(postId) {
481
+ const id = (postId ?? "").trim();
482
+ if (!id)
483
+ return { ok: false, source: "campus-talent.alibaba.com", message: "post_id is required" };
484
+ let title = "";
485
+ let applyUrl = "https://campus-talent.alibaba.com";
486
+ try {
487
+ const detail = (await fetchPositionDetail(id));
488
+ if (detail?.ok === false) {
489
+ return { ok: false, source: "campus-talent.alibaba.com", message: detail.message ?? "post not found" };
490
+ }
491
+ title = detail?.title ?? "";
492
+ if (detail?.apply_url)
493
+ applyUrl = detail.apply_url;
494
+ }
495
+ catch { }
496
+ return {
497
+ ok: true,
498
+ schema: _buildBespokeApplySchema_alibaba({
499
+ source: "campus-talent.alibaba.com",
500
+ postId: id,
501
+ jobTitle: title,
502
+ applyUrl,
503
+ submitEndpoint: "https://campus-talent.alibaba.com/campus/applyPosition.json",
504
+ submitKind: "multipart-session",
505
+ submitNotes: "Alibaba — POST /campus/applyPosition.json with session cookie. Alipay OAuth gates the session. Endpoint inferred; needs validation.",
506
+ }),
507
+ };
508
+ }
package/dist/antgroup.js CHANGED
@@ -360,3 +360,33 @@ export async function matchResume(text, opts = {}) {
360
360
  };
361
361
  }
362
362
  export { extractResumeSignals, scoreOverlap };
363
+ import { buildBespokeApplySchema as _buildBespokeApplySchema_antgroup } from "./apply.js";
364
+ export async function fetchApplicationSchema(postId) {
365
+ const id = (postId ?? "").trim();
366
+ if (!id)
367
+ return { ok: false, source: "hrcareersweb.antgroup.com", message: "post_id is required" };
368
+ let title = "";
369
+ let applyUrl = "https://hrcareersweb.antgroup.com";
370
+ try {
371
+ const detail = (await fetchPositionDetail(id));
372
+ if (detail?.ok === false) {
373
+ return { ok: false, source: "hrcareersweb.antgroup.com", message: detail.message ?? "post not found" };
374
+ }
375
+ title = detail?.title ?? "";
376
+ if (detail?.apply_url)
377
+ applyUrl = detail.apply_url;
378
+ }
379
+ catch { }
380
+ return {
381
+ ok: true,
382
+ schema: _buildBespokeApplySchema_antgroup({
383
+ source: "hrcareersweb.antgroup.com",
384
+ postId: id,
385
+ jobTitle: title,
386
+ applyUrl,
387
+ submitEndpoint: "https://hrcareersweb.antgroup.com/api/social/position/apply",
388
+ submitKind: "multipart-session",
389
+ submitNotes: "Ant Group — POST /api/social/position/apply (also campus variant). Alipay OAuth session required. Endpoint inferred from parallel read-side path; needs validation.",
390
+ }),
391
+ };
392
+ }
package/dist/apply.js CHANGED
@@ -201,6 +201,25 @@ export function formatStaged(s) {
201
201
  function truncate(s, n) {
202
202
  return s.length > n ? s.slice(0, n - 1) + "…" : s;
203
203
  }
204
+ export function buildBespokeApplySchema(cfg) {
205
+ const standard = [
206
+ { label: "Name", required: true, fields: [{ name: "name", type: "input_text" }] },
207
+ { label: "Email", required: true, fields: [{ name: "email", type: "input_text" }] },
208
+ { label: "Phone", required: true, fields: [{ name: "phone", type: "input_text" }] },
209
+ { label: "Resume", required: true, fields: [{ name: "resume", type: "input_file" }] },
210
+ ];
211
+ return {
212
+ source: cfg.source,
213
+ post_id: cfg.postId,
214
+ job_title: cfg.jobTitle,
215
+ apply_url: cfg.applyUrl,
216
+ submit_endpoint: cfg.submitEndpoint,
217
+ submit_method: cfg.submitEndpoint ? "POST" : undefined,
218
+ submit_kind: cfg.submitKind ?? "multipart-session",
219
+ submit_notes: cfg.submitNotes,
220
+ questions: [...standard, ...(cfg.extraQuestions ?? [])],
221
+ };
222
+ }
204
223
  export async function submitApplication(staged, target, options = {}) {
205
224
  if (!staged.submit_endpoint) {
206
225
  return {
package/dist/baidu.js CHANGED
@@ -419,3 +419,33 @@ export async function matchResume(text, opts = {}) {
419
419
  "The only authority on selection is HR.",
420
420
  };
421
421
  }
422
+ import { buildBespokeApplySchema as _buildBespokeApplySchema_baidu } from "./apply.js";
423
+ export async function fetchApplicationSchema(postId) {
424
+ const id = (postId ?? "").trim();
425
+ if (!id)
426
+ return { ok: false, source: "talent.baidu.com", message: "post_id is required" };
427
+ let title = "";
428
+ let applyUrl = "https://talent.baidu.com";
429
+ try {
430
+ const detail = (await fetchPositionDetail(id));
431
+ if (detail?.ok === false) {
432
+ return { ok: false, source: "talent.baidu.com", message: detail.message ?? "post not found" };
433
+ }
434
+ title = detail?.title ?? "";
435
+ if (detail?.apply_url)
436
+ applyUrl = detail.apply_url;
437
+ }
438
+ catch { }
439
+ return {
440
+ ok: true,
441
+ schema: _buildBespokeApplySchema_baidu({
442
+ source: "talent.baidu.com",
443
+ postId: id,
444
+ jobTitle: title,
445
+ applyUrl,
446
+ submitEndpoint: "https://talent.baidu.com/external/baidu/applyJob.json",
447
+ submitKind: "multipart-session",
448
+ submitNotes: "Baidu — POST /external/baidu/applyJob.json with session cookie. Endpoint inferred; needs validation.",
449
+ }),
450
+ };
451
+ }
package/dist/bilibili.js CHANGED
@@ -422,3 +422,33 @@ export async function findNoticesByQuestion(_question, _opts = {}) {
422
422
  message: "Bilibili: no public notices endpoint",
423
423
  };
424
424
  }
425
+ import { buildBespokeApplySchema as _buildBespokeApplySchema_bilibili } from "./apply.js";
426
+ export async function fetchApplicationSchema(postId) {
427
+ const id = (postId ?? "").trim();
428
+ if (!id)
429
+ return { ok: false, source: "jobs.bilibili.com", message: "post_id is required" };
430
+ let title = "";
431
+ let applyUrl = "https://jobs.bilibili.com";
432
+ try {
433
+ const detail = (await fetchPositionDetail(id));
434
+ if (detail?.ok === false) {
435
+ return { ok: false, source: "jobs.bilibili.com", message: detail.message ?? "post not found" };
436
+ }
437
+ title = detail?.title ?? "";
438
+ if (detail?.apply_url)
439
+ applyUrl = detail.apply_url;
440
+ }
441
+ catch { }
442
+ return {
443
+ ok: true,
444
+ schema: _buildBespokeApplySchema_bilibili({
445
+ source: "jobs.bilibili.com",
446
+ postId: id,
447
+ jobTitle: title,
448
+ applyUrl,
449
+ submitEndpoint: "https://jobs.bilibili.com/api/post/apply",
450
+ submitKind: "multipart-session",
451
+ submitNotes: "Bilibili — POST /api/post/apply with session cookie. Endpoint inferred; needs validation.",
452
+ }),
453
+ };
454
+ }
package/dist/byd.js CHANGED
@@ -379,3 +379,33 @@ export async function matchResume(text, opts = {}) {
379
379
  };
380
380
  }
381
381
  export { extractResumeSignals, scoreOverlap };
382
+ import { buildBespokeApplySchema as _buildBespokeApplySchema_byd } from "./apply.js";
383
+ export async function fetchApplicationSchema(postId) {
384
+ const id = (postId ?? "").trim();
385
+ if (!id)
386
+ return { ok: false, source: "job.byd.com", message: "post_id is required" };
387
+ let title = "";
388
+ let applyUrl = "https://job.byd.com";
389
+ try {
390
+ const detail = (await fetchPositionDetail(id));
391
+ if (detail?.ok === false) {
392
+ return { ok: false, source: "job.byd.com", message: detail.message ?? "post not found" };
393
+ }
394
+ title = detail?.title ?? "";
395
+ if (detail?.apply_url)
396
+ applyUrl = detail.apply_url;
397
+ }
398
+ catch { }
399
+ return {
400
+ ok: true,
401
+ schema: _buildBespokeApplySchema_byd({
402
+ source: "job.byd.com",
403
+ postId: id,
404
+ jobTitle: title,
405
+ applyUrl,
406
+ submitEndpoint: "https://job.byd.com/portal/api/portal-api/position/apply",
407
+ submitKind: "multipart-session",
408
+ submitNotes: "BYD — POST /portal/api/portal-api/position/apply with JWT bearer + session. Endpoint inferred from job.byd.com bundle; needs validation.",
409
+ }),
410
+ };
411
+ }
package/dist/bytedance.js CHANGED
@@ -586,3 +586,33 @@ export async function matchResume(text, opts = {}) {
586
586
  "The only authority on selection is HR.",
587
587
  };
588
588
  }
589
+ import { buildBespokeApplySchema as _buildBespokeApplySchema_bytedance } from "./apply.js";
590
+ export async function fetchApplicationSchema(postId) {
591
+ const id = (postId ?? "").trim();
592
+ if (!id)
593
+ return { ok: false, source: "jobs.bytedance.com", message: "post_id is required" };
594
+ let title = "";
595
+ let applyUrl = "https://jobs.bytedance.com";
596
+ try {
597
+ const detail = (await fetchPositionDetail(id));
598
+ if (detail?.ok === false) {
599
+ return { ok: false, source: "jobs.bytedance.com", message: detail.message ?? "post not found" };
600
+ }
601
+ title = detail?.title ?? "";
602
+ if (detail?.apply_url)
603
+ applyUrl = detail.apply_url;
604
+ }
605
+ catch { }
606
+ return {
607
+ ok: true,
608
+ schema: _buildBespokeApplySchema_bytedance({
609
+ source: "jobs.bytedance.com",
610
+ postId: id,
611
+ jobTitle: title,
612
+ applyUrl,
613
+ submitEndpoint: "https://jobs.bytedance.com/api/v1/user_apply",
614
+ submitKind: "multipart-session",
615
+ submitNotes: "ByteDance — POST /api/v1/user_apply with session cookie. CAPTCHA verification required for first-time applicants. Endpoint inferred; needs validation.",
616
+ }),
617
+ };
618
+ }
package/dist/cainiao.js CHANGED
@@ -24,3 +24,33 @@ export const getNotice = adapter.getNotice;
24
24
  export const findNoticesByQuestion = adapter.findNoticesByQuestion;
25
25
  export const matchResume = adapter.matchResume;
26
26
  export const checkResume = adapter.checkResume;
27
+ import { buildBespokeApplySchema as _buildBespokeApplySchema_cainiao } from "./apply.js";
28
+ export async function fetchApplicationSchema(postId) {
29
+ const id = (postId ?? "").trim();
30
+ if (!id)
31
+ return { ok: false, source: "cainiao.com (via api-c.liepin.com)", message: "post_id is required" };
32
+ let title = "";
33
+ let applyUrl = "https://cainiao.com";
34
+ try {
35
+ const detail = (await fetchPositionDetail(id));
36
+ if (detail?.ok === false) {
37
+ return { ok: false, source: "cainiao.com (via api-c.liepin.com)", message: detail.message ?? "post not found" };
38
+ }
39
+ title = detail?.title ?? "";
40
+ if (detail?.apply_url)
41
+ applyUrl = detail.apply_url;
42
+ }
43
+ catch { }
44
+ return {
45
+ ok: true,
46
+ schema: _buildBespokeApplySchema_cainiao({
47
+ source: "cainiao.com (via api-c.liepin.com)",
48
+ postId: id,
49
+ jobTitle: title,
50
+ applyUrl,
51
+ submitEndpoint: undefined,
52
+ submitKind: "external",
53
+ submitNotes: "Cainiao (Liepin-backed) — submission is recruiter-IM-mediated through Liepin. Open the apply_url to start the chat.",
54
+ }),
55
+ };
56
+ }
package/dist/cambricon.js CHANGED
@@ -30,3 +30,4 @@ export const getNotice = adapter.getNotice;
30
30
  export const findNoticesByQuestion = adapter.findNoticesByQuestion;
31
31
  export const matchResume = adapter.matchResume;
32
32
  export const checkResume = adapter.checkResume;
33
+ export const fetchApplicationSchema = adapter.fetchApplicationSchema;
package/dist/cicc.js CHANGED
@@ -24,3 +24,33 @@ export const getNotice = adapter.getNotice;
24
24
  export const findNoticesByQuestion = adapter.findNoticesByQuestion;
25
25
  export const matchResume = adapter.matchResume;
26
26
  export const checkResume = adapter.checkResume;
27
+ import { buildBespokeApplySchema as _buildBespokeApplySchema_cicc } from "./apply.js";
28
+ export async function fetchApplicationSchema(postId) {
29
+ const id = (postId ?? "").trim();
30
+ if (!id)
31
+ return { ok: false, source: "cicc.com (via api-c.liepin.com)", message: "post_id is required" };
32
+ let title = "";
33
+ let applyUrl = "https://cicc.com";
34
+ try {
35
+ const detail = (await fetchPositionDetail(id));
36
+ if (detail?.ok === false) {
37
+ return { ok: false, source: "cicc.com (via api-c.liepin.com)", message: detail.message ?? "post not found" };
38
+ }
39
+ title = detail?.title ?? "";
40
+ if (detail?.apply_url)
41
+ applyUrl = detail.apply_url;
42
+ }
43
+ catch { }
44
+ return {
45
+ ok: true,
46
+ schema: _buildBespokeApplySchema_cicc({
47
+ source: "cicc.com (via api-c.liepin.com)",
48
+ postId: id,
49
+ jobTitle: title,
50
+ applyUrl,
51
+ submitEndpoint: undefined,
52
+ submitKind: "external",
53
+ submitNotes: "CICC (Liepin-backed) — submission is recruiter-IM-mediated through Liepin. Open the apply_url to start the chat.",
54
+ }),
55
+ };
56
+ }
package/dist/deepseek.js CHANGED
@@ -22,3 +22,4 @@ export const getNotice = adapter.getNotice;
22
22
  export const findNoticesByQuestion = adapter.findNoticesByQuestion;
23
23
  export const matchResume = adapter.matchResume;
24
24
  export const checkResume = adapter.checkResume;
25
+ export const fetchApplicationSchema = adapter.fetchApplicationSchema;
package/dist/didi.js CHANGED
@@ -348,3 +348,33 @@ export async function matchResume(text, opts = {}) {
348
348
  "The only authority on selection is HR.",
349
349
  };
350
350
  }
351
+ import { buildBespokeApplySchema as _buildBespokeApplySchema_didi } from "./apply.js";
352
+ export async function fetchApplicationSchema(postId) {
353
+ const id = (postId ?? "").trim();
354
+ if (!id)
355
+ return { ok: false, source: "talent.didiglobal.com", message: "post_id is required" };
356
+ let title = "";
357
+ let applyUrl = "https://talent.didiglobal.com";
358
+ try {
359
+ const detail = (await fetchPositionDetail(id));
360
+ if (detail?.ok === false) {
361
+ return { ok: false, source: "talent.didiglobal.com", message: detail.message ?? "post not found" };
362
+ }
363
+ title = detail?.title ?? "";
364
+ if (detail?.apply_url)
365
+ applyUrl = detail.apply_url;
366
+ }
367
+ catch { }
368
+ return {
369
+ ok: true,
370
+ schema: _buildBespokeApplySchema_didi({
371
+ source: "talent.didiglobal.com",
372
+ postId: id,
373
+ jobTitle: title,
374
+ applyUrl,
375
+ submitEndpoint: "https://talent.didiglobal.com/talent-api/applyResume",
376
+ submitKind: "multipart-session",
377
+ submitNotes: "Didi — POST /talent-api/applyResume with session cookie. Endpoint inferred; needs validation.",
378
+ }),
379
+ };
380
+ }
@@ -21,3 +21,4 @@ export const getNotice = adapter.getNotice;
21
21
  export const findNoticesByQuestion = adapter.findNoticesByQuestion;
22
22
  export const matchResume = adapter.matchResume;
23
23
  export const checkResume = adapter.checkResume;
24
+ export const fetchApplicationSchema = adapter.fetchApplicationSchema;
package/dist/geely.js CHANGED
@@ -32,3 +32,4 @@ export const getNotice = adapter.getNotice;
32
32
  export const findNoticesByQuestion = adapter.findNoticesByQuestion;
33
33
  export const matchResume = adapter.matchResume;
34
34
  export const checkResume = adapter.checkResume;
35
+ export const fetchApplicationSchema = adapter.fetchApplicationSchema;
package/dist/hikvision.js CHANGED
@@ -26,3 +26,33 @@ export const getNotice = adapter.getNotice;
26
26
  export const findNoticesByQuestion = adapter.findNoticesByQuestion;
27
27
  export const matchResume = adapter.matchResume;
28
28
  export const checkResume = adapter.checkResume;
29
+ import { buildBespokeApplySchema as _buildBespokeApplySchema_hikvision } from "./apply.js";
30
+ export async function fetchApplicationSchema(postId) {
31
+ const id = (postId ?? "").trim();
32
+ if (!id)
33
+ return { ok: false, source: "hikvision.com (via api-c.liepin.com)", message: "post_id is required" };
34
+ let title = "";
35
+ let applyUrl = "https://hikvision.com";
36
+ try {
37
+ const detail = (await fetchPositionDetail(id));
38
+ if (detail?.ok === false) {
39
+ return { ok: false, source: "hikvision.com (via api-c.liepin.com)", message: detail.message ?? "post not found" };
40
+ }
41
+ title = detail?.title ?? "";
42
+ if (detail?.apply_url)
43
+ applyUrl = detail.apply_url;
44
+ }
45
+ catch { }
46
+ return {
47
+ ok: true,
48
+ schema: _buildBespokeApplySchema_hikvision({
49
+ source: "hikvision.com (via api-c.liepin.com)",
50
+ postId: id,
51
+ jobTitle: title,
52
+ applyUrl,
53
+ submitEndpoint: undefined,
54
+ submitKind: "external",
55
+ submitNotes: "Hikvision (Liepin-backed) — submission is recruiter-IM-mediated through Liepin. Open the apply_url to start the chat.",
56
+ }),
57
+ };
58
+ }
@@ -43,3 +43,4 @@ export const getNotice = adapter.getNotice;
43
43
  export const findNoticesByQuestion = adapter.findNoticesByQuestion;
44
44
  export const matchResume = adapter.matchResume;
45
45
  export const checkResume = adapter.checkResume;
46
+ export const fetchApplicationSchema = adapter.fetchApplicationSchema;
package/dist/huawei.js CHANGED
@@ -504,3 +504,33 @@ export async function matchResume(text, opts = {}) {
504
504
  "The only authority on selection is HR.",
505
505
  };
506
506
  }
507
+ import { buildBespokeApplySchema as _buildBespokeApplySchema_huawei } from "./apply.js";
508
+ export async function fetchApplicationSchema(postId) {
509
+ const id = (postId ?? "").trim();
510
+ if (!id)
511
+ return { ok: false, source: "career.huawei.com", message: "post_id is required" };
512
+ let title = "";
513
+ let applyUrl = "https://career.huawei.com";
514
+ try {
515
+ const detail = (await fetchPositionDetail(id));
516
+ if (detail?.ok === false) {
517
+ return { ok: false, source: "career.huawei.com", message: detail.message ?? "post not found" };
518
+ }
519
+ title = detail?.title ?? "";
520
+ if (detail?.apply_url)
521
+ applyUrl = detail.apply_url;
522
+ }
523
+ catch { }
524
+ return {
525
+ ok: true,
526
+ schema: _buildBespokeApplySchema_huawei({
527
+ source: "career.huawei.com",
528
+ postId: id,
529
+ jobTitle: title,
530
+ applyUrl,
531
+ submitEndpoint: "https://career.huawei.com/career/api/web/postApply",
532
+ submitKind: "multipart-session",
533
+ submitNotes: "Huawei — POST /career/api/web/postApply with session cookie. Endpoint inferred; needs validation.",
534
+ }),
535
+ };
536
+ }
package/dist/iflytek.js CHANGED
@@ -337,3 +337,41 @@ export { extractResumeSignals, scoreOverlap };
337
337
  // Silence unused warning for the GET helper — kept for future taxonomy/city
338
338
  // endpoints that return BeisenEnvelope JSON via GET.
339
339
  void get;
340
+ export async function fetchApplicationSchema(postId) {
341
+ const id = (postId ?? '').trim();
342
+ if (!id)
343
+ return { ok: false, source: SOURCE, message: 'post_id is required' };
344
+ let title = '';
345
+ try {
346
+ const detail = await fetchPositionDetail(id);
347
+ if (detail?.ok === false) {
348
+ return { ok: false, source: SOURCE, message: detail.message ?? 'post not found' };
349
+ }
350
+ title = detail?.title ?? '';
351
+ }
352
+ catch { }
353
+ const questions = [
354
+ { label: 'Name', required: true, fields: [{ name: 'name', type: 'input_text' }] },
355
+ { label: 'Email', required: true, fields: [{ name: 'email', type: 'input_text' }] },
356
+ { label: 'Phone', required: true, fields: [{ name: 'phone', type: 'input_text' }] },
357
+ { label: 'Resume', required: true, fields: [{ name: 'resume', type: 'input_file' }] },
358
+ ];
359
+ return {
360
+ ok: true,
361
+ schema: {
362
+ source: SOURCE,
363
+ post_id: id,
364
+ job_title: title,
365
+ apply_url: 'https://iflytek.zhiye.com/jobs',
366
+ submit_endpoint: 'https://iflytek.zhiye.com/api/Apply/SubmitResume',
367
+ submit_method: 'POST',
368
+ submit_kind: 'beisen-italent',
369
+ submit_notes: 'Beisen iTalent apply: POST /api/Resume/UploadResume (multipart) + ' +
370
+ 'POST /api/Apply/SubmitResume with { JobAdId, ResumeId, … }. ' +
371
+ 'Requires candidate session — Beisen iTalent uses email+phone+OTP login at ' +
372
+ '/login.html. Capture via extension/, drop session.json under ~/.jobpro/. ' +
373
+ 'Multi-step submitter lands in a future iteration.',
374
+ questions,
375
+ },
376
+ };
377
+ }
package/dist/index.js CHANGED
@@ -54,7 +54,7 @@ import { loadProfile, loadSession, profileTemplate, stageApplication, submitAppl
54
54
  import { memoryList, memoryGet, memorySet, memoryEvent, memoryClear, } from "./memory.js";
55
55
  import { writeFileSync, mkdirSync, existsSync } from "node:fs";
56
56
  import { dirname } from "node:path";
57
- const VERSION = "0.9.3";
57
+ const VERSION = "0.9.5";
58
58
  const COMPANIES = [
59
59
  { key: "tencent", family: "Bespoke", source: "join.qq.com", label: "Tencent / 腾讯" },
60
60
  { key: "bytedance", family: "Bespoke", source: "jobs.bytedance.com", label: "ByteDance / 字节跳动" },
@@ -123,11 +123,22 @@ USAGE
123
123
  by ATS family (Bespoke / Feishu / Beisen Wecruit / Beisen iTalent / Moka
124
124
  / Greenhouse-Lever / Liepin). Coverage summary at job.ha7ch.com.
125
125
 
126
- PHASE 2 (auto-apply) is in early access. \`job-pro <co> apply <postId>\`
127
- prints the staged POST in dry-run mode. Today only Greenhouse +
128
- Lever boards (xpeng / hoyoverse / weride) expose the application
129
- schema; the rest return a "not yet wired" note. See docs/auto-apply.md
130
- for the rollout plan.
126
+ PHASE 2 (auto-apply) schema coverage is now 50/50:
127
+ 3 Greenhouse / Lever (xpeng / hoyoverse / weride auto-submit
128
+ ready, no session needed)
129
+ 🟡 22 bespoke session (tencent, bytedance, alibaba, …)
130
+ 🟡 9 Feishu (xiaomi, nio, minimax, moonshot, zhipu,
131
+ iqiyi, agibot, lilith, zerooneai, baichuan)
132
+ 🟡 7 Moka (megvii, deepseek, galaxyuniversal,
133
+ stepfun, cambricon, geely, moonshot)
134
+ 🟡 2 Beisen Wecruit (sensetime, horizonrobotics)
135
+ 🟡 2 Beisen iTalent (vivo, iflytek)
136
+ ⛔ 5 external (unitree WeChat, hikvision/cicc/cainiao/
137
+ webank — Liepin IM-mediated)
138
+ \`apply <postId>\` dry-runs the staged POST for any of them. The 🟡
139
+ families need a session.json (extension/) + a family-specific
140
+ multi-step submitter; --really-submit currently fires only for ✅.
141
+ See docs/auto-apply.md.
131
142
 
132
143
  VERBS (same surface for every company)
133
144
  search <kw> search openings (free text)
@@ -467,6 +478,20 @@ async function runCompany(adapter, company, rawArgs) {
467
478
  const isAnonMultipart = kind === "multipart-anon";
468
479
  const isSessionMultipart = kind === "multipart-session";
469
480
  const isGenericMultipart = isAnonMultipart || isSessionMultipart;
481
+ if (kind === "external") {
482
+ return emit({
483
+ ok: false,
484
+ source: company,
485
+ post_id: postId,
486
+ mode: "really-submit-external",
487
+ staged,
488
+ submit_kind: kind,
489
+ apply_url: staged.apply_url,
490
+ message: `${company} has no programmatic submit API — recruiting is mediated ` +
491
+ `via WeChat mini-program / Liepin recruiter chat / other IM channel. ` +
492
+ `Open apply_url in your browser to start the actual application flow.`,
493
+ }, compact);
494
+ }
470
495
  if (!isGenericMultipart) {
471
496
  return emit({
472
497
  ok: false,
package/dist/jd.js CHANGED
@@ -526,3 +526,33 @@ export async function matchResume(text, opts = {}) {
526
526
  "The only authority on selection is HR.",
527
527
  };
528
528
  }
529
+ import { buildBespokeApplySchema as _buildBespokeApplySchema_jd } from "./apply.js";
530
+ export async function fetchApplicationSchema(postId) {
531
+ const id = (postId ?? "").trim();
532
+ if (!id)
533
+ return { ok: false, source: "campus.jd.com", message: "post_id is required" };
534
+ let title = "";
535
+ let applyUrl = "https://campus.jd.com";
536
+ try {
537
+ const detail = (await fetchPositionDetail(id));
538
+ if (detail?.ok === false) {
539
+ return { ok: false, source: "campus.jd.com", message: detail.message ?? "post not found" };
540
+ }
541
+ title = detail?.title ?? "";
542
+ if (detail?.apply_url)
543
+ applyUrl = detail.apply_url;
544
+ }
545
+ catch { }
546
+ return {
547
+ ok: true,
548
+ schema: _buildBespokeApplySchema_jd({
549
+ source: "campus.jd.com",
550
+ postId: id,
551
+ jobTitle: title,
552
+ applyUrl,
553
+ submitEndpoint: "https://campus.jd.com/web/job/apply",
554
+ submitKind: "multipart-session",
555
+ submitNotes: "JD — POST /web/job/apply with session cookie. Endpoint inferred from campus.jd.com SPA; needs validation.",
556
+ }),
557
+ };
558
+ }
package/dist/kuaishou.js CHANGED
@@ -463,3 +463,33 @@ export async function matchResume(text, opts = {}) {
463
463
  "The only authority on selection is HR.",
464
464
  };
465
465
  }
466
+ import { buildBespokeApplySchema as _buildBespokeApplySchema_kuaishou } from "./apply.js";
467
+ export async function fetchApplicationSchema(postId) {
468
+ const id = (postId ?? "").trim();
469
+ if (!id)
470
+ return { ok: false, source: "campus.kuaishou.cn", message: "post_id is required" };
471
+ let title = "";
472
+ let applyUrl = "https://campus.kuaishou.cn";
473
+ try {
474
+ const detail = (await fetchPositionDetail(id));
475
+ if (detail?.ok === false) {
476
+ return { ok: false, source: "campus.kuaishou.cn", message: detail.message ?? "post not found" };
477
+ }
478
+ title = detail?.title ?? "";
479
+ if (detail?.apply_url)
480
+ applyUrl = detail.apply_url;
481
+ }
482
+ catch { }
483
+ return {
484
+ ok: true,
485
+ schema: _buildBespokeApplySchema_kuaishou({
486
+ source: "campus.kuaishou.cn",
487
+ postId: id,
488
+ jobTitle: title,
489
+ applyUrl,
490
+ submitEndpoint: "https://campus.kuaishou.cn/rest/campus-recruit/post/deliver",
491
+ submitKind: "multipart-session",
492
+ submitNotes: "Kuaishou — POST /rest/campus-recruit/post/deliver with session cookie. Endpoint inferred; needs validation.",
493
+ }),
494
+ };
495
+ }
package/dist/liauto.js CHANGED
@@ -360,3 +360,33 @@ export async function matchResume(text, opts = {}) {
360
360
  "The only authority on selection is HR.",
361
361
  };
362
362
  }
363
+ import { buildBespokeApplySchema as _buildBespokeApplySchema_liauto } from "./apply.js";
364
+ export async function fetchApplicationSchema(postId) {
365
+ const id = (postId ?? "").trim();
366
+ if (!id)
367
+ return { ok: false, source: "www.lixiang.com", message: "post_id is required" };
368
+ let title = "";
369
+ let applyUrl = "https://www.lixiang.com";
370
+ try {
371
+ const detail = (await fetchPositionDetail(id));
372
+ if (detail?.ok === false) {
373
+ return { ok: false, source: "www.lixiang.com", message: detail.message ?? "post not found" };
374
+ }
375
+ title = detail?.title ?? "";
376
+ if (detail?.apply_url)
377
+ applyUrl = detail.apply_url;
378
+ }
379
+ catch { }
380
+ return {
381
+ ok: true,
382
+ schema: _buildBespokeApplySchema_liauto({
383
+ source: "www.lixiang.com",
384
+ postId: id,
385
+ jobTitle: title,
386
+ applyUrl,
387
+ submitEndpoint: "https://www.lixiang.com/api/career/apply",
388
+ submitKind: "multipart-session",
389
+ submitNotes: "Li Auto — POST /api/career/apply with session cookie. Endpoint inferred; needs validation.",
390
+ }),
391
+ };
392
+ }
package/dist/megvii.js CHANGED
@@ -24,3 +24,4 @@ export const getNotice = adapter.getNotice;
24
24
  export const findNoticesByQuestion = adapter.findNoticesByQuestion;
25
25
  export const matchResume = adapter.matchResume;
26
26
  export const checkResume = adapter.checkResume;
27
+ export const fetchApplicationSchema = adapter.fetchApplicationSchema;