@profullstack/agenticjobs 0.10.0 → 0.11.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.
Files changed (63) hide show
  1. package/README.md +3 -1
  2. package/dist/cli/args.js +28 -2
  3. package/dist/cli/args.js.map +1 -1
  4. package/dist/cli/index.js +247 -3
  5. package/dist/cli/index.js.map +1 -1
  6. package/dist/client/client.d.ts +36 -0
  7. package/dist/client/client.js +54 -12
  8. package/dist/client/client.js.map +1 -1
  9. package/dist/client/fanout.js +7 -1
  10. package/dist/client/fanout.js.map +1 -1
  11. package/dist/config.d.ts +1 -1
  12. package/dist/config.js +1 -1
  13. package/dist/core/candidates.js +30 -1
  14. package/dist/core/candidates.js.map +1 -1
  15. package/dist/core/capacity-alert.d.ts +84 -0
  16. package/dist/core/capacity-alert.js +144 -0
  17. package/dist/core/capacity-alert.js.map +1 -0
  18. package/dist/core/capacity.d.ts +96 -0
  19. package/dist/core/capacity.js +182 -0
  20. package/dist/core/capacity.js.map +1 -0
  21. package/dist/core/import-job.js +18 -7
  22. package/dist/core/import-job.js.map +1 -1
  23. package/dist/core/import.js +9 -8
  24. package/dist/core/import.js.map +1 -1
  25. package/dist/core/jobs.js +12 -2
  26. package/dist/core/jobs.js.map +1 -1
  27. package/dist/core/orgs.d.ts +39 -0
  28. package/dist/core/orgs.js +69 -0
  29. package/dist/core/orgs.js.map +1 -1
  30. package/dist/directory/federate.js +2 -4
  31. package/dist/directory/federate.js.map +1 -1
  32. package/dist/directory/fetch.d.ts +1 -1
  33. package/dist/markup/resume.js +66 -1
  34. package/dist/markup/resume.js.map +1 -1
  35. package/dist/mcp/server.js +5 -1
  36. package/dist/mcp/server.js.map +1 -1
  37. package/dist/mcp/stdio.js +3 -2
  38. package/dist/mcp/stdio.js.map +1 -1
  39. package/dist/mcp/tools.js +1 -1
  40. package/dist/mcp/tools.js.map +1 -1
  41. package/dist/schema/jsonld.js +1 -8
  42. package/dist/schema/jsonld.js.map +1 -1
  43. package/dist/schema/salary.d.ts +5 -0
  44. package/dist/schema/salary.js +15 -0
  45. package/dist/schema/salary.js.map +1 -0
  46. package/dist/schema/text.js +7 -3
  47. package/dist/schema/text.js.map +1 -1
  48. package/dist/server/routes/api.js +63 -1
  49. package/dist/server/routes/api.js.map +1 -1
  50. package/dist/server/routes/discovery.js +56 -0
  51. package/dist/server/routes/discovery.js.map +1 -1
  52. package/dist/server/routes/openapi.js +17 -1
  53. package/dist/server/routes/openapi.js.map +1 -1
  54. package/dist/views/candidates.d.ts +7 -0
  55. package/dist/views/candidates.js +2 -1
  56. package/dist/views/candidates.js.map +1 -1
  57. package/dist/views/docs.js +38 -3
  58. package/dist/views/docs.js.map +1 -1
  59. package/docs/openjob.md +5 -0
  60. package/docs/openresume.md +36 -0
  61. package/package.json +15 -17
  62. package/web/public/app.css +11 -3
  63. package/web/public/sw.js +1 -1
@@ -44,6 +44,31 @@ export class BoardClient {
44
44
  return this.token !== null && this.token !== '';
45
45
  }
46
46
  async request(method, path, body) {
47
+ const { body: parsed } = await this.requestWithStatus(method, path, body);
48
+ return parsed;
49
+ }
50
+ /**
51
+ * Same as `request`, but keeps the HTTP status.
52
+ *
53
+ * Create endpoints answer 201. The stdio MCP host used to report every
54
+ * success as 200, so `apply_to_job` / `post_job` treated a successful write
55
+ * as a failure.
56
+ */
57
+ async requestWithStatus(method, path, body) {
58
+ try {
59
+ return await this.requestOnce(method, path, body);
60
+ }
61
+ catch (error) {
62
+ // A hosted board that has been idle can miss a single client timeout
63
+ // (curl's default 15s from a distant region, #36) and then answer in
64
+ // about a second. GET is safe to repeat; POST is not.
65
+ if (method === 'GET' && error instanceof ApiError && error.code === 'timeout') {
66
+ return this.requestOnce(method, path, body);
67
+ }
68
+ throw error;
69
+ }
70
+ }
71
+ async requestOnce(method, path, body) {
47
72
  const controller = new AbortController();
48
73
  const timer = setTimeout(() => controller.abort(), this.timeoutMs);
49
74
  try {
@@ -66,15 +91,13 @@ export class BoardClient {
66
91
  catch {
67
92
  // A board that answers HTML where JSON was asked for is usually a
68
93
  // proxy or a login wall, and saying so beats "unexpected token <".
69
- if (!response.ok) {
70
- throw new ApiError(`${this.server} answered ${response.status} with something that is not JSON. Is that a board?`, response.status);
71
- }
94
+ throw new ApiError(`${this.server} answered ${response.status} with something that is not JSON. Is that a board?`, response.status);
72
95
  }
73
96
  if (!response.ok) {
74
97
  const error = parsed?.error;
75
98
  throw new ApiError(error?.message ?? `${this.server} answered ${response.status}.`, response.status, error?.code ?? 'error', error?.fields ?? []);
76
99
  }
77
- return parsed;
100
+ return { status: response.status, body: parsed };
78
101
  }
79
102
  catch (error) {
80
103
  if (error instanceof ApiError)
@@ -129,16 +152,35 @@ export class BoardClient {
129
152
  return this.request('GET', '/api/v1/resumes');
130
153
  }
131
154
  async saveResume(markdown, options = {}) {
132
- if (options.slug !== undefined) {
133
- return this.request('PATCH', `/api/v1/resumes/${encodeURIComponent(options.slug)}`, {
134
- markdown,
135
- ...(options.title === undefined ? {} : { title: options.title }),
136
- });
137
- }
138
- return this.request('POST', '/api/v1/resumes', {
155
+ const body = {
139
156
  markdown,
140
157
  ...(options.title === undefined ? {} : { title: options.title }),
141
- });
158
+ ...(options.visibility === undefined ? {} : { visibility: options.visibility }),
159
+ };
160
+ if (options.slug !== undefined) {
161
+ return this.request('PATCH', `/api/v1/resumes/${encodeURIComponent(options.slug)}`, body);
162
+ }
163
+ return this.request('POST', '/api/v1/resumes', body);
164
+ }
165
+ /** Change only a resume's visibility, leaving the document alone. */
166
+ async setResumeVisibility(slug, visibility) {
167
+ return this.request('PATCH', `/api/v1/resumes/${encodeURIComponent(slug)}`, { visibility });
168
+ }
169
+ async deleteResume(slug) {
170
+ return this.request('DELETE', `/api/v1/resumes/${encodeURIComponent(slug)}`);
171
+ }
172
+ /** The employers this account belongs to, which is not the public list. */
173
+ async myOrgs() {
174
+ return (await this.me()).orgs;
175
+ }
176
+ async createOrg(input) {
177
+ return this.request('POST', '/api/v1/orgs', input);
178
+ }
179
+ async updateOrg(slug, input) {
180
+ return this.request('PATCH', `/api/v1/orgs/${encodeURIComponent(slug)}`, input);
181
+ }
182
+ async deleteOrg(slug) {
183
+ return this.request('DELETE', `/api/v1/orgs/${encodeURIComponent(slug)}`);
142
184
  }
143
185
  async postJob(input) {
144
186
  return this.request('POST', '/api/v1/jobs', input);
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/client/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/client/client.ts"],"names":[],"mappings":"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"}
@@ -7,6 +7,7 @@
7
7
  * nowhere. Same guarantees - parallel, per-board timeout, a board that fails
8
8
  * is named rather than silently dropped.
9
9
  */
10
+ import { annualisedTopSalary } from "../schema/salary.js";
10
11
  import { BoardClient } from "./client.js";
11
12
  import { loadConfig } from "./config.js";
12
13
  export function configuredBoards() {
@@ -56,7 +57,12 @@ export async function searchEverywhere(boards, query, options = {}) {
56
57
  }));
57
58
  // Each board sorted its own page; "newest" across three boards is none of
58
59
  // those orders, so it is redone here.
59
- jobs.sort((a, b) => published(b.job) - published(a.job));
60
+ if (query.sort === 'salary') {
61
+ jobs.sort((a, b) => annualisedTopSalary(b.job.salary) - annualisedTopSalary(a.job.salary));
62
+ }
63
+ else {
64
+ jobs.sort((a, b) => published(b.job) - published(a.job));
65
+ }
60
66
  return {
61
67
  jobs,
62
68
  sources,
@@ -1 +1 @@
1
- {"version":3,"file":"fanout.js","sourceRoot":"","sources":["../../src/client/fanout.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"fanout.js","sourceRoot":"","sources":["../../src/client/fanout.ts"],"names":[],"mappings":"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"}
package/dist/config.d.ts CHANGED
@@ -47,7 +47,7 @@ export interface Config {
47
47
  export declare function sameOrigin(a: string | null, b: string | null): boolean;
48
48
  export declare function loadConfig(env?: NodeJS.ProcessEnv): Config;
49
49
  /** Kept in step with package.json by the release script. */
50
- export declare const VERSION = "0.10.0";
50
+ export declare const VERSION = "0.11.0";
51
51
  export declare const SOFTWARE_NAME = "agenticjobs";
52
52
  /**
53
53
  * Tokens are stored as a hash of what was handed out, so this is the only
package/dist/config.js CHANGED
@@ -82,7 +82,7 @@ export function loadConfig(env = process.env) {
82
82
  };
83
83
  }
84
84
  /** Kept in step with package.json by the release script. */
85
- export const VERSION = '0.10.0';
85
+ export const VERSION = '0.11.0';
86
86
  export const SOFTWARE_NAME = 'agenticjobs';
87
87
  /**
88
88
  * Tokens are stored as a hash of what was handed out, so this is the only
@@ -6,6 +6,7 @@
6
6
  * document they already wrote, and a second copy of the same facts is a second
7
7
  * copy to keep in step.
8
8
  */
9
+ import { parseCapacity } from "./capacity.js";
9
10
  import { parseResume, redactContactChannels } from "../markup/resume.js";
10
11
  /** Contact keys that read as a place rather than an address. */
11
12
  const LOCATION_KEYS = /^(location|based|city|where|region)$/i;
@@ -100,13 +101,41 @@ export function resumeForViewer(resume, signedIn) {
100
101
  return { markdown: resume.markdown, parsed: resume.parsed, redacted: false };
101
102
  return { markdown, parsed: parseResume(markdown), redacted: true };
102
103
  }
104
+ /**
105
+ * The headline, re-checked at render time rather than trusted.
106
+ *
107
+ * `parsed` is a cache written on save, so fixing the parser does not fix the
108
+ * rows already in the table. Cleaning the headline at parse time left the live
109
+ * directory still captioned `Operated by:** DevilX (<address>)` — correct code
110
+ * serving a stale value, which is the shape of every derived-cache bug.
111
+ *
112
+ * A backfill would repair those rows, but it would not stop the next one: any
113
+ * resume saved by an older build, restored from a backup, or written straight
114
+ * into the column arrives here the same way. This is a public directory page
115
+ * and the field is one line of text, so it is checked on the way out. Cheap,
116
+ * and it cannot go stale.
117
+ */
118
+ function headlineOf(resume) {
119
+ const headline = resume.parsed?.headline;
120
+ if (headline === null || headline === undefined)
121
+ return null;
122
+ const cleaned = headline.replace(/\*\*|__/g, '').trim();
123
+ if (cleaned === '')
124
+ return null;
125
+ return /[^\s@]+@[^\s@]+\.[^\s@]+/.test(cleaned) ? null : cleaned;
126
+ }
103
127
  export function toCandidateSummary(resume) {
104
128
  return {
105
129
  slug: resume.publicSlug ?? '',
106
130
  name: nameOf(resume),
107
- headline: resume.parsed?.headline ?? null,
131
+ headline: headlineOf(resume),
108
132
  location: locationOf(resume),
109
133
  skills: skillsOf(resume),
134
+ // Capacity is a summary field for the same reason location is: it is what
135
+ // an employer filters on before opening anything. It is also the one thing
136
+ // here that is null for most resumes today, since the convention is new —
137
+ // the card says so rather than hiding the row.
138
+ capacity: parseCapacity(resume.parsed?.contact ?? []),
110
139
  updatedAt: resume.updatedAt,
111
140
  };
112
141
  }
@@ -1 +1 @@
1
- {"version":3,"file":"candidates.js","sourceRoot":"","sources":["../../src/core/candidates.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,EAAmB,WAAW,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAE1F,gEAAgE;AAChE,MAAM,aAAa,GAAG,uCAAuC,CAAC;AAE9D;;;;;;GAMG;AACH,SAAS,QAAQ,CAAC,MAAc,EAAE,KAAK,GAAG,CAAC;IACzC,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC;IAC/E,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO,EAAE,CAAC;IAErC,MAAM,WAAW,GAAG,OAAO,CAAC,QAAQ;SACjC,KAAK,CAAC,IAAI,CAAC;SACX,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QACtD,yEAAyE;QACzE,yEAAyE;QACzE,uDAAuD;SACtD,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,gCAAgC,EAAE,EAAE,CAAC,CAAC;SACjE,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;IAE1D,MAAM,SAAS,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAC7C,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CACzE,CAAC;IAEF,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,MAAM,KAAK,IAAI,SAAS,EAAE,CAAC;QAC9B,uEAAuE;QACvE,gDAAgD;QAChD,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QACxE,IAAI,OAAO,KAAK,EAAE,IAAI,OAAO,CAAC,MAAM,GAAG,EAAE;YAAE,SAAS;QACpD,MAAM,GAAG,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;QAClC,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,SAAS;QAC5B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACd,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAClB,IAAI,GAAG,CAAC,MAAM,IAAI,KAAK;YAAE,MAAM;IACjC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,UAAU,CAAC,MAAc;IAChC,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAClF,OAAO,KAAK,EAAE,KAAK,IAAI,IAAI,CAAC;AAC9B,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,QAAQ,GAAG,EAAE,CAAC;AAEpB;;;;;;GAMG;AACH,MAAM,UAAU,MAAM,CAAC,MAAc;IACnC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAC3C,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,EAAE,IAAI,MAAM,CAAC,MAAM,IAAI,QAAQ;QAAE,OAAO,MAAM,CAAC;IACtF,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;IAClC,OAAO,KAAK,KAAK,EAAE,IAAI,KAAK,CAAC,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC;AACvE,CAAC;AAUD;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,eAAe,CAC7B,MAAuD,EACvD,QAAiB;IAEjB,IAAI,QAAQ;QAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IAE3F,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,qBAAqB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACtE,2EAA2E;IAC3E,6DAA6D;IAC7D,IAAI,CAAC,QAAQ;QAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IAE5F,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,CAAC,QAAQ,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AACrE,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,MAAc;IAC/C,OAAO;QACL,IAAI,EAAE,MAAM,CAAC,UAAU,IAAI,EAAE;QAC7B,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC;QACpB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,IAAI,IAAI;QACzC,QAAQ,EAAE,UAAU,CAAC,MAAM,CAAC;QAC5B,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC;QACxB,SAAS,EAAE,MAAM,CAAC,SAAS;KAC5B,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,QAAQ,CAAC,MAAuB;IAC9C,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;IAC5D,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QAClC,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QACxB,IAAI,GAAG,KAAK,EAAE;YAAE,SAAS;QACzB,MAAM,GAAG,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;QAC9B,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,SAAS;QAC5B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACd,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAChB,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,QAAQ,CAAC,UAA8B,EAAE,IAAc;IACrE,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,UAAU,CAAC;IACzC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC;IACpD,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE;QACrC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;QAC1E,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;AACL,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,OAAO,CAAC,UAA8B;IACpD,MAAM,MAAM,GAAG,IAAI,GAAG,EAA0C,CAAC;IACjE,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,KAAK,MAAM,KAAK,IAAI,SAAS,CAAC,MAAM,EAAE,CAAC;YACrC,MAAM,GAAG,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;YAChC,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC7B,IAAI,IAAI,KAAK,SAAS;gBAAE,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;;gBAC7D,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;IACD,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAC9B,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAC1D,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"candidates.js","sourceRoot":"","sources":["../../src/core/candidates.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Asking listed candidates to state their swarm capacity.
3
+ *
4
+ * The convention in `capacity.ts` is new, so every resume published before it
5
+ * has nothing to show and the directory says "capacity not stated" on almost
6
+ * every card. Backfilling was the alternative and it is the wrong one: nobody
7
+ * here knows whether a given candidate is one agent or ten, and inventing an
8
+ * answer would put a made-up price on a real person's profile. So we ask.
9
+ *
10
+ * Two rules this module exists to enforce, both of which are easy to get wrong
11
+ * when a send is one function call away:
12
+ *
13
+ * - **It only ever writes to people who are actually missing it.** The set
14
+ * is computed from the same parser the directory renders with, so "who
15
+ * needs asking" and "whose card looks empty" can never drift apart.
16
+ * - **It does not send unless asked to.** `plan` is the default and returns
17
+ * the recipients without contacting anybody, because the cost of a bug in
18
+ * an outbound loop is paid by other people's inboxes and cannot be undone.
19
+ */
20
+ import type pg from 'pg';
21
+ import type { Mailer, Message } from './mail.ts';
22
+ export interface CapacityAlertTarget {
23
+ userId: string;
24
+ email: string;
25
+ /** The name on the resume, for the greeting. */
26
+ name: string;
27
+ /** Board-wide slug, so the mail can link the profile being talked about. */
28
+ publicSlug: string;
29
+ /** The owner's own slug, which is what /me/resumes/<slug> wants. */
30
+ slug: string;
31
+ }
32
+ /**
33
+ * Listed candidates whose resume states no capacity.
34
+ *
35
+ * Only `public` resumes: a private resume is not in the directory, so nothing
36
+ * about it is missing and its owner has not asked to be in this conversation.
37
+ *
38
+ * One row per person, not per resume. A candidate with three public resumes
39
+ * has one inbox, and three emails saying the same thing is how a useful
40
+ * request becomes spam. The most recently touched resume is the one named,
41
+ * because it is the one they are most likely to still be editing.
42
+ */
43
+ export declare function candidatesMissingCapacity(pool: pg.Pool): Promise<CapacityAlertTarget[]>;
44
+ /**
45
+ * The ask.
46
+ *
47
+ * It shows the two lines to paste rather than describing them, because the
48
+ * whole convention *is* two lines and a person who has to go and read a spec
49
+ * to answer a one-question email mostly does not answer it. Both shapes are
50
+ * given — a single agent and a swarm — since "I am one agent" is a real answer
51
+ * and an email that only demonstrates the swarm case reads as though it is not.
52
+ */
53
+ export declare function capacityAlertMessage(options: {
54
+ to: string;
55
+ name: string;
56
+ boardName: string;
57
+ profileUrl: string;
58
+ editUrl: string;
59
+ specUrl: string;
60
+ }): Message;
61
+ export interface CapacityAlertResult {
62
+ target: CapacityAlertTarget;
63
+ /** False when the provider refused, null when this was a plan-only run. */
64
+ sent: boolean | null;
65
+ }
66
+ /**
67
+ * Work the list.
68
+ *
69
+ * `send` has to be passed explicitly. A default of "yes, mail everyone" is the
70
+ * kind of default that turns a typo in a WHERE clause into an apology, and
71
+ * this is the one function in the module that can do that.
72
+ *
73
+ * Sends are sequential. The list is small by construction — it is the people
74
+ * listed on one board who have not filled in one field — and a provider that
75
+ * rate-limits a burst would report failures that mean nothing about the
76
+ * recipient.
77
+ */
78
+ export declare function runCapacityAlerts(options: {
79
+ pool: pg.Pool;
80
+ mailer: Mailer | null;
81
+ boardName: string;
82
+ publicUrl: string;
83
+ send: boolean;
84
+ }): Promise<CapacityAlertResult[]>;
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Asking listed candidates to state their swarm capacity.
3
+ *
4
+ * The convention in `capacity.ts` is new, so every resume published before it
5
+ * has nothing to show and the directory says "capacity not stated" on almost
6
+ * every card. Backfilling was the alternative and it is the wrong one: nobody
7
+ * here knows whether a given candidate is one agent or ten, and inventing an
8
+ * answer would put a made-up price on a real person's profile. So we ask.
9
+ *
10
+ * Two rules this module exists to enforce, both of which are easy to get wrong
11
+ * when a send is one function call away:
12
+ *
13
+ * - **It only ever writes to people who are actually missing it.** The set
14
+ * is computed from the same parser the directory renders with, so "who
15
+ * needs asking" and "whose card looks empty" can never drift apart.
16
+ * - **It does not send unless asked to.** `plan` is the default and returns
17
+ * the recipients without contacting anybody, because the cost of a bug in
18
+ * an outbound loop is paid by other people's inboxes and cannot be undone.
19
+ */
20
+ import { escapeHtml } from "../markup/escape.js";
21
+ import { parseCapacity } from "./capacity.js";
22
+ /**
23
+ * Listed candidates whose resume states no capacity.
24
+ *
25
+ * Only `public` resumes: a private resume is not in the directory, so nothing
26
+ * about it is missing and its owner has not asked to be in this conversation.
27
+ *
28
+ * One row per person, not per resume. A candidate with three public resumes
29
+ * has one inbox, and three emails saying the same thing is how a useful
30
+ * request becomes spam. The most recently touched resume is the one named,
31
+ * because it is the one they are most likely to still be editing.
32
+ */
33
+ export async function candidatesMissingCapacity(pool) {
34
+ const result = await pool.query(`select distinct on (r.user_id)
35
+ r.user_id, u.email, r.title, r.slug, r.public_slug, r.parsed
36
+ from resumes r
37
+ join users u on u.id = r.user_id
38
+ where r.visibility = 'public'
39
+ and r.public_slug is not null
40
+ and u.email is not null
41
+ order by r.user_id, r.updated_at desc`);
42
+ const out = [];
43
+ for (const row of result.rows) {
44
+ // The same parser the card uses. If this ever disagrees with the directory
45
+ // we would be mailing people whose profile already looks complete.
46
+ if (parseCapacity(row.parsed?.contact ?? []) !== null)
47
+ continue;
48
+ const name = row.parsed?.name?.trim();
49
+ out.push({
50
+ userId: row.user_id,
51
+ email: row.email,
52
+ name: name === undefined || name === '' || name.length > 80 ? row.title : name,
53
+ publicSlug: row.public_slug,
54
+ slug: row.slug,
55
+ });
56
+ }
57
+ return out;
58
+ }
59
+ /**
60
+ * The ask.
61
+ *
62
+ * It shows the two lines to paste rather than describing them, because the
63
+ * whole convention *is* two lines and a person who has to go and read a spec
64
+ * to answer a one-question email mostly does not answer it. Both shapes are
65
+ * given — a single agent and a swarm — since "I am one agent" is a real answer
66
+ * and an email that only demonstrates the swarm case reads as though it is not.
67
+ */
68
+ export function capacityAlertMessage(options) {
69
+ const subject = `Add your agent capacity to ${options.boardName}`;
70
+ const lines = [
71
+ `Hi ${options.name},`,
72
+ '',
73
+ `Your profile is listed on ${options.boardName}, and employers browsing it cannot`,
74
+ `tell one thing they care about: whether you are a single agent, or whether you`,
75
+ `run several in parallel — and what that costs.`,
76
+ '',
77
+ `Add two lines to the contact block at the top of your resume:`,
78
+ '',
79
+ ` - **Agents**: 10`,
80
+ ` - **Rate**: $100/hour/agent`,
81
+ '',
82
+ `Your profile would then read "10 agents · $100/hr each · $1,000/hr total".`,
83
+ '',
84
+ `If you are a single agent, that is a real answer and worth stating:`,
85
+ '',
86
+ ` - **Agents**: 1`,
87
+ ` - **Rate**: $100/hour`,
88
+ '',
89
+ `Edit it here: ${options.editUrl}`,
90
+ `Your public profile: ${options.profileUrl}`,
91
+ `The convention: ${options.specUrl}`,
92
+ '',
93
+ `Nothing is removed if you skip this — your profile stays listed and simply`,
94
+ `says the capacity is not stated.`,
95
+ ];
96
+ const code = (text) => `<code>${escapeHtml(text)}</code>`;
97
+ const link = (url, label) => `<a href="${escapeHtml(url)}">${escapeHtml(label)}</a>`;
98
+ const html = [
99
+ `<p>Hi ${escapeHtml(options.name)},</p>`,
100
+ `<p>Your profile is listed on ${escapeHtml(options.boardName)}, and employers browsing it cannot tell one thing they care about: whether you are a single agent, or whether you run several in parallel &mdash; and what that costs.</p>`,
101
+ `<p>Add two lines to the contact block at the top of your resume:</p>`,
102
+ `<pre style="background:#f6f6f6;padding:12px;border-radius:6px">${code('- **Agents**: 10\n- **Rate**: $100/hour/agent')}</pre>`,
103
+ `<p>Your profile would then read &ldquo;10 agents &middot; $100/hr each &middot; $1,000/hr total&rdquo;.</p>`,
104
+ `<p>If you are a single agent, that is a real answer and worth stating:</p>`,
105
+ `<pre style="background:#f6f6f6;padding:12px;border-radius:6px">${code('- **Agents**: 1\n- **Rate**: $100/hour')}</pre>`,
106
+ `<p>${link(options.editUrl, 'Edit your resume')} &middot; ${link(options.profileUrl, 'your public profile')} &middot; ${link(options.specUrl, 'the convention')}</p>`,
107
+ `<p style="color:#666;font-size:12px">Nothing is removed if you skip this &mdash; your profile stays listed and simply says the capacity is not stated.</p>`,
108
+ ].join('');
109
+ return { to: options.to, subject, html, text: lines.join('\n') };
110
+ }
111
+ /**
112
+ * Work the list.
113
+ *
114
+ * `send` has to be passed explicitly. A default of "yes, mail everyone" is the
115
+ * kind of default that turns a typo in a WHERE clause into an apology, and
116
+ * this is the one function in the module that can do that.
117
+ *
118
+ * Sends are sequential. The list is small by construction — it is the people
119
+ * listed on one board who have not filled in one field — and a provider that
120
+ * rate-limits a burst would report failures that mean nothing about the
121
+ * recipient.
122
+ */
123
+ export async function runCapacityAlerts(options) {
124
+ const targets = await candidatesMissingCapacity(options.pool);
125
+ const base = options.publicUrl.replace(/\/+$/, '');
126
+ const out = [];
127
+ for (const target of targets) {
128
+ if (!options.send || options.mailer === null) {
129
+ out.push({ target, sent: null });
130
+ continue;
131
+ }
132
+ const sent = await options.mailer.send(capacityAlertMessage({
133
+ to: target.email,
134
+ name: target.name,
135
+ boardName: options.boardName,
136
+ profileUrl: `${base}/candidates/${target.publicSlug}`,
137
+ editUrl: `${base}/me/resumes/${target.slug}`,
138
+ specUrl: `${base}/docs/openresume#capacity`,
139
+ }));
140
+ out.push({ target, sent });
141
+ }
142
+ return out;
143
+ }
144
+ //# sourceMappingURL=capacity-alert.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capacity-alert.js","sourceRoot":"","sources":["../../src/core/capacity-alert.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Swarm capacity: how many agents a candidate brings, and what they cost.
3
+ *
4
+ * This board's thesis is agents hiring agents, and the question an employer
5
+ * actually has to answer before hiring one is not on any resume yet: is this a
6
+ * single agent, or someone who runs ten in parallel? The difference is the
7
+ * difference between a contractor and a firm, and it changes both the price
8
+ * and the kind of work you would send.
9
+ *
10
+ * It is read out of the resume rather than stored beside it, for the reason
11
+ * `candidates.ts` gives: a profile that restates the document is a second copy
12
+ * to keep in step. The contact block is the right home because it is already
13
+ * where the resume keeps its scalars — `Email`, `Location` — and a reader,
14
+ * an agent and a parser all see the same two lines:
15
+ *
16
+ * # Athena
17
+ * - **Email**: a@b.com
18
+ * - **Agents**: 10
19
+ * - **Rate**: $100/hour/agent
20
+ *
21
+ * Like every other OpenResume convention this one degrades. A resume with
22
+ * neither key is a resume with unstated capacity, not an invalid one, and
23
+ * `parseCapacity` returns null rather than throwing. That matters here more
24
+ * than elsewhere: every resume written before this convention existed has no
25
+ * capacity, and none of them should stop rendering.
26
+ */
27
+ export interface SwarmCapacity {
28
+ /** Agents working in parallel. 1 is a single agent, and is a real answer. */
29
+ agents: number;
30
+ /** Hourly cost of ONE agent. Null when the resume only priced the swarm. */
31
+ ratePerAgent: number | null;
32
+ /** Hourly cost of the whole swarm. Null when the resume gave no price. */
33
+ totalPerHour: number | null;
34
+ /** ISO code where we recognised one, otherwise the symbol as written. */
35
+ currency: string;
36
+ /**
37
+ * True when the resume priced one agent and we multiplied, false when it
38
+ * priced the swarm and we divided.
39
+ *
40
+ * Kept because the two are not equally trustworthy: a stated per-agent rate
41
+ * times a stated agent count is arithmetic, while a per-agent figure derived
42
+ * from a swarm total is an average that may not be what anyone charges.
43
+ */
44
+ ratePerAgentStated: boolean;
45
+ }
46
+ /** The contact block, as `parseResume` produces it. */
47
+ interface ContactLike {
48
+ key: string;
49
+ value: string;
50
+ }
51
+ /**
52
+ * Agents, from a value a person actually typed.
53
+ *
54
+ * "10", "10 agents", "up to 10" and "single" all appear in the wild, so the
55
+ * first integer wins and the words that mean one are handled by name. A count
56
+ * of zero is treated as unstated: nobody is offering zero agents, so it is far
57
+ * more likely to be a placeholder than a claim.
58
+ */
59
+ export declare function parseAgentCount(value: string): number | null;
60
+ interface ParsedRate {
61
+ amount: number;
62
+ currency: string;
63
+ /** The resume said this price is for one agent, not for the whole swarm. */
64
+ perAgent: boolean;
65
+ }
66
+ /**
67
+ * A price, and whether it is per agent.
68
+ *
69
+ * The per-agent question is the one that matters and the one people express
70
+ * loosely: "$100/hour/agent", "$100 per agent per hour", "$100/hr each". Any
71
+ * of those means one agent costs 100. Without such a marker the figure is read
72
+ * as the price of the whole swarm, because "$1000/hour" from someone running
73
+ * ten agents is a swarm price — reading it as per-agent would report a rate
74
+ * ten times too high, which is the expensive direction to be wrong in.
75
+ */
76
+ export declare function parseRate(value: string): ParsedRate | null;
77
+ /**
78
+ * Capacity for a resume, or null when it does not state any.
79
+ *
80
+ * A count with no price is still capacity worth showing — "10 agents, price on
81
+ * request" is a real listing — so a missing rate is not fatal. A price with no
82
+ * count is not: without knowing how many agents it buys, a swarm price and a
83
+ * single-agent price are indistinguishable, and guessing turns an employer's
84
+ * budget into a surprise. That one comes back null.
85
+ */
86
+ export declare function parseCapacity(contact: ContactLike[]): SwarmCapacity | null;
87
+ /**
88
+ * One line an employer can read, e.g. "10 agents · $100/hr each · $1,000/hr total".
89
+ *
90
+ * The total is the number being shopped for and the per-agent rate is how it
91
+ * is justified, so both are shown. A single agent gets neither a multiplication
92
+ * nor the word "total", because "1 agent · $100/hr · $100/hr total" reads like
93
+ * a bug.
94
+ */
95
+ export declare function formatCapacity(capacity: SwarmCapacity): string;
96
+ export {};