@profullstack/agenticjobs 0.5.0 → 0.6.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 (51) hide show
  1. package/README.md +42 -4
  2. package/dist/cli/index.js +70 -1
  3. package/dist/cli/index.js.map +1 -1
  4. package/dist/client/client.d.ts +36 -0
  5. package/dist/client/client.js +22 -0
  6. package/dist/client/client.js.map +1 -1
  7. package/dist/config.d.ts +1 -1
  8. package/dist/config.js +1 -1
  9. package/dist/core/auth.js +4 -1
  10. package/dist/core/auth.js.map +1 -1
  11. package/dist/core/markdown-media.d.ts +51 -0
  12. package/dist/core/markdown-media.js +224 -0
  13. package/dist/core/markdown-media.js.map +1 -0
  14. package/dist/core/resumes.d.ts +12 -0
  15. package/dist/core/resumes.js +19 -0
  16. package/dist/core/resumes.js.map +1 -1
  17. package/dist/core/updates.d.ts +149 -0
  18. package/dist/core/updates.js +332 -0
  19. package/dist/core/updates.js.map +1 -0
  20. package/dist/directory/fetch.d.ts +1 -1
  21. package/dist/mcp/tools.js +78 -0
  22. package/dist/mcp/tools.js.map +1 -1
  23. package/dist/server/middleware.d.ts +11 -6
  24. package/dist/server/middleware.js +12 -7
  25. package/dist/server/middleware.js.map +1 -1
  26. package/dist/server/routes/api.js +167 -0
  27. package/dist/server/routes/api.js.map +1 -1
  28. package/dist/server/routes/discovery.js +130 -11
  29. package/dist/server/routes/discovery.js.map +1 -1
  30. package/dist/server/routes/openapi.js +105 -0
  31. package/dist/server/routes/openapi.js.map +1 -1
  32. package/dist/server/routes/pages.js +208 -9
  33. package/dist/server/routes/pages.js.map +1 -1
  34. package/dist/views/candidates.d.ts +3 -0
  35. package/dist/views/candidates.js +3 -2
  36. package/dist/views/candidates.js.map +1 -1
  37. package/dist/views/jobs.d.ts +40 -1
  38. package/dist/views/jobs.js +69 -4
  39. package/dist/views/jobs.js.map +1 -1
  40. package/dist/views/layout.js +2 -2
  41. package/dist/views/layout.js.map +1 -1
  42. package/dist/views/me.d.ts +11 -0
  43. package/dist/views/me.js +5 -2
  44. package/dist/views/me.js.map +1 -1
  45. package/dist/views/updates.d.ts +80 -0
  46. package/dist/views/updates.js +49 -0
  47. package/dist/views/updates.js.map +1 -0
  48. package/migrations/0010_updates_and_follows.sql +70 -0
  49. package/package.json +17 -15
  50. package/web/public/app.css +44 -0
  51. package/web/public/sw.js +1 -1
@@ -6,6 +6,7 @@ import type { FC } from 'hono/jsx';
6
6
  import type { Job, Organisation } from '../schema/index.ts';
7
7
  import type { Resume } from '../core/resumes.ts';
8
8
  import type { Viewer } from '../core/auth.ts';
9
+ import type { Following, Update } from '../core/updates.ts';
9
10
  export declare const MePage: FC<{
10
11
  viewer: Viewer;
11
12
  orgs: Organisation[];
@@ -17,6 +18,16 @@ export declare const MePage: FC<{
17
18
  status: string;
18
19
  createdAt: string;
19
20
  }[];
21
+ /** Your own updates, and who you follow. */
22
+ updates: Update[];
23
+ following: Following[];
24
+ /**
25
+ * The page your updates would appear on, or null if you have not published
26
+ * a resume. Posting requires one: an update whose author has no page is an
27
+ * anonymous post, which is the thing this feature must not become.
28
+ */
29
+ candidateSlug: string | null;
30
+ updateMax: number;
20
31
  }>;
21
32
  export declare const ResumeEditor: FC<{
22
33
  resume: Resume | null;
package/dist/views/me.js CHANGED
@@ -1,7 +1,10 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "hono/jsx/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "hono/jsx/jsx-runtime";
2
2
  import { ago } from "../schema/text.js";
3
3
  import { Alert, Badge, Card, Empty, Field, Prose } from "./layout.js";
4
- export const MePage = ({ viewer, orgs, jobs, resumes, applications }) => (_jsxs("div", { class: "stack", children: [_jsxs("div", { children: [_jsx("h1", { children: "You" }), _jsx("p", { class: "lede", children: viewer.email })] }), _jsxs("section", { class: "stack", children: [_jsxs("div", { class: "spread", children: [_jsx("h2", { children: "Resumes" }), _jsx("a", { class: "btn btn-sm", href: "/me/resumes/new", children: "New resume" })] }), _jsx("p", { class: "small muted", children: "Markdown, in the OpenResume.md convention. Upload a PDF or a Word file and it is converted for you; what you keep is the Markdown." }), resumes.length === 0 ? (_jsx(Empty, { children: "No resumes yet." })) : (_jsx("ul", { class: "job-list", children: resumes.map((resume) => (_jsx("li", { children: _jsxs("a", { class: "card card-link", href: `/me/resumes/${resume.slug}`, children: [_jsxs("div", { class: "spread", children: [_jsx("h3", { class: "card-title", children: resume.title }), _jsx(Badge, { variant: resume.visibility === 'private' ? 'outline' : 'primary', children: resume.visibility })] }), _jsxs("p", { class: "small muted", children: ["Updated ", ago(resume.updatedAt), resume.sourceName !== null && ` - from ${resume.sourceName}`] })] }) }))) }))] }), _jsxs("section", { class: "stack", children: [_jsxs("div", { class: "spread", children: [_jsx("h2", { children: "Employers" }), _jsx("a", { class: "btn btn-sm btn-secondary", href: "/me/employers/new", children: "Add an employer" })] }), orgs.length === 0 ? (_jsx(Empty, { children: "You cannot post a job until you add the employer it is for." })) : (_jsx("div", { class: "row", children: orgs.map((org) => (_jsx("a", { class: "badge badge-primary", href: `/employers/${org.slug}`, children: org.name }))) }))] }), _jsxs("section", { class: "stack", children: [_jsxs("div", { class: "spread", children: [_jsx("h2", { children: "Your listings" }), orgs.length > 0 && (_jsx("a", { class: "btn btn-sm", href: "/post", children: "Post a job" }))] }), jobs.length === 0 ? (_jsx(Empty, { children: "Nothing posted yet." })) : (_jsx("ul", { class: "job-list", children: jobs.map((job) => (_jsx("li", { children: _jsxs("a", { class: "card card-link", href: `/me/jobs/${job.slug}`, children: [_jsxs("div", { class: "spread", children: [_jsx("h3", { class: "card-title", children: job.title }), _jsx(Badge, { variant: job.status === 'published' ? 'primary' : 'outline', children: job.status })] }), _jsxs("p", { class: "small muted", children: [job.org.name, " - ", job.status === 'published' ? ago(job.publishedAt) : 'not live'] })] }) }))) }))] }), _jsxs("section", { class: "stack", children: [_jsx("h2", { children: "Applications you have sent" }), applications.length === 0 ? (_jsx(Empty, { children: "None yet." })) : (_jsx("ul", { class: "job-list", children: applications.map((application) => (_jsx("li", { children: _jsxs("a", { class: "card card-link", href: `/jobs/${application.jobSlug}`, children: [_jsxs("div", { class: "spread", children: [_jsx("h3", { class: "card-title", children: application.jobTitle }), _jsx(Badge, { variant: "outline", children: application.status })] }), _jsxs("p", { class: "small muted", children: ["Sent ", ago(application.createdAt)] })] }) }))) }))] }), _jsxs(Card, { children: [_jsxs("div", { class: "card-header", children: [_jsx("h2", { class: "card-title", children: "Terminals and agents" }), _jsxs("p", { class: "card-description", children: [_jsx("code", { children: "agenticjobs login" }), " asks this board for a code; approve it at", ' ', _jsx("a", { href: "/device", children: "/device" }), ". A terminal token can read and apply, and is never an administrator."] })] }), _jsx("button", { class: "btn btn-secondary btn-sm", type: "button", id: "passkey-add", hidden: true, children: "Add a passkey to this account" }), _jsx("p", { class: "small error-text", id: "passkey-add-error", hidden: true }), _jsx("form", { method: "post", action: "/logout", style: "margin-top:.75rem", children: _jsx("button", { class: "btn btn-ghost btn-sm", type: "submit", children: "Sign out of this browser" }) })] })] }));
4
+ import { UpdateComposer, UpdateList } from "./updates.js";
5
+ export const MePage = ({ viewer, orgs, jobs, resumes, applications, updates, following, candidateSlug, updateMax, }) => (_jsxs("div", { class: "stack", children: [_jsxs("div", { children: [_jsx("h1", { children: "You" }), _jsx("p", { class: "lede", children: viewer.email })] }), _jsxs("section", { class: "stack", children: [_jsxs("div", { class: "spread", children: [_jsx("h2", { children: "Resumes" }), _jsx("a", { class: "btn btn-sm", href: "/me/resumes/new", children: "New resume" })] }), _jsx("p", { class: "small muted", children: "Markdown, in the OpenResume.md convention. Upload a PDF or a Word file and it is converted for you; what you keep is the Markdown." }), resumes.length === 0 ? (_jsx(Empty, { children: "No resumes yet." })) : (_jsx("ul", { class: "job-list", children: resumes.map((resume) => (_jsx("li", { children: _jsxs("a", { class: "card card-link", href: `/me/resumes/${resume.slug}`, children: [_jsxs("div", { class: "spread", children: [_jsx("h3", { class: "card-title", children: resume.title }), _jsx(Badge, { variant: resume.visibility === 'private' ? 'outline' : 'primary', children: resume.visibility })] }), _jsxs("p", { class: "small muted", children: ["Updated ", ago(resume.updatedAt), resume.sourceName !== null && ` - from ${resume.sourceName}`] })] }) }))) }))] }), _jsxs("section", { class: "stack", children: [_jsx("h2", { children: "Updates" }), candidateSlug === null ? (_jsx("p", { class: "small muted", children: "Publish a resume and you can post updates as yourself: what you shipped, when you are free next. They appear on your candidate page and in the board's feed." })) : (_jsxs(_Fragment, { children: [_jsx(UpdateComposer, { action: "/me/updates", as: viewer.name ?? viewer.email, max: updateMax }), updates.length > 0 && _jsx(UpdateList, { updates: updates, showAuthor: false })] })), following.length > 0 && (_jsxs("p", { class: "small muted", children: ["Following", ' ', following.map((entry, index) => (_jsxs(_Fragment, { children: [index > 0 && ', ', entry.slug === null ? (entry.name) : (_jsx("a", { href: entry.kind === 'employer'
6
+ ? `/employers/${entry.slug}`
7
+ : `/candidates/${entry.slug}`, children: entry.name }))] }))), ". ", _jsx("a", { href: "/updates", children: "Their updates" }), "."] }))] }), _jsxs("section", { class: "stack", children: [_jsxs("div", { class: "spread", children: [_jsx("h2", { children: "Employers" }), _jsx("a", { class: "btn btn-sm btn-secondary", href: "/me/employers/new", children: "Add an employer" })] }), orgs.length === 0 ? (_jsx(Empty, { children: "You cannot post a job until you add the employer it is for." })) : (_jsx("div", { class: "row", children: orgs.map((org) => (_jsx("a", { class: "badge badge-primary", href: `/employers/${org.slug}`, children: org.name }))) }))] }), _jsxs("section", { class: "stack", children: [_jsxs("div", { class: "spread", children: [_jsx("h2", { children: "Your listings" }), orgs.length > 0 && (_jsx("a", { class: "btn btn-sm", href: "/post", children: "Post a job" }))] }), jobs.length === 0 ? (_jsx(Empty, { children: "Nothing posted yet." })) : (_jsx("ul", { class: "job-list", children: jobs.map((job) => (_jsx("li", { children: _jsxs("a", { class: "card card-link", href: `/me/jobs/${job.slug}`, children: [_jsxs("div", { class: "spread", children: [_jsx("h3", { class: "card-title", children: job.title }), _jsx(Badge, { variant: job.status === 'published' ? 'primary' : 'outline', children: job.status })] }), _jsxs("p", { class: "small muted", children: [job.org.name, " - ", job.status === 'published' ? ago(job.publishedAt) : 'not live'] })] }) }))) }))] }), _jsxs("section", { class: "stack", children: [_jsx("h2", { children: "Applications you have sent" }), applications.length === 0 ? (_jsx(Empty, { children: "None yet." })) : (_jsx("ul", { class: "job-list", children: applications.map((application) => (_jsx("li", { children: _jsxs("a", { class: "card card-link", href: `/jobs/${application.jobSlug}`, children: [_jsxs("div", { class: "spread", children: [_jsx("h3", { class: "card-title", children: application.jobTitle }), _jsx(Badge, { variant: "outline", children: application.status })] }), _jsxs("p", { class: "small muted", children: ["Sent ", ago(application.createdAt)] })] }) }))) }))] }), _jsxs(Card, { children: [_jsxs("div", { class: "card-header", children: [_jsx("h2", { class: "card-title", children: "Terminals and agents" }), _jsxs("p", { class: "card-description", children: [_jsx("code", { children: "agenticjobs login" }), " asks this board for a code; approve it at", ' ', _jsx("a", { href: "/device", children: "/device" }), ". A terminal token can read and apply, and is never an administrator."] })] }), _jsx("button", { class: "btn btn-secondary btn-sm", type: "button", id: "passkey-add", hidden: true, children: "Add a passkey to this account" }), _jsx("p", { class: "small error-text", id: "passkey-add-error", hidden: true }), _jsx("form", { method: "post", action: "/logout", style: "margin-top:.75rem", children: _jsx("button", { class: "btn btn-ghost btn-sm", type: "submit", children: "Sign out of this browser" }) })] })] }));
5
8
  export const ResumeEditor = ({ resume, html, warnings, error, saved }) => (
6
9
  /*
7
10
  * The preview sits below the editor, not beside it.
@@ -1 +1 @@
1
- {"version":3,"file":"me.js","sourceRoot":"","sources":["../../src/views/me.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"me.js","sourceRoot":"","sources":["../../src/views/me.tsx"],"names":[],"mappings":";AASA,OAAO,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AACxC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,aAAc,CAAC;AACvE,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,cAAe,CAAC;AAG3D,MAAM,CAAC,MAAM,MAAM,GAgBd,CAAC,EACJ,MAAM,EACN,IAAI,EACJ,IAAI,EACJ,OAAO,EACP,YAAY,EACZ,OAAO,EACP,SAAS,EACT,aAAa,EACb,SAAS,GACV,EAAE,EAAE,CAAC,CACJ,eAAK,KAAK,EAAC,OAAO,aAChB,0BACE,+BAAY,EACZ,YAAG,KAAK,EAAC,MAAM,YAAE,MAAM,CAAC,KAAK,GAAK,IAC9B,EAEN,mBAAS,KAAK,EAAC,OAAO,aACpB,eAAK,KAAK,EAAC,QAAQ,aACjB,mCAAgB,EAChB,YAAG,KAAK,EAAC,YAAY,EAAC,IAAI,EAAC,iBAAiB,2BAExC,IACA,EACN,YAAG,KAAK,EAAC,aAAa,mJAGlB,EACH,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CACtB,KAAC,KAAK,kCAAwB,CAC/B,CAAC,CAAC,CAAC,CACF,aAAI,KAAK,EAAC,UAAU,YACjB,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CACvB,uBACE,aAAG,KAAK,EAAC,gBAAgB,EAAC,IAAI,EAAE,eAAe,MAAM,CAAC,IAAI,EAAE,aAC1D,eAAK,KAAK,EAAC,QAAQ,aACjB,aAAI,KAAK,EAAC,YAAY,YAAE,MAAM,CAAC,KAAK,GAAM,EAC1C,KAAC,KAAK,IAAC,OAAO,EAAE,MAAM,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,YACpE,MAAM,CAAC,UAAU,GACZ,IACJ,EACN,aAAG,KAAK,EAAC,aAAa,yBACX,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,EAC7B,MAAM,CAAC,UAAU,KAAK,IAAI,IAAI,WAAW,MAAM,CAAC,UAAU,EAAE,IAC3D,IACF,GACD,CACN,CAAC,GACC,CACN,IACO,EAEV,mBAAS,KAAK,EAAC,OAAO,aACpB,mCAAgB,EACf,aAAa,KAAK,IAAI,CAAC,CAAC,CAAC,CACxB,YAAG,KAAK,EAAC,aAAa,6KAGlB,CACL,CAAC,CAAC,CAAC,CACF,8BACE,KAAC,cAAc,IACb,MAAM,EAAC,aAAa,EACpB,EAAE,EAAE,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,KAAK,EAC/B,GAAG,EAAE,SAAS,GACd,EACD,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,KAAC,UAAU,IAAC,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,GAAI,IACzE,CACJ,EACA,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,CACvB,aAAG,KAAK,EAAC,aAAa,0BACV,GAAG,EACZ,SAAS,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,CAC/B,8BACG,KAAK,GAAG,CAAC,IAAI,IAAI,EACjB,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,CACrB,KAAK,CAAC,IAAI,CACX,CAAC,CAAC,CAAC,CACF,YACE,IAAI,EACF,KAAK,CAAC,IAAI,KAAK,UAAU;wCACvB,CAAC,CAAC,cAAc,KAAK,CAAC,IAAI,EAAE;wCAC5B,CAAC,CAAC,eAAe,KAAK,CAAC,IAAI,EAAE,YAGhC,KAAK,CAAC,IAAI,GACT,CACL,IACA,CACJ,CAAC,QACA,YAAG,IAAI,EAAC,UAAU,8BAAkB,SACpC,CACL,IACO,EAEV,mBAAS,KAAK,EAAC,OAAO,aACpB,eAAK,KAAK,EAAC,QAAQ,aACjB,qCAAkB,EAClB,YAAG,KAAK,EAAC,0BAA0B,EAAC,IAAI,EAAC,mBAAmB,gCAExD,IACA,EACL,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CACnB,KAAC,KAAK,8EAEE,CACT,CAAC,CAAC,CAAC,CACF,cAAK,KAAK,EAAC,KAAK,YACb,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CACjB,YAAG,KAAK,EAAC,qBAAqB,EAAC,IAAI,EAAE,cAAc,GAAG,CAAC,IAAI,EAAE,YAC1D,GAAG,CAAC,IAAI,GACP,CACL,CAAC,GACE,CACP,IACO,EAEV,mBAAS,KAAK,EAAC,OAAO,aACpB,eAAK,KAAK,EAAC,QAAQ,aACjB,yCAAsB,EACrB,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,CAClB,YAAG,KAAK,EAAC,YAAY,EAAC,IAAI,EAAC,OAAO,2BAE9B,CACL,IACG,EACL,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CACnB,KAAC,KAAK,sCAA4B,CACnC,CAAC,CAAC,CAAC,CACF,aAAI,KAAK,EAAC,UAAU,YACjB,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CACjB,uBACE,aAAG,KAAK,EAAC,gBAAgB,EAAC,IAAI,EAAE,YAAY,GAAG,CAAC,IAAI,EAAE,aACpD,eAAK,KAAK,EAAC,QAAQ,aACjB,aAAI,KAAK,EAAC,YAAY,YAAE,GAAG,CAAC,KAAK,GAAM,EACvC,KAAC,KAAK,IAAC,OAAO,EAAE,GAAG,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,YAC/D,GAAG,CAAC,MAAM,GACL,IACJ,EACN,aAAG,KAAK,EAAC,aAAa,aACnB,GAAG,CAAC,GAAG,CAAC,IAAI,SAAK,GAAG,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,UAAU,IAC9E,IACF,GACD,CACN,CAAC,GACC,CACN,IACO,EAEV,mBAAS,KAAK,EAAC,OAAO,aACpB,sDAAmC,EAClC,YAAY,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAC3B,KAAC,KAAK,4BAAkB,CACzB,CAAC,CAAC,CAAC,CACF,aAAI,KAAK,EAAC,UAAU,YACjB,YAAY,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,CACjC,uBACE,aAAG,KAAK,EAAC,gBAAgB,EAAC,IAAI,EAAE,SAAS,WAAW,CAAC,OAAO,EAAE,aAC5D,eAAK,KAAK,EAAC,QAAQ,aACjB,aAAI,KAAK,EAAC,YAAY,YAAE,WAAW,CAAC,QAAQ,GAAM,EAClD,KAAC,KAAK,IAAC,OAAO,EAAC,SAAS,YAAE,WAAW,CAAC,MAAM,GAAS,IACjD,EACN,aAAG,KAAK,EAAC,aAAa,sBAAO,GAAG,CAAC,WAAW,CAAC,SAAS,CAAC,IAAK,IAC1D,GACD,CACN,CAAC,GACC,CACN,IACO,EAEV,MAAC,IAAI,eACH,eAAK,KAAK,EAAC,aAAa,aACtB,aAAI,KAAK,EAAC,YAAY,qCAA0B,EAChD,aAAG,KAAK,EAAC,kBAAkB,aACzB,+CAA8B,gDAA2C,GAAG,EAC5E,YAAG,IAAI,EAAC,SAAS,wBAAY,6EAE3B,IACA,EAGN,iBAAQ,KAAK,EAAC,0BAA0B,EAAC,IAAI,EAAC,QAAQ,EAAC,EAAE,EAAC,aAAa,EAAC,MAAM,oDAErE,EACT,YAAG,KAAK,EAAC,kBAAkB,EAAC,EAAE,EAAC,mBAAmB,EAAC,MAAM,SAAK,EAC9D,eAAM,MAAM,EAAC,MAAM,EAAC,MAAM,EAAC,SAAS,EAAC,KAAK,EAAC,mBAAmB,YAC5D,iBAAQ,KAAK,EAAC,sBAAsB,EAAC,IAAI,EAAC,QAAQ,yCAEzC,GACJ,IACF,IACH,CACP,CAAC;AAEF,MAAM,CAAC,MAAM,YAAY,GAMpB,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;AACjD;;;;;;;GAOG;AACH,eAAK,KAAK,EAAC,OAAO,aAChB,eAAK,KAAK,EAAC,QAAQ,aACjB,eAAK,KAAK,EAAC,OAAO,aAClB,uBAAK,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,GAAM,EACvD,KAAK,KAAK,SAAS,IAAI,KAAC,KAAK,IAAC,OAAO,EAAC,OAAO,YAAE,KAAK,GAAS,EAC7D,KAAK,KAAK,IAAI,IAAI,KAAC,KAAK,IAAC,OAAO,EAAC,SAAS,uBAAe,EAEzD,MAAM,KAAK,IAAI,IAAI,CAClB,MAAC,IAAI,eACH,eAAK,KAAK,EAAC,aAAa,aACtB,aAAI,KAAK,EAAC,YAAY,kCAAuB,EAC7C,YAAG,KAAK,EAAC,kBAAkB,2JAGvB,IACA,EACN,gBAAM,MAAM,EAAC,MAAM,EAAC,MAAM,EAAC,oBAAoB,EAAC,OAAO,EAAC,qBAAqB,EAAC,KAAK,EAAC,OAAO,aACzF,gBACE,KAAK,EAAC,OAAO,EACb,IAAI,EAAC,MAAM,EACX,IAAI,EAAC,MAAM,EACX,MAAM,EAAC,8CAA8C,EACrD,QAAQ,SACR,EACF,iBAAQ,KAAK,EAAC,KAAK,EAAC,IAAI,EAAC,QAAQ,oCAExB,IACJ,IACF,CACR,EAED,gBACE,KAAK,EAAC,OAAO,EACb,MAAM,EAAC,MAAM,EACb,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,eAAe,MAAM,CAAC,IAAI,EAAE,aAE1E,KAAC,KAAK,IAAC,KAAK,EAAC,OAAO,EAAC,IAAI,EAAC,OAAO,EAAC,IAAI,EAAC,oDAAoD,YACzF,gBACE,KAAK,EAAC,OAAO,EACb,IAAI,EAAC,MAAM,EACX,EAAE,EAAC,OAAO,EACV,IAAI,EAAC,OAAO,EACZ,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,EAAE,EAC1B,WAAW,EAAC,iBAAiB,GAC7B,GACI,EACR,KAAC,KAAK,IACJ,KAAK,EAAC,QAAQ,EACd,IAAI,EAAC,UAAU,EACf,IAAI,EAAC,0FAA0F,YAE/F,mBAAU,KAAK,EAAC,eAAe,EAAC,EAAE,EAAC,UAAU,EAAC,IAAI,EAAC,UAAU,EAAC,UAAU,EAAE,KAAK,YAC5E,MAAM,EAAE,QAAQ,IAAI,EAAE,GACd,GACL,EACR,KAAC,KAAK,IACJ,KAAK,EAAC,gBAAgB,EACtB,IAAI,EAAC,YAAY,EACjB,IAAI,EAAC,2FAA2F,YAEhG,kBAAQ,KAAK,EAAC,QAAQ,EAAC,EAAE,EAAC,YAAY,EAAC,IAAI,EAAC,YAAY,aACtD,iBAAQ,KAAK,EAAC,SAAS,EAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,KAAK,SAAS,+DAEzD,EACT,iBAAQ,KAAK,EAAC,MAAM,EAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,KAAK,MAAM,2DAEnD,EACT,iBAAQ,KAAK,EAAC,QAAQ,EAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,KAAK,QAAQ,8CAEvD,IACF,GACH,EACR,eAAK,KAAK,EAAC,KAAK,aACd,iBAAQ,KAAK,EAAC,KAAK,EAAC,IAAI,EAAC,QAAQ,qBAExB,EACR,MAAM,KAAK,IAAI,IAAI,CAClB,YAAG,KAAK,EAAC,mBAAmB,EAAC,IAAI,EAAE,mBAAmB,MAAM,CAAC,IAAI,EAAE,wBAE/D,CACL,IACG,IACD,EAEN,MAAM,KAAK,IAAI,IAAI,CAClB,eAAM,MAAM,EAAC,MAAM,EAAC,MAAM,EAAE,eAAe,MAAM,CAAC,IAAI,SAAS,YAC7D,iBAAQ,KAAK,EAAC,4BAA4B,EAAC,IAAI,EAAC,QAAQ,mCAE/C,GACJ,CACR,IACG,EAEJ,iBAAO,KAAK,EAAC,OAAO,aACjB,MAAM,KAAK,IAAI,IAAI,MAAM,CAAC,UAAU,KAAK,SAAS,IAAI,MAAM,CAAC,UAAU,KAAK,IAAI,IAAI,CACrF,MAAC,IAAI,eACH,eAAK,KAAK,EAAC,aAAa,aACtB,aAAI,KAAK,EAAC,YAAY,YACnB,MAAM,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,gBAAgB,GACxE,EACL,YAAG,KAAK,EAAC,kBAAkB,YACxB,MAAM,CAAC,UAAU,KAAK,QAAQ;gDAC7B,CAAC,CAAC,oDAAoD;gDACtD,CAAC,CAAC,yDAAyD,GAC3D,IACA,EACN,YAAG,KAAK,EAAC,OAAO,YACd,aAAG,IAAI,EAAE,eAAe,MAAM,CAAC,UAAU,EAAE,6BAAe,MAAM,CAAC,UAAU,IAAK,GAC9E,IACC,CACR,EACE,QAAQ,CAAC,MAAM,GAAG,CAAC,IAAI,CACtB,MAAC,KAAK,IAAC,OAAO,EAAC,SAAS,aACtB,6CAA8B,EAC9B,aAAI,KAAK,EAAC,sCAAsC,YAC7C,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CACzB,uBAAK,OAAO,GAAM,CACnB,CAAC,GACC,IACC,CACT,IACK,IACJ,EAEN,MAAC,IAAI,eACH,eAAK,KAAK,EAAC,aAAa,aACtB,aAAI,KAAK,EAAC,YAAY,wBAAa,EACnC,aAAG,KAAK,EAAC,kBAAkB,kDACS,MAAM,EAAE,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,gCAEpF,IACA,EACN,KAAC,KAAK,IAAC,IAAI,EAAE,IAAI,GAAI,IAChB,IACH,CACP,CAAC"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Updates: the short posts an employer or a candidate makes between jobs.
3
+ *
4
+ * Deliberately plain. There is no like, no repost, no counter that rewards
5
+ * posting more often, because the failure mode of this feature is a feed
6
+ * nobody reads, and every one of those is an incentive to post noise.
7
+ *
8
+ * What an update does have is an author with a page and, at most, one link.
9
+ */
10
+ import type { FC } from 'hono/jsx';
11
+ import type { Following, Update } from '../core/updates.ts';
12
+ export declare const UpdateItem: FC<{
13
+ update: Update;
14
+ showAuthor?: boolean;
15
+ }>;
16
+ export declare const UpdateList: FC<{
17
+ updates: Update[];
18
+ showAuthor?: boolean;
19
+ }>;
20
+ /**
21
+ * The composer.
22
+ *
23
+ * `action` is where it posts, so the same form serves an employer page and a
24
+ * candidate's own dashboard without either growing a hidden "who am I" field
25
+ * that a caller could change.
26
+ */
27
+ export declare const UpdateComposer: FC<{
28
+ action: string;
29
+ as: string;
30
+ max: number;
31
+ error?: string;
32
+ value?: string;
33
+ }>;
34
+ /**
35
+ * Follow, as a form rather than a link.
36
+ *
37
+ * A GET that changes state is a state change any prefetching browser, mail
38
+ * scanner or crawler can make on the reader's behalf.
39
+ */
40
+ export declare const FollowButton: FC<{
41
+ action: string;
42
+ following: boolean;
43
+ followers: number;
44
+ signedIn: boolean;
45
+ /** Where to send a signed-out reader back to after they sign in. */
46
+ next: string;
47
+ }>;
48
+ /**
49
+ * Everything social about one author, in one block.
50
+ *
51
+ * The employer page and the candidate page get the identical thing rather
52
+ * than each growing their own follow button and their own list, because two
53
+ * of these would drift the first time one is changed.
54
+ */
55
+ export interface SocialProps {
56
+ /** The name of whoever this page is about, for the composer. */
57
+ as: string;
58
+ updates: Update[];
59
+ follow: {
60
+ action: string;
61
+ following: boolean;
62
+ followers: number;
63
+ signedIn: boolean;
64
+ next: string;
65
+ };
66
+ /** Present only when the viewer is allowed to post as this author. */
67
+ composer: {
68
+ action: string;
69
+ max: number;
70
+ } | null;
71
+ error?: string;
72
+ }
73
+ export declare const AuthorSocial: FC<SocialProps>;
74
+ /** The board's news page: everything anybody posted. */
75
+ export declare const UpdatesPage: FC<{
76
+ updates: Update[];
77
+ boardName: string;
78
+ followed: Update[] | null;
79
+ following: Following[];
80
+ }>;
@@ -0,0 +1,49 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "hono/jsx/jsx-runtime";
2
+ import { Card, Empty, Field } from "./layout.js";
3
+ import { ago } from "../schema/text.js";
4
+ /** Where an author's own page is, when they have one. */
5
+ function authorHref(author) {
6
+ if (author.slug === null)
7
+ return null;
8
+ return author.kind === 'employer' ? `/employers/${author.slug}` : `/candidates/${author.slug}`;
9
+ }
10
+ /** A link, shown as its host so the destination is legible before the click. */
11
+ function hostOf(link) {
12
+ try {
13
+ return new URL(link).host.replace(/^www\./, '');
14
+ }
15
+ catch {
16
+ return link;
17
+ }
18
+ }
19
+ export const UpdateItem = ({ update, showAuthor = true, }) => {
20
+ const href = authorHref(update.author);
21
+ return (
22
+ // The id is the feed's anchor: every entry's guid points at this element,
23
+ // so an item opened from a reader lands on the update it came from.
24
+ _jsxs("li", { class: "update", id: update.id, children: [showAuthor && (_jsxs("p", { class: "update-author", children: [href === null ? (_jsx("strong", { children: update.author.name })) : (_jsx("a", { href: href, children: _jsx("strong", { children: update.author.name }) })), ' ', _jsxs("span", { class: "small muted", children: [update.author.kind === 'employer' ? 'employer' : 'candidate', " \u00B7", ' ', ago(update.createdAt)] })] })), _jsx("p", { class: "update-body", children: update.body }), update.link !== null && (_jsx("p", { class: "small", children: _jsx("a", { href: update.link, rel: "nofollow noopener", class: "update-link", children: hostOf(update.link) }) })), !showAuthor && _jsx("p", { class: "small muted", children: ago(update.createdAt) })] }));
25
+ };
26
+ export const UpdateList = ({ updates, showAuthor = true, }) => (_jsx("ul", { class: "update-list", children: updates.map((update) => (_jsx(UpdateItem, { update: update, showAuthor: showAuthor }))) }));
27
+ /**
28
+ * The composer.
29
+ *
30
+ * `action` is where it posts, so the same form serves an employer page and a
31
+ * candidate's own dashboard without either growing a hidden "who am I" field
32
+ * that a caller could change.
33
+ */
34
+ export const UpdateComposer = ({ action, as, max, error, value }) => (_jsxs(Card, { children: [_jsxs("div", { class: "card-header", children: [_jsx("h2", { class: "card-title", children: "Post an update" }), _jsxs("p", { class: "card-description", children: ["As ", _jsx("strong", { children: as }), ". What changed: a role filled, something shipped, when you are free next. Five a day, ", max, " characters, one link."] })] }), _jsxs("form", { method: "post", action: action, class: "stack-sm", children: [_jsx(Field, { label: "Update", name: "body", error: error, children: _jsx("textarea", { id: "body", name: "body", rows: 3, maxlength: max, required: true, placeholder: "We just closed the backend role. Two more open next month.", children: value ?? '' }) }), _jsx(Field, { label: "Link", name: "link", hint: "Optional. One public URL.", children: _jsx("input", { id: "link", name: "link", type: "url", placeholder: "https://" }) }), _jsx("div", { class: "row", children: _jsx("button", { class: "btn", type: "submit", children: "Post" }) })] })] }));
35
+ /**
36
+ * Follow, as a form rather than a link.
37
+ *
38
+ * A GET that changes state is a state change any prefetching browser, mail
39
+ * scanner or crawler can make on the reader's behalf.
40
+ */
41
+ export const FollowButton = ({ action, following, followers, signedIn, next }) => (_jsxs("div", { class: "row", style: "align-items:center;gap:.6rem;flex-wrap:wrap", children: [signedIn ? (_jsxs("form", { method: "post", action: action, children: [_jsx("input", { type: "hidden", name: "following", value: following ? 'yes' : 'no' }), _jsx("button", { class: following ? 'btn btn-secondary btn-sm' : 'btn btn-sm', type: "submit", children: following ? 'Following' : 'Follow' })] })) : (_jsx("a", { class: "btn btn-sm", href: `/login?next=${encodeURIComponent(next)}`, children: "Follow" })), _jsxs("span", { class: "small muted", children: [followers, " ", followers === 1 ? 'follower' : 'followers'] })] }));
42
+ export const AuthorSocial = ({ as, updates, follow, composer, error }) => (_jsxs("div", { class: "stack", children: [_jsx(FollowButton, { ...follow }), composer !== null && (_jsx(UpdateComposer, { action: composer.action, as: as, max: composer.max, error: error })), updates.length > 0 && (_jsxs("div", { class: "stack-sm", children: [_jsx("h2", { class: "card-title", children: "Updates" }), _jsx(UpdateList, { updates: updates, showAuthor: false })] }))] }));
43
+ /** The board's news page: everything anybody posted. */
44
+ export const UpdatesPage = ({ updates, boardName, followed, following }) => (_jsxs("div", { class: "stack", children: [_jsxs("div", { class: "stack-sm", children: [_jsx("h1", { children: "Updates" }), _jsxs("p", { class: "lede", children: ["Short posts from the employers and candidates on ", boardName, ". Everyone here is a real employer or a person with a resume, and nobody can post more than five a day."] })] }), followed !== null && (_jsxs(Card, { children: [_jsx("div", { class: "card-header", children: _jsxs("h2", { class: "card-title", children: ["From the ", following.length, " you follow"] }) }), followed.length === 0 ? (_jsx("p", { class: "small muted", children: following.length === 0
45
+ ? 'You do not follow anybody yet. There is a Follow button on every employer and candidate page.'
46
+ : 'Nothing yet from anybody you follow.' })) : (_jsx(UpdateList, { updates: followed })), following.length > 0 && (_jsxs("p", { class: "small muted", style: "margin-top:.6rem", children: ["Following:", ' ', following.map((entry, index) => (_jsxs(_Fragment, { children: [index > 0 && ', ', entry.slug === null ? (entry.name) : (_jsx("a", { href: entry.kind === 'employer'
47
+ ? `/employers/${entry.slug}`
48
+ : `/candidates/${entry.slug}`, children: entry.name }))] })))] }))] })), _jsx("h2", { class: "card-title", children: "Everyone" }), updates.length === 0 ? (_jsxs(Empty, { children: [_jsx("h2", { children: "Nothing posted yet" }), _jsx("p", { children: "An employer or a candidate posts here from their own page. It is the space between \"posted a job\" and silence." })] })) : (_jsx(UpdateList, { updates: updates })), _jsxs("p", { class: "small muted", children: ["This page is a feed: ", _jsx("a", { href: "/updates/feed", children: "/updates/feed" }), ", as Markdown at", ' ', _jsx("a", { href: "/updates.md", children: "/updates.md" }), ", as JSON at ", _jsx("a", { href: "/api/v1/updates", children: "/api/v1/updates" }), ". One author at a time with ", _jsx("code", { children: "?org=slug" }), " or ", _jsx("code", { children: "?candidate=slug" }), "."] })] }));
49
+ //# sourceMappingURL=updates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"updates.js","sourceRoot":"","sources":["../../src/views/updates.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ -- Updates, and following the people who post them.
2
+ --
3
+ -- A short post from an employer or a candidate: hiring news, what shipped,
4
+ -- what someone is looking for next. The thing that makes this worth having
5
+ -- rather than another timeline is that it is attached to an identity the board
6
+ -- already knows, so an update is from a real employer or a real candidate and
7
+ -- not from an account made this morning.
8
+ --
9
+ -- Two constraints are in the schema rather than in a validator, because they
10
+ -- are what stop this becoming a spam feed and a validator is easy to route
11
+ -- around:
12
+ --
13
+ -- - An update is short. 600 characters is a paragraph and a link, which is
14
+ -- the shape of the thing; it is not room for an article.
15
+ -- - An update has exactly one author, and that author is an employer this
16
+ -- person belongs to or their own candidate profile. There is no anonymous
17
+ -- posting and no posting as somebody else.
18
+
19
+ create table if not exists updates (
20
+ id uuid primary key default gen_random_uuid(),
21
+ -- Exactly one of these. A CHECK enforces it rather than a comment hoping.
22
+ org_id uuid references organisations (id) on delete cascade,
23
+ user_id uuid references users (id) on delete cascade,
24
+ -- Who actually typed it, kept even for an org post so a deleted member's
25
+ -- posts can be found, and so "who posted this" has an answer.
26
+ author_id uuid not null references users (id) on delete cascade,
27
+ body text not null check (length(body) between 1 and 600),
28
+ -- One link, optional. Kept as a column rather than fished out of the body,
29
+ -- so a reader and an agent see the same URL and nothing has to parse prose.
30
+ link text,
31
+ created_at timestamptz not null default now(),
32
+ constraint updates_one_author check (
33
+ (org_id is not null and user_id is null) or (org_id is null and user_id is not null)
34
+ )
35
+ );
36
+
37
+ -- The feed reads "newest first, by author", and the whole-board feed reads
38
+ -- "newest first" across everything.
39
+ create index if not exists updates_org_idx on updates (org_id, created_at desc)
40
+ where org_id is not null;
41
+ create index if not exists updates_user_idx on updates (user_id, created_at desc)
42
+ where user_id is not null;
43
+ create index if not exists updates_recent_idx on updates (created_at desc);
44
+
45
+ -- Following.
46
+ --
47
+ -- A row is one person following one employer or one candidate. Same one-target
48
+ -- rule as an update, for the same reason, and a unique index rather than a
49
+ -- primary key over nullable columns so following twice is a no-op instead of
50
+ -- an error the caller has to interpret.
51
+ create table if not exists follows (
52
+ id uuid primary key default gen_random_uuid(),
53
+ follower_id uuid not null references users (id) on delete cascade,
54
+ org_id uuid references organisations (id) on delete cascade,
55
+ user_id uuid references users (id) on delete cascade,
56
+ created_at timestamptz not null default now(),
57
+ constraint follows_one_target check (
58
+ (org_id is not null and user_id is null) or (org_id is null and user_id is not null)
59
+ ),
60
+ -- Nobody follows themselves; it is not an error worth a message, but it is
61
+ -- not a row worth keeping either.
62
+ constraint follows_not_self check (user_id is null or user_id <> follower_id)
63
+ );
64
+
65
+ create unique index if not exists follows_org_key
66
+ on follows (follower_id, org_id) where org_id is not null;
67
+ create unique index if not exists follows_user_key
68
+ on follows (follower_id, user_id) where user_id is not null;
69
+ create index if not exists follows_org_count_idx on follows (org_id) where org_id is not null;
70
+ create index if not exists follows_user_count_idx on follows (user_id) where user_id is not null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@profullstack/agenticjobs",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "An agent-friendly job board you self-host. It posts its own jobs, never scrapes anyone else's, and answers on every surface: web, API, MCP, CLI, TUI, desktop and PWA. Instances find each other through an open directory.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -29,6 +29,7 @@
29
29
  "engines": {
30
30
  "node": ">=24"
31
31
  },
32
+ "packageManager": "pnpm@11.18.0",
32
33
  "bin": {
33
34
  "agenticjobs": "./bin/agenticjobs.mjs",
34
35
  "agenticjobs-mcp": "./bin/agenticjobs-mcp.mjs"
@@ -42,6 +43,20 @@
42
43
  "README.md",
43
44
  "LICENSE"
44
45
  ],
46
+ "scripts": {
47
+ "build": "tsc -p tsconfig.json",
48
+ "clean": "rm -rf dist",
49
+ "dev": "node --env-file-if-exists=.env --watch dist/cli/index.js serve",
50
+ "start": "node --env-file-if-exists=.env dist/cli/index.js serve",
51
+ "migrate": "node --env-file-if-exists=.env dist/db/migrate.js",
52
+ "seed": "node --env-file-if-exists=.env dist/db/seed.js",
53
+ "tui": "node --env-file-if-exists=.env dist/cli/index.js tui",
54
+ "test": "pnpm run build && node --test \"test/*.test.ts\"",
55
+ "typecheck": "tsc -p tsconfig.json --noEmit",
56
+ "format": "prettier --write .",
57
+ "prepublishOnly": "pnpm run clean && pnpm run build",
58
+ "test:only": "node --test \"test/*.test.ts\""
59
+ },
45
60
  "dependencies": {
46
61
  "@hono/node-server": "^1.14.0",
47
62
  "@profullstack/emailer": "^1.0.3",
@@ -74,18 +89,5 @@
74
89
  "default": "./dist/mcp/server.js"
75
90
  },
76
91
  "./package.json": "./package.json"
77
- },
78
- "scripts": {
79
- "build": "tsc -p tsconfig.json",
80
- "clean": "rm -rf dist",
81
- "dev": "node --env-file-if-exists=.env --watch dist/cli/index.js serve",
82
- "start": "node --env-file-if-exists=.env dist/cli/index.js serve",
83
- "migrate": "node --env-file-if-exists=.env dist/db/migrate.js",
84
- "seed": "node --env-file-if-exists=.env dist/db/seed.js",
85
- "tui": "node --env-file-if-exists=.env dist/cli/index.js tui",
86
- "test": "pnpm run build && node --test \"test/*.test.ts\"",
87
- "typecheck": "tsc -p tsconfig.json --noEmit",
88
- "format": "prettier --write .",
89
- "test:only": "node --test \"test/*.test.ts\""
90
92
  }
91
- }
93
+ }
@@ -815,3 +815,47 @@ a.badge-plain:hover .badge {
815
815
  .install-strip .install-note {
816
816
  margin: 0;
817
817
  }
818
+
819
+ /* --- updates ------------------------------------------------------------
820
+ *
821
+ * A short post from an employer or a candidate. Deliberately quieter than a
822
+ * job card: this is the space between listings rather than a second kind of
823
+ * listing, and anything that makes one post look important is an argument
824
+ * for posting more of them.
825
+ */
826
+
827
+ .update-list {
828
+ list-style: none;
829
+ margin: 0;
830
+ padding: 0;
831
+ display: flex;
832
+ flex-direction: column;
833
+ gap: 0.75rem;
834
+ }
835
+
836
+ .update {
837
+ border: 1px solid var(--border);
838
+ border-radius: var(--radius);
839
+ padding: 0.9rem 1rem;
840
+ background: var(--card);
841
+ /* The feed's guids are anchors into this page, so an item opened from a
842
+ reader lands somewhere that is not behind the header. */
843
+ scroll-margin-top: 5rem;
844
+ }
845
+
846
+ .update-author {
847
+ margin: 0 0 0.35rem;
848
+ }
849
+
850
+ .update-body {
851
+ margin: 0;
852
+ /* Written in a textarea, so its line breaks are the ones the author made. */
853
+ white-space: pre-wrap;
854
+ /* A pasted URL is one unbreakable word and would otherwise push the card
855
+ wider than the viewport on a phone. */
856
+ overflow-wrap: anywhere;
857
+ }
858
+
859
+ .update-link {
860
+ overflow-wrap: anywhere;
861
+ }
package/web/public/sw.js CHANGED
@@ -13,7 +13,7 @@
13
13
  * drifted, which is the only version of this rule that survives contact.
14
14
  */
15
15
 
16
- const VERSION = '6c4facbe';
16
+ const VERSION = 'c6b9327c';
17
17
  const SHELL = `shell-${VERSION}`;
18
18
  const ASSETS = ['/assets/app.css', '/assets/tokens.css', '/assets/icon.svg'];
19
19