@timurtekb/tekjobs 0.31.0 → 0.31.1
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/CHANGELOG.md +4 -5
- package/app/server/cover-letter.mjs +25 -5
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,15 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
Every release, newest first. Written by semantic-release from the commit messages.
|
|
4
4
|
|
|
5
|
-
## 0.31.
|
|
5
|
+
## <small>0.31.1 (2026-10-07)</small>
|
|
6
6
|
|
|
7
|
-
* fix(
|
|
8
|
-
* chore(
|
|
9
|
-
* feat(cli): tekjobs serve opens the app and leaves when the app is closed ([91a584d](https://github.com/Timurtek/tekjobs/commit/91a584d))
|
|
10
|
-
* docs(site): a square cut of the showreel ([26a4f3c](https://github.com/Timurtek/tekjobs/commit/26a4f3c))
|
|
7
|
+
* fix(mail): a recruiter's "401(k)" no longer reads as a signed-out CLI ([8610854](https://github.com/Timurtek/tekjobs/commit/8610854))
|
|
8
|
+
* chore(changelog): one entry for 0.31.0, not the one a failed run left behind ([538df22](https://github.com/Timurtek/tekjobs/commit/538df22))
|
|
11
9
|
|
|
12
10
|
## 0.31.0 (2026-10-07)
|
|
13
11
|
|
|
12
|
+
* fix(cli): servers stay up until you stop them; tekjobs up, down and ps ([4cb10b6](https://github.com/Timurtek/tekjobs/commit/4cb10b6))
|
|
14
13
|
* feat(cli): tekjobs serve opens the app and leaves when the app is closed ([91a584d](https://github.com/Timurtek/tekjobs/commit/91a584d))
|
|
15
14
|
* docs(site): a square cut of the showreel ([26a4f3c](https://github.com/Timurtek/tekjobs/commit/26a4f3c))
|
|
16
15
|
|
|
@@ -214,17 +214,37 @@ export function runLLM(prompt, { timeoutMs = 240000, extraArgs = [] } = {}) {
|
|
|
214
214
|
child.on('error', (e) => { clearTimeout(timer); reject(new Error(`Could not start "${command}": ${e.message}`)); });
|
|
215
215
|
child.on('close', (code) => {
|
|
216
216
|
clearTimeout(timer);
|
|
217
|
-
const
|
|
218
|
-
if (
|
|
219
|
-
if (/failed to authenticate|oauth|not logged in|please log in|login required|unauthorized|401/i.test(all)) return reject(Object.assign(new Error(`${command} is signed out. Open a terminal, run "${command}", sign in, then try again. (The desktop app's login is separate from the terminal's.)`), { kind: 'auth' }));
|
|
220
|
-
if (/requires a newer version|please upgrade/i.test(all)) return reject(Object.assign(new Error(`${command} is out of date and its model refused the request. Update it (npm i -g, or its own updater), then try again.`), { kind: 'outdated' }));
|
|
221
|
-
if (code !== 0 && !out.trim()) return reject(new Error(`${command} exited with code ${code}: ${err.trim().split('\n').slice(-2).join(' ') || 'no output'}`));
|
|
217
|
+
const failure = classifyRun({ code, out, err, command });
|
|
218
|
+
if (failure) return reject(failure);
|
|
222
219
|
resolve(out.replace(/^```[a-z]*\n|\n```\s*$/g, '').trim());
|
|
223
220
|
});
|
|
224
221
|
child.stdin.write(prompt); child.stdin.end();
|
|
225
222
|
});
|
|
226
223
|
}
|
|
227
224
|
|
|
225
|
+
/**
|
|
226
|
+
* What a finished CLI run means: null when it answered, otherwise an Error with a `kind` (missing, auth,
|
|
227
|
+
* outdated, failed) and the CLI's last words. A run that exited 0 with output answered, whatever words the
|
|
228
|
+
* answer contains: the earlier version read "401" and "OAuth" anywhere in the output as a sign-out, and a
|
|
229
|
+
* recruiter's "401(k) match" turned a healthy morning mail check into "claude is signed out".
|
|
230
|
+
*/
|
|
231
|
+
export function classifyRun({ code, out = '', err = '', command = 'claude' }) {
|
|
232
|
+
const tail = err.trim().split('\n').slice(-3).join(' ').slice(0, 300);
|
|
233
|
+
if (/not recognized as an internal|command not found|ENOENT|is not recognized/i.test(err) && !out.trim()) {
|
|
234
|
+
return Object.assign(new Error(`"${command}" is not installed or not on PATH. Install Claude Code, or set another CLI under "llm" in ${CONFIG_FILE}.`), { kind: 'missing' });
|
|
235
|
+
}
|
|
236
|
+
if (code === 0 && out.trim()) return null;
|
|
237
|
+
const signedOut = /not logged in|please run \/login|run `?\/login|failed to authenticate|authentication[_ ]error|invalid[_ ]api[_ ]key|token (has )?expired|(^|\W)unauthorized(\W|$)|\b(http|status|error)\s*:?\s*401\b/i;
|
|
238
|
+
if (signedOut.test(err) || (!out.trim() && signedOut.test(out))) {
|
|
239
|
+
return Object.assign(new Error(`${command} is signed out. Open a terminal, run "${command}", sign in, then try again. (The desktop app's login is separate from the terminal's.) It said: ${tail || 'nothing'}`), { kind: 'auth' });
|
|
240
|
+
}
|
|
241
|
+
if (/requires a newer version|please upgrade/i.test(`${out}\n${err}`)) {
|
|
242
|
+
return Object.assign(new Error(`${command} is out of date and its model refused the request. Update it (npm i -g, or its own updater), then try again.`), { kind: 'outdated' });
|
|
243
|
+
}
|
|
244
|
+
if (!out.trim()) return Object.assign(new Error(`${command} exited with code ${code}: ${tail || 'no output'}`), { kind: 'failed' });
|
|
245
|
+
return null;
|
|
246
|
+
}
|
|
247
|
+
|
|
228
248
|
const drafts = new Map(); // id → { running, startedAt, finishedAt, error, errorKind }
|
|
229
249
|
export function state(id) {
|
|
230
250
|
const d = drafts.get(id) || { running: false, startedAt: null, finishedAt: null, error: '', errorKind: '' };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@timurtekb/tekjobs",
|
|
3
|
-
"version": "0.31.
|
|
3
|
+
"version": "0.31.1",
|
|
4
4
|
"description": "A local-first job-search machine: watches hundreds of company job boards, scores every posting against your profile, and files matches into a folder of markdown notes you own. Bring your own LLM through MCP.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|