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.
- package/dist/index.js +86 -6
- 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.
|
|
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:
|
|
422
|
-
|
|
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.
|
|
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",
|