job-pro 1.0.7 → 1.0.9
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 +63 -4
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -121,7 +121,9 @@ USAGE
|
|
|
121
121
|
job-pro <company> <verb> [options]
|
|
122
122
|
job-pro list [--compact] list all 50 companies + source family
|
|
123
123
|
job-pro status [--compact] survey profile / sessions / memory / chrome
|
|
124
|
-
job-pro profile init [--force]
|
|
124
|
+
job-pro profile init [--interactive] [--force]
|
|
125
|
+
write ~/.jobpro/profile.json
|
|
126
|
+
--interactive fills it via prompts.
|
|
125
127
|
job-pro profile show print the loaded profile
|
|
126
128
|
job-pro --version
|
|
127
129
|
job-pro help
|
|
@@ -936,6 +938,56 @@ function printStatus(compact) {
|
|
|
936
938
|
console.log(` needed for: lilith adapter, --proxy-server geo-bypass (hikvision).`);
|
|
937
939
|
}
|
|
938
940
|
}
|
|
941
|
+
async function runProfileInitInteractive(template) {
|
|
942
|
+
if (!process.stdin.isTTY) {
|
|
943
|
+
die("profile init --interactive needs a TTY (got a piped stdin). " +
|
|
944
|
+
"Either run from a real terminal, or drop --interactive and edit " +
|
|
945
|
+
"the JSON file directly.");
|
|
946
|
+
}
|
|
947
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
948
|
+
const ask = (prompt) => new Promise((resolve, reject) => {
|
|
949
|
+
let answered = false;
|
|
950
|
+
const onClose = () => {
|
|
951
|
+
if (!answered)
|
|
952
|
+
reject(new Error("stdin closed before answer"));
|
|
953
|
+
};
|
|
954
|
+
rl.once("close", onClose);
|
|
955
|
+
rl.question(prompt, (a) => {
|
|
956
|
+
answered = true;
|
|
957
|
+
rl.off("close", onClose);
|
|
958
|
+
resolve(a);
|
|
959
|
+
});
|
|
960
|
+
});
|
|
961
|
+
const filled = { ...template };
|
|
962
|
+
console.log(`\nProfile setup — fill in 5 fields (Ctrl-C to abort).\n`);
|
|
963
|
+
try {
|
|
964
|
+
filled.first_name = await prompt("First name: ", ask, (v) => v.trim().length > 0 || "(required)");
|
|
965
|
+
filled.last_name = await prompt("Last name: ", ask, (v) => v.trim().length > 0 || "(required)");
|
|
966
|
+
filled.email = await prompt("Email: ", ask, (v) => (/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v.trim()) ? true : "(must look like name@domain.tld)"));
|
|
967
|
+
filled.phone = await prompt("Phone (with country code, e.g. +86 13800138000): ", ask, (v) => (/^[+]?[\d\s\-()]{7,}$/.test(v.trim()) ? true : "(digits + optional spaces/dashes; min 7)"));
|
|
968
|
+
filled.resume_path = await prompt("Resume file path (absolute, PDF/DOCX): ", ask, (v) => {
|
|
969
|
+
const p = v.trim();
|
|
970
|
+
if (!p)
|
|
971
|
+
return "(required — pass an absolute path to your résumé)";
|
|
972
|
+
if (!existsSync(p))
|
|
973
|
+
return `(file not found: ${p})`;
|
|
974
|
+
return true;
|
|
975
|
+
});
|
|
976
|
+
}
|
|
977
|
+
finally {
|
|
978
|
+
rl.close();
|
|
979
|
+
}
|
|
980
|
+
return filled;
|
|
981
|
+
}
|
|
982
|
+
async function prompt(q, ask, validate) {
|
|
983
|
+
while (true) {
|
|
984
|
+
const v = (await ask(q)).trim();
|
|
985
|
+
const res = validate(v);
|
|
986
|
+
if (res === true)
|
|
987
|
+
return v;
|
|
988
|
+
console.log(` ${res}`);
|
|
989
|
+
}
|
|
990
|
+
}
|
|
939
991
|
function printCompanyList(compact) {
|
|
940
992
|
// Validate the directory still matches the ADAPTERS map. If a company
|
|
941
993
|
// appears in only one place, treat it as a bug.
|
|
@@ -1013,8 +1065,15 @@ async function main() {
|
|
|
1013
1065
|
process.exit(1);
|
|
1014
1066
|
}
|
|
1015
1067
|
mkdirSync(dirname(path), { recursive: true });
|
|
1016
|
-
|
|
1017
|
-
|
|
1068
|
+
const interactive = args.includes("--interactive");
|
|
1069
|
+
const filled = interactive ? await runProfileInitInteractive(template) : template;
|
|
1070
|
+
writeFileSync(path, JSON.stringify(filled, null, 2) + "\n", "utf8");
|
|
1071
|
+
if (interactive) {
|
|
1072
|
+
console.log(`\nWrote ${path}. Run \`job-pro status\` to confirm, then \`job-pro <co> apply <id>\` to start.`);
|
|
1073
|
+
}
|
|
1074
|
+
else {
|
|
1075
|
+
console.log(`Wrote ${path}. Fill in first_name / last_name / email / phone / resume_path before running \`job-pro <co> apply\`. (Tip: pass --interactive to fill it in the terminal now.)`);
|
|
1076
|
+
}
|
|
1018
1077
|
return;
|
|
1019
1078
|
}
|
|
1020
1079
|
if (sub === "show") {
|
|
@@ -1026,7 +1085,7 @@ async function main() {
|
|
|
1026
1085
|
console.log(JSON.stringify(r.profile, null, 2));
|
|
1027
1086
|
return;
|
|
1028
1087
|
}
|
|
1029
|
-
die(`usage: job-pro profile <init [--force] | show>`);
|
|
1088
|
+
die(`usage: job-pro profile <init [--interactive] [--force] | show>`);
|
|
1030
1089
|
}
|
|
1031
1090
|
const adapter = ADAPTERS[cmd];
|
|
1032
1091
|
if (adapter) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "job-pro",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.9",
|
|
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",
|