jobless 1.0.0 → 1.1.0

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/README.md CHANGED
@@ -1,56 +1,66 @@
1
1
  # jobless
2
2
 
3
- A terminal resume for a broken job market.
4
-
5
- LinkedIn turned into social media. Applications take 30 minutes and get rejected by a bot. Recruiters schedule interviews, then vanish. This package is the profile I actually want people to read.
6
-
7
3
  ```bash
8
4
  npx jobless
9
5
  ```
10
6
 
11
- ## Commands
7
+ A terminal resume for a broken job market. LinkedIn is a content farm with a jobs tab. Applications take 30 minutes. The no takes 400ms. Recruiters book the call so they have something to cancel. I still do not know their coffee, their mug, or their star sign.
8
+
9
+ ## The market
10
+
11
+ ### I do not know their coffee, their mug, or their stars
12
+
13
+ The job posting said TypeScript, PostgreSQL, and "excellent communication." The actual exam is telepathy. What is on the recruiter's mind at 10:02am. Oat milk or "just black, I ship." What color is the mug. Company merch that says world-class talent, or the chipped navy one from a 2019 conference that still has a lipstick ghost. What is their star sign. A Virgo who will reject you for a missing Oxford comma. A Gemini who double-booked you with someone named also-Yonas. A Scorpio who already decided during the handshake.
14
+
15
+ I can trace a silent cron death across 17 processes. I cannot see into their mug. Apparently that was the seniority gap. Next round I will bring a natal chart, a color swatch, and a cortado. Or we could talk about the actual system.
16
+
17
+ ### I applied for 30 minutes. The bot needed 400ms
18
+
19
+ The modern application is unpaid data entry with extra steps. Upload the PDF. Then type the PDF into twelve boxes the parser already filled wrong. Then salary in USD, GBP, and emotional damage. Then a culture quiz written by someone who has never been in the culture. Then "why this company?" as if Greenhouse is going to light a candle and read it.
20
+
21
+ Submit. Rejected in 400ms. Sometimes the no arrives before the confirmation. Five years in production, $100K pulled out of infra, payment rails that moved billions — filtered out because I did not write "synergy" enough times. Cool product. Would not ship it.
22
+
23
+ ### They booked the call so they had something to cancel
24
+
25
+ Favorite genre of fiction: the recruiter calendar invite. "Loved your profile. Thursday 10am?" I clear the morning. I make tea. I put on a shirt with buttons. 9:58am: "we've decided to move forward with other candidates." Which other candidates. The ones you have not scheduled yet?
26
+
27
+ If ghosting is the process, skip the theater. I debug silent failures for a living. Yours is not that silent.
28
+
29
+ ### LinkedIn: 40% more thought leadership, 0% more jobs
30
+
31
+ LinkedIn used to be a jobs board that accidentally had a feed. Now it is a feed that accidentally has jobs. Everyone is humbled. Everyone is announcing. Everyone is a thought leader on a Tuesday. The algorithm loves a carousel called "10 habits of senior engineers" from someone who has never been on-call. It does not love the person who actually kept production up.
32
+
33
+ I did not open this app to like your new chapter. I opened it because I can build the thing you are posting about.
12
34
 
13
35
  ```bash
14
- npx jobless # interactive
15
- npx jobless who # who I am
16
- npx jobless looking # roles I want
17
- npx jobless rant # the market, unfiltered
18
- npx jobless work # proof of work
19
- npx jobless skills # the stack
20
- npx jobless hire # links + email
21
- npx jobless --json # machine readable
22
- npx jobless --no-anim # skip the ATS joke
36
+ npx jobless rant
23
37
  ```
24
38
 
25
39
  ## Yonas Alem
26
40
 
27
41
  Senior Software Engineer in Addis Ababa. Open to remote senior roles.
28
42
 
43
+ 5+ years in production · 35% infra cost cut · ~30% performance gain · 3B+ ETB payment volume
44
+
29
45
  - Site: [yonasalem.vercel.app](https://yonasalem.vercel.app)
30
46
  - GitHub: [github.com/Yonas21](https://github.com/Yonas21)
31
47
  - LinkedIn: [linkedin.com/in/yonasalem21](https://www.linkedin.com/in/yonasalem21/)
32
48
  - Email: yonalem21@gmail.com
33
49
 
34
- Zero dependencies. Node 18+.
35
-
36
- ## Publish
37
-
38
- npm now requires 2FA or a granular token. Browser login alone is not enough.
39
-
40
- 1. Enable 2FA on your npm account: [npmjs.com/settings](https://www.npmjs.com/) → Account → Two-Factor Authentication.
41
- 2. Publish with the authenticator code:
42
-
43
50
  ```bash
44
- npm publish --access public --otp=123456
51
+ npx jobless hire
45
52
  ```
46
53
 
47
- Or create a **Granular Access Token** with Read and Write + **Bypass 2FA**, then:
54
+ ## Commands
48
55
 
49
56
  ```bash
50
- npm config set //registry.npmjs.org/:_authToken=npm_YOUR_TOKEN
51
- npm publish --access public
57
+ npx jobless # interactive
58
+ npx jobless rant # the market, with jokes
59
+ npx jobless who # who I am
60
+ npx jobless looking # roles I want
61
+ npx jobless work # proof of work
62
+ npx jobless skills # the stack
63
+ npx jobless hire # links + email
52
64
  ```
53
65
 
54
- Then tell people:
55
-
56
- > I was so done with the job market that I published a resume to npm. Run `npx jobless`.
66
+ Zero dependencies. Node 18+.
package/package.json CHANGED
@@ -1,14 +1,17 @@
1
1
  {
2
2
  "name": "jobless",
3
- "version": "1.0.0",
4
- "description": "A terminal resume for a broken job market. npx jobless",
3
+ "version": "1.1.0",
4
+ "description": "npx jobless — I still do not know the recruiter's coffee, mug color, or star sign. A terminal resume for a broken job market.",
5
5
  "keywords": [
6
6
  "cli",
7
7
  "npx",
8
8
  "resume",
9
- "portfolio",
9
+ "rant",
10
+ "job-market",
11
+ "linkedin",
12
+ "recruiter",
10
13
  "terminal",
11
- "job-search",
14
+ "portfolio",
12
15
  "yonas-alem"
13
16
  ],
14
17
  "license": "MIT",
package/src/data.js CHANGED
@@ -41,24 +41,29 @@ export const lookingFor = {
41
41
  'Managers who can say no to a 7-round interview for a role they already understand.',
42
42
  ],
43
43
  no: [
44
- 'Unpaid take-homes that look like a sprint of free consulting.',
45
- '"Entry-level" postings that require 5 years, 12 frameworks, and a public blog.',
46
- 'Culture surveys that take longer than the actual interview.',
44
+ 'Take-homes that are just your Q3 roadmap with a Sunday deadline.',
45
+ '"Entry-level." Must have 5 years, 12 frameworks, and a personal brand.',
46
+ 'Culture surveys longer than the product spec.',
47
+ 'Interviews that secretly grade my guess at their coffee order.',
47
48
  ],
48
49
  };
49
50
 
50
51
  export const rants = [
51
52
  {
52
- title: 'LinkedIn is not a job market anymore',
53
- body: "LinkedIn used to be where you found work. Now it is Instagram with a resume attached. Everyone is a thought leader. Everyone is humbled to announce. Nobody is hiring. The feed is bragging, engagement bait, and 10-slide carousels on 'how senior engineers think' from people who have never been on-call. I did not come here to like your humble-brag. I came here because I can actually build the thing.",
53
+ title: 'LinkedIn: 40% more thought leadership, 0% more jobs',
54
+ body: "LinkedIn used to be a jobs board that accidentally had a feed. Now it is a feed that accidentally has jobs. Everyone is humbled. Everyone is announcing. Everyone is a thought leader on a Tuesday. The algorithm loves a carousel called '10 habits of senior engineers' from someone who has never been on-call. It does not love the person who actually kept production up. I did not open this app to like your new chapter. I opened it because I can build the thing you are posting about.",
54
55
  },
55
56
  {
56
- title: '30 minutes to apply. 0.4 seconds to get rejected',
57
- body: 'I spend half an hour on an application. Upload the PDF. Then type the same PDF into 12 text boxes. Then salary in three currencies. Then a culture quiz. Then "why this company?" as if the ATS is going to read it. I hit submit. The rejection arrives so fast it had to be a machine. Sometimes the rejection beats the confirmation email. Five years of production work, $100K of infra savings, payment rails that moved billions — discarded because the keyword density was wrong.',
57
+ title: 'I applied for 30 minutes. The bot needed 400ms',
58
+ body: 'The modern application is unpaid data entry with extra steps. Upload the PDF. Then type the PDF into twelve boxes the parser already filled wrong. Then salary in USD, GBP, and emotional damage. Then a culture quiz written by someone who has never been in the culture. Then "why this company?" as if Greenhouse is going to light a candle and read it. Submit. Rejected in 400ms. Sometimes the no arrives before the confirmation. Five years in production, $100K pulled out of infra, payment rails that moved billions — filtered out because I did not write "synergy" enough times. Cool product. Would not ship it.',
58
59
  },
59
60
  {
60
- title: 'Recruiters who schedule, then vanish',
61
- body: 'A recruiter books a call. I clear the calendar. I prepare. I show up. They cancel at T-minus two minutes, or reject me after the invite is already on the calendar, or ghost so hard the Google Calendar event is the last human artifact. If you are going to disappear, skip the scheduling theater. Do not waste a working engineer\'s Thursday morning just to keep your Greenhouse pipeline looking alive.',
61
+ title: 'They booked the call so they had something to cancel',
62
+ body: 'Favorite genre of fiction: the recruiter calendar invite. "Loved your profile. Thursday 10am?" I clear the morning. I make tea. I put on a shirt with buttons. 9:58am: "we\'ve decided to move forward with other candidates." Which other candidates. The ones you have not scheduled yet? Or they just never show, and the Google Calendar event is the last proof a human existed. If ghosting is the process, skip the theater. Do not put a working engineer on your Greenhouse stage so the pipeline looks busy. I debug silent failures for a living. Yours is not that silent.',
63
+ },
64
+ {
65
+ title: 'I do not know their coffee, their mug, or their stars',
66
+ body: "The job posting said TypeScript, PostgreSQL, and 'excellent communication.' The actual exam is telepathy. What is on the recruiter's mind at 10:02am. Oat milk or 'just black, I ship.' What color is the mug. Company merch that says world-class talent, or the chipped navy one from a 2019 conference that still has a lipstick ghost. What is their star sign. A Virgo who will reject you for a missing Oxford comma. A Gemini who double-booked you with someone named also-Yonas. A Scorpio who already decided during the handshake. I can trace a silent cron death across 17 processes. I cannot see into their mug. Apparently that was the seniority gap. Next round I will bring a natal chart, a color swatch, and a cortado. Or we could talk about the actual system.",
62
67
  },
63
68
  ];
64
69
 
@@ -166,7 +171,7 @@ export const quotes = [
166
171
  export const menu = [
167
172
  { key: '1', command: 'who', label: 'who I am' },
168
173
  { key: '2', command: 'looking', label: 'roles I want' },
169
- { key: '3', command: 'rant', label: 'the market, unfiltered' },
174
+ { key: '3', command: 'rant', label: 'the market, with jokes' },
170
175
  { key: '4', command: 'work', label: 'proof of work' },
171
176
  { key: '5', command: 'skills', label: 'the stack' },
172
177
  { key: '6', command: 'hire', label: 'hire me / links' },
@@ -174,9 +179,9 @@ export const menu = [
174
179
  ];
175
180
 
176
181
  export const bootLines = [
177
- 'parsing resume.pdf',
178
- 'pasting the same resume into 12 identical boxes',
179
- 'answering "why this company?" for a parser',
180
- 'waiting for a human',
181
- 'human not found',
182
+ 'uploading resume.pdf',
183
+ 'guessing oat milk vs just-black-I-ship',
184
+ 'guessing navy mug vs emotional-support Stanley',
185
+ 'checking if Mercury is in Greenhouse',
186
+ '404 human',
182
187
  ];
package/src/screens.js CHANGED
@@ -74,7 +74,7 @@ export const printHeader = () => {
74
74
  export const printBoot = async () => {
75
75
  hideCursor();
76
76
  try {
77
- print(dim(' simulating the modern application process...'));
77
+ print(dim(' applying to a role that was closed in 2022...'));
78
78
  blank();
79
79
  for (const [index, line] of bootLines.entries()) {
80
80
  print(` ${dim(`[${String(index + 1)}/5]`)} ${line}`);
@@ -82,9 +82,9 @@ export const printBoot = async () => {
82
82
  }
83
83
  blank();
84
84
  print(` ${bold(red('RESULT'))} ${bold('REJECTED')}`);
85
- print(` ${dim('reason')} keyword density insufficient`);
86
- print(` ${dim('elapsed')} 0.41s`);
87
- print(` ${dim('note')} this part is a joke. the rest is not.`);
85
+ print(` ${dim('reason')} guessed white mug. it was navy. also a Virgo.`);
86
+ print(` ${dim('elapsed')} 0.40s (personal best)`);
87
+ print(` ${dim('note')} the loading bar is the joke. the rejection is documentary.`);
88
88
  } finally {
89
89
  showCursor();
90
90
  }
@@ -125,7 +125,7 @@ export const printRant = () => {
125
125
  section('THE MARKET');
126
126
  blank();
127
127
  for (const line of wrap(
128
- 'LinkedIn became social media. Applications became rituals. Recruiters became calendar ghosts.',
128
+ 'The feed is thriving. Hiring is a lore page. The recruiter\'s coffee order is a senior requirement.',
129
129
  )) {
130
130
  print(` ${dim(line)}`);
131
131
  }
@@ -134,7 +134,7 @@ export const printRant = () => {
134
134
  print(box([bold(yellow(rant.title)), '', ...wrap(rant.body, inner())]));
135
135
  }
136
136
  blank();
137
- print(` ${dim('If you are still reading, you are already more serious than the feed.')}`);
137
+ print(` ${dim('Still here? Congrats. You already outperformed the ATS.')}`);
138
138
  };
139
139
 
140
140
  export const printWork = () => {
@@ -220,15 +220,16 @@ export const printHelp = () => {
220
220
  print(` ${bold('npx jobless --json')} machine readable`);
221
221
  print(` ${bold('npx jobless --no-anim')} skip the ATS joke`);
222
222
  blank();
223
- print(` ${dim('Built because LinkedIn stopped being useful.')}`);
223
+ print(` ${dim('Built because the feed would not shut up.')}`);
224
224
  print(` ${dim(profile.website)}`);
225
225
  };
226
226
 
227
227
  export const printLandingTeaser = () => {
228
228
  blank();
229
- print(` ${yellow('LinkedIn is a social network now. This is the actual profile.')}`);
230
- print(` ${dim('Applications take 30 minutes. Rejections take milliseconds.')}`);
231
- print(` ${dim('Recruiters book the call, then ghost the calendar.')}`);
229
+ print(` ${yellow('LinkedIn is a content farm with a jobs tab. This is the profile.')}`);
230
+ print(` ${dim('Applications take 30 minutes. The no takes 400ms.')}`);
231
+ print(` ${dim('Recruiters book the call so they have something to cancel.')}`);
232
+ print(` ${dim('I still do not know their coffee, their mug, or their star sign.')}`);
232
233
  };
233
234
 
234
235
  export const toJson = () =>