job-pro 1.0.6 → 1.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +86 -6
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -60,7 +60,7 @@ import { createRequire as require_createRequire } from "node:module";
60
60
  function require_module() {
61
61
  return { createRequire: require_createRequire };
62
62
  }
63
- const VERSION = "1.0.6";
63
+ const VERSION = "1.0.7";
64
64
  const COMPANIES = [
65
65
  { key: "tencent", family: "Bespoke", source: "join.qq.com", label: "Tencent / 腾讯" },
66
66
  { key: "bytedance", family: "Bespoke", source: "jobs.bytedance.com", label: "ByteDance / 字节跳动" },
@@ -162,6 +162,7 @@ VERBS (same surface for every company)
162
162
  --print-form emit a fillable JSON template
163
163
  --form-file <path> merge per-job answers
164
164
  --interactive prompt for unanswered fields
165
+ --batch <file|-> apply to many post_ids (one/line)
165
166
  --debug-submit-to <url> verify wire format
166
167
  --really-submit actually fire (env-gated)
167
168
  memory list | get <k> | set k=v | event <kind> [payload] | clear
@@ -411,15 +412,94 @@ async function runCompany(adapter, company, rawArgs) {
411
412
  return emit(adapter.checkResume(text), compact);
412
413
  }
413
414
  if (verb === "apply") {
414
- const postId = args[0];
415
- if (!postId)
416
- die(`usage: job-pro ${company} apply <post_id> [--print-form | --form-file <path>] [--dry-run | --debug-submit-to <url> | --really-submit]`);
417
415
  const reallySubmit = args.includes("--really-submit");
418
416
  const printForm = args.includes("--print-form");
419
417
  const interactive = args.includes("--interactive");
420
418
  const { args: aDebug, value: debugUrl } = popFlagValue(args, "--debug-submit-to");
421
- const { args: _aForm, value: formFilePath } = popFlagValue(aDebug, "--form-file");
422
- void _aForm;
419
+ const { args: aForm, value: formFilePath } = popFlagValue(aDebug, "--form-file");
420
+ const { args: aBatch, value: batchPath } = popFlagValue(aForm, "--batch");
421
+ // Batch mode: read post_ids from a file (or stdin if "-"). Each non-empty,
422
+ // non-`#`-prefixed line is a post_id. Output is a JSON array of
423
+ // { post_id, result } so downstream tooling can iterate.
424
+ if (batchPath) {
425
+ if (reallySubmit) {
426
+ die(`--batch + --really-submit is intentionally refused. Submitting to ` +
427
+ `multiple jobs at once is the exact failure mode this CLI is designed to ` +
428
+ `prevent. Drop --really-submit and use --debug-submit-to <url> for batch ` +
429
+ `verification, or run apply one job at a time.`);
430
+ }
431
+ let rawLines;
432
+ try {
433
+ rawLines = batchPath === "-" ? readFileSync(0, "utf8") : readFileSync(batchPath, "utf8");
434
+ }
435
+ catch (err) {
436
+ die(`could not read batch file ${batchPath}: ${err instanceof Error ? err.message : err}`);
437
+ }
438
+ const postIds = rawLines
439
+ .split("\n")
440
+ .map((l) => l.trim())
441
+ .filter((l) => l && !l.startsWith("#"));
442
+ if (postIds.length === 0)
443
+ die(`batch file ${batchPath} contains no post_ids`);
444
+ // We need the schema fetcher / profile / session ONCE, not per-job.
445
+ const fetchSchema = adapter.fetchApplicationSchema;
446
+ if (typeof fetchSchema !== "function") {
447
+ return emit({ ok: false, source: company, message: `apply: not wired for "${company}"` }, compact);
448
+ }
449
+ const prof = loadProfile();
450
+ if (!prof.ok)
451
+ die(prof.message);
452
+ let effectiveProfile = prof.profile;
453
+ if (formFilePath) {
454
+ const merged = applyFormFile(effectiveProfile, formFilePath);
455
+ if (!merged.ok)
456
+ die(merged.message);
457
+ effectiveProfile = merged.profile;
458
+ }
459
+ const session = loadSession(company);
460
+ const out = [];
461
+ for (const id of postIds) {
462
+ try {
463
+ const schemaResult = (await fetchSchema.call(adapter, id));
464
+ if (!schemaResult.ok || !schemaResult.schema) {
465
+ out.push({ post_id: id, ok: false, message: schemaResult.message ?? "schema fetch failed" });
466
+ continue;
467
+ }
468
+ const staged = stageApplication(schemaResult.schema, effectiveProfile);
469
+ if (debugUrl) {
470
+ const kind = schemaResult.schema.submit_kind ?? "multipart-anon";
471
+ const debugExecutor = kind === "feishu-3-step" ? executeFeishu3Step :
472
+ kind === "moka-aes" ? executeMokaApply :
473
+ kind === "beisen-wecruit" ? executeBeisenWecruit :
474
+ kind === "beisen-italent" ? executeBeisenITalent :
475
+ kind === "cdp-real-browser" ? executeCdpRealBrowser :
476
+ null;
477
+ const result = debugExecutor
478
+ ? await debugExecutor(staged, session, { kind: "debug", url: debugUrl })
479
+ : await submitApplication(staged, { kind: "debug", url: debugUrl });
480
+ out.push({ post_id: id, ok: result.ok, ready: staged.ready, submit_kind: kind, debug_result: result });
481
+ }
482
+ else {
483
+ out.push({
484
+ post_id: id,
485
+ ok: staged.ready,
486
+ ready: staged.ready,
487
+ submit_kind: schemaResult.schema.submit_kind,
488
+ message: staged.ready ? "staged ok" : `${staged.unanswered_required.length} required field(s) unfilled`,
489
+ });
490
+ }
491
+ }
492
+ catch (err) {
493
+ out.push({ post_id: id, ok: false, message: err instanceof Error ? err.message : String(err) });
494
+ }
495
+ }
496
+ const okCount = out.filter((r) => r.ok).length;
497
+ return emit({ mode: debugUrl ? "batch-debug" : "batch-dry-run", company, total: out.length, ok_count: okCount, results: out }, compact);
498
+ }
499
+ void aBatch;
500
+ const postId = args[0];
501
+ if (!postId)
502
+ die(`usage: job-pro ${company} apply <post_id> [--print-form | --form-file <path> | --interactive | --batch <file>] [--debug-submit-to <url> | --really-submit]`);
423
503
  const fetchSchema = adapter.fetchApplicationSchema;
424
504
  if (typeof fetchSchema !== "function") {
425
505
  return emit({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "job-pro",
3
- "version": "1.0.6",
3
+ "version": "1.0.7",
4
4
  "description": "Query Chinese big-tech campus recruiting from your terminal. 50 companies, all 50 live. 46 via each company's own API; the 4 with no public canonical feed (Hikvision, CICC, Cainiao, WeBank) surfaced via Liepin as a clearly-labeled third-party fallback. No signup, no token, no server.",
5
5
  "homepage": "https://job.ha7ch.com",
6
6
  "repository": "https://github.com/HA7CH/job-pro",