job-pro 1.0.7 → 1.0.8

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 +63 -4
  2. 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] write ~/.jobpro/profile.json template
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
- writeFileSync(path, JSON.stringify(template, null, 2) + "\n", "utf8");
1017
- console.log(`Wrote ${path}. Fill in first_name / last_name / email / phone / resume_path before running \`job-pro <co> apply\`.`);
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.7",
3
+ "version": "1.0.8",
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",