job-pro 1.0.13 → 1.0.15
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 +42 -7
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -127,7 +127,8 @@ USAGE
|
|
|
127
127
|
job-pro profile show print the loaded profile
|
|
128
128
|
job-pro find <keyword> search ALL 50 companies in parallel
|
|
129
129
|
[--limit N] [--companies a,b,c]
|
|
130
|
-
[--timeout ms] [--
|
|
130
|
+
[--timeout ms] [--apply-ready]
|
|
131
|
+
[--compact | --text]
|
|
131
132
|
job-pro --version
|
|
132
133
|
job-pro help
|
|
133
134
|
|
|
@@ -164,6 +165,7 @@ VERBS (same surface for every company)
|
|
|
164
165
|
pass "-" to read resume from stdin
|
|
165
166
|
resume-check <resume-text-or--> structural sanity check on a resume
|
|
166
167
|
apply <post_id> stage an application (Phase 2 dry-run)
|
|
168
|
+
--schema dump raw schema (no profile needed)
|
|
167
169
|
--print-form emit a fillable JSON template
|
|
168
170
|
--form-file <path> merge per-job answers
|
|
169
171
|
--interactive prompt for unanswered fields
|
|
@@ -420,6 +422,7 @@ async function runCompany(adapter, company, rawArgs) {
|
|
|
420
422
|
if (verb === "apply") {
|
|
421
423
|
const reallySubmit = args.includes("--really-submit");
|
|
422
424
|
const printForm = args.includes("--print-form");
|
|
425
|
+
const schemaOnly = args.includes("--schema");
|
|
423
426
|
const interactive = args.includes("--interactive");
|
|
424
427
|
const remember = args.includes("--remember");
|
|
425
428
|
const { args: aDebug, value: debugUrl } = popFlagValue(args, "--debug-submit-to");
|
|
@@ -506,7 +509,7 @@ async function runCompany(adapter, company, rawArgs) {
|
|
|
506
509
|
void aBatch;
|
|
507
510
|
const postId = args[0];
|
|
508
511
|
if (!postId)
|
|
509
|
-
die(`usage: job-pro ${company} apply <post_id> [--print-form | --form-file <path> | --interactive [--remember] | --batch <file>] [--debug-submit-to <url> | --really-submit]`);
|
|
512
|
+
die(`usage: job-pro ${company} apply <post_id> [--schema | --print-form | --form-file <path> | --interactive [--remember] | --batch <file>] [--debug-submit-to <url> | --really-submit]`);
|
|
510
513
|
const fetchSchema = adapter.fetchApplicationSchema;
|
|
511
514
|
if (typeof fetchSchema !== "function") {
|
|
512
515
|
return emit({
|
|
@@ -527,6 +530,11 @@ async function runCompany(adapter, company, rawArgs) {
|
|
|
527
530
|
if (!sr.ok || !sr.schema) {
|
|
528
531
|
return emit({ ok: false, source: company, post_id: postId, message: sr.message ?? "unknown error" }, compact);
|
|
529
532
|
}
|
|
533
|
+
// --schema short-circuits everything (and crucially doesn't need a
|
|
534
|
+
// profile). Useful for recon: "what fields does this job ask?".
|
|
535
|
+
if (schemaOnly) {
|
|
536
|
+
return emit({ ok: true, source: company, post_id: postId, schema: sr.schema }, compact);
|
|
537
|
+
}
|
|
530
538
|
const prof = loadProfile();
|
|
531
539
|
if (!prof.ok) {
|
|
532
540
|
return emit({
|
|
@@ -1088,10 +1096,22 @@ async function main() {
|
|
|
1088
1096
|
if (cmd === "find") {
|
|
1089
1097
|
const compact = args.includes("--compact");
|
|
1090
1098
|
const textMode = args.includes("--text");
|
|
1099
|
+
const applyReadyOnly = args.includes("--apply-ready");
|
|
1091
1100
|
const keyword = args[1];
|
|
1092
1101
|
if (!keyword || keyword.startsWith("--")) {
|
|
1093
|
-
die(`usage: job-pro find <keyword> [--limit N] [--companies a,b,c] [--timeout ms] [--compact | --text]`);
|
|
1102
|
+
die(`usage: job-pro find <keyword> [--limit N] [--companies a,b,c] [--timeout ms] [--apply-ready] [--compact | --text]`);
|
|
1094
1103
|
}
|
|
1104
|
+
// Static apply-readiness map. Source of truth for what kind of submission
|
|
1105
|
+
// each adapter supports — kept in sync with apply-smoke's submit_kind tally.
|
|
1106
|
+
const ANON_ADAPTERS = new Set(["xpeng", "weride", "hoyoverse"]);
|
|
1107
|
+
const EXTERNAL_ADAPTERS = new Set(["hikvision", "cicc", "cainiao", "webank", "unitree"]);
|
|
1108
|
+
const applyStatusFor = (adapterKey) => {
|
|
1109
|
+
if (EXTERNAL_ADAPTERS.has(adapterKey))
|
|
1110
|
+
return "external";
|
|
1111
|
+
if (ANON_ADAPTERS.has(adapterKey))
|
|
1112
|
+
return "anon";
|
|
1113
|
+
return loadSession(adapterKey) ? "session" : "missing-session";
|
|
1114
|
+
};
|
|
1095
1115
|
const { args: aLimit, value: limitStr } = popFlagValue(args, "--limit");
|
|
1096
1116
|
const { args: aCompanies, value: companiesStr } = popFlagValue(aLimit, "--companies");
|
|
1097
1117
|
const { args: aTimeout, value: timeoutStr } = popFlagValue(aCompanies, "--timeout");
|
|
@@ -1126,7 +1146,7 @@ async function main() {
|
|
|
1126
1146
|
return { company, ok: false, count: 0, positions: [], message: r.message ?? "search failed", elapsed_ms: elapsed };
|
|
1127
1147
|
}
|
|
1128
1148
|
const positions = Array.isArray(r?.positions) ? r.positions.slice(0, limit) : [];
|
|
1129
|
-
return { company, ok: true, count: positions.length, positions, elapsed_ms: elapsed };
|
|
1149
|
+
return { company, ok: true, count: positions.length, positions, apply_status: applyStatusFor(company), elapsed_ms: elapsed };
|
|
1130
1150
|
}
|
|
1131
1151
|
catch (err) {
|
|
1132
1152
|
const elapsed = Date.now() - t0;
|
|
@@ -1139,13 +1159,24 @@ async function main() {
|
|
|
1139
1159
|
}
|
|
1140
1160
|
}));
|
|
1141
1161
|
const totalMs = Date.now() - startedAt;
|
|
1142
|
-
const
|
|
1162
|
+
const allHits = settled.filter((r) => r.count > 0);
|
|
1163
|
+
const withHits = applyReadyOnly
|
|
1164
|
+
? allHits.filter((r) => r.apply_status === "anon" || r.apply_status === "session")
|
|
1165
|
+
: allHits;
|
|
1143
1166
|
const total = withHits.reduce((s, r) => s + r.count, 0);
|
|
1144
1167
|
const failed = settled.filter((r) => !r.ok).map((r) => ({ company: r.company, message: r.message }));
|
|
1145
1168
|
if (textMode) {
|
|
1146
|
-
|
|
1169
|
+
const STATUS_ICON = {
|
|
1170
|
+
anon: "✅",
|
|
1171
|
+
session: "🟢",
|
|
1172
|
+
"missing-session": "🟡",
|
|
1173
|
+
external: "⛔",
|
|
1174
|
+
};
|
|
1175
|
+
const filterNote = applyReadyOnly ? " [apply-ready only]" : "";
|
|
1176
|
+
console.log(`\nfind "${keyword}" — ${total} hit(s) across ${withHits.length}/${scope.length} companies (${totalMs}ms)${filterNote}\n`);
|
|
1147
1177
|
for (const r of withHits) {
|
|
1148
|
-
|
|
1178
|
+
const icon = STATUS_ICON[r.apply_status ?? ""] ?? "?";
|
|
1179
|
+
console.log(`${icon} ${r.company} (${r.count}) — ${r.apply_status}`);
|
|
1149
1180
|
for (const p of r.positions) {
|
|
1150
1181
|
const title = (p.title ?? "").trim().replace(/\s+/g, " ");
|
|
1151
1182
|
const loc = (p.work_cities ?? "").trim();
|
|
@@ -1155,6 +1186,10 @@ async function main() {
|
|
|
1155
1186
|
}
|
|
1156
1187
|
console.log("");
|
|
1157
1188
|
}
|
|
1189
|
+
const hiddenCount = allHits.length - withHits.length;
|
|
1190
|
+
if (applyReadyOnly && hiddenCount > 0) {
|
|
1191
|
+
console.log(`(${hiddenCount} company-bucket(s) hidden — missing-session / external)\n`);
|
|
1192
|
+
}
|
|
1158
1193
|
if (failed.length > 0) {
|
|
1159
1194
|
console.log(`Failed (${failed.length}):`);
|
|
1160
1195
|
for (const f of failed)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "job-pro",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.15",
|
|
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",
|